Implement changes

This commit is contained in:
Peter Zandbergen 2026-06-18 08:25:53 +02:00
parent 1cc4bb9873
commit 8c7e7cd615
7 changed files with 111 additions and 36 deletions

View File

@ -80,7 +80,10 @@ jobs:
df -h
echo "Start CI build"
docker run --privileged --rm tonistiigi/binfmt --install all
podman manifest create build
podman build --format docker --platform linux/amd64,linux/arm64,linux/arm/v7 --manifest localhost/build .
podman manifest push localhost/build docker://docker.io/bbernhard/signal-cli-rest-api:${EPOCHSECONDS}-ci
podman manifest create build-jre
podman build --format docker --target jre --platform linux/amd64,linux/arm64,linux/arm/v7 --manifest localhost/build-jre .
podman manifest push localhost/build-jre docker://docker.io/bbernhard/signal-cli-rest-api:${EPOCHSECONDS}-ci
podman manifest create build-native
podman build --format docker --target native --platform linux/amd64,linux/arm64 --manifest localhost/build-native .
podman manifest push localhost/build-native docker://docker.io/bbernhard/signal-cli-rest-api:${EPOCHSECONDS}-ci-native

View File

@ -83,7 +83,11 @@ jobs:
run: |
echo "Start dev build"
docker run --privileged --rm tonistiigi/binfmt --install all
podman manifest create build
podman build --format docker --build-arg BUILD_VERSION_ARG=${VERSION} --manifest localhost/build --platform linux/amd64,linux/arm64,linux/arm/v7 .
podman manifest push localhost/build docker://docker.io/bbernhard/signal-cli-rest-api:${VERSION}-dev
podman manifest push localhost/build docker://docker.io/bbernhard/signal-cli-rest-api:latest-dev
podman manifest create build-jre
podman build --format docker --target jre --build-arg BUILD_VERSION_ARG=${VERSION} --platform linux/amd64,linux/arm64,linux/arm/v7 --manifest localhost/build-jre .
podman manifest push localhost/build-jre docker://docker.io/bbernhard/signal-cli-rest-api:${VERSION}-dev
podman manifest push localhost/build-jre docker://docker.io/bbernhard/signal-cli-rest-api:latest-dev
podman manifest create build-native
podman build --format docker --target native --build-arg BUILD_VERSION_ARG=${VERSION} --platform linux/amd64,linux/arm64 --manifest localhost/build-native .
podman manifest push localhost/build-native docker://docker.io/bbernhard/signal-cli-rest-api:${VERSION}-dev-native
podman manifest push localhost/build-native docker://docker.io/bbernhard/signal-cli-rest-api:latest-dev-native

View File

@ -83,7 +83,11 @@ jobs:
run: |
echo "Start productive build"
docker run --privileged --rm tonistiigi/binfmt --install all
podman manifest create build
podman build --format docker --build-arg BUILD_VERSION_ARG=${VERSION} --manifest localhost/build --platform linux/amd64,linux/arm64,linux/arm/v7 .
podman manifest push localhost/build docker://docker.io/bbernhard/signal-cli-rest-api:${VERSION}
podman manifest push localhost/build docker://docker.io/bbernhard/signal-cli-rest-api:latest
podman manifest create build-jre
podman build --format docker --target jre --build-arg BUILD_VERSION_ARG=${VERSION} --platform linux/amd64,linux/arm64,linux/arm/v7 --manifest localhost/build-jre .
podman manifest push localhost/build-jre docker://docker.io/bbernhard/signal-cli-rest-api:${VERSION}
podman manifest push localhost/build-jre docker://docker.io/bbernhard/signal-cli-rest-api:latest
podman manifest create build-native
podman build --format docker --target native --build-arg BUILD_VERSION_ARG=${VERSION} --platform linux/amd64,linux/arm64 --manifest localhost/build-native .
podman manifest push localhost/build-native docker://docker.io/bbernhard/signal-cli-rest-api:${VERSION}-native
podman manifest push localhost/build-native docker://docker.io/bbernhard/signal-cli-rest-api:latest-native

View File

@ -16,8 +16,8 @@ Go-based REST API wrapping [signal-cli](https://github.com/AsamK/signal-cli) for
- `scripts/jsonrpc2-helper.go` — daemon manager for json-rpc mode
- `plugin_loader.go` — Go plugin system using Lua scripts (v1/v2 plugin API)
- `plugins/` — example Lua plugins and persistence plugin
- `Dockerfile` — multi-stage build: Go compile → release image with signal-cli + Java runtime
- `entrypoint.sh` — container entrypoint; handles UID/GID, chown, supervisor for json-rpc mode
- `Dockerfile` — multi-stage build with two release targets: `jre` and `native`
- `entrypoint.sh` — container entrypoint; validates MODE against available binaries, handles UID/GID, chown, supervisor for json-rpc mode
## Build & Run
@ -34,6 +34,11 @@ Go-based REST API wrapping [signal-cli](https://github.com/AsamK/signal-cli) for
docker compose build
docker compose up
```
- **Build specific variant (Docker):**
```bash
docker build --target jre . # JRE variant (normal + json-rpc)
docker build --target native . # native variant (native + json-rpc-native)
```
- **No linter or typecheck config exists** — standard Go tooling only (e.g., `go vet`).
## Swagger / API Docs
@ -47,6 +52,19 @@ go run github.com/swaggo/swag/cmd/swag@v1.16.6 init --requiredByDefault --output
The receive V1 schemas require an extra step (`add_v1_receive_schemas.go`); see `src/docs/README.md`. CI checks that generated docs are up-to-date (workflow: `check-docs.yml`).
## Image Variants
The Dockerfile produces two release targets from a shared `base` stage:
| Target | Tag suffix | Contains | Modes | Platforms |
|---|---|---|---|---|
| `jre` | `latest`, `X.Y.Z` | headless JRE + signal-cli Java dist | `normal`, `json-rpc` | amd64, arm64, arm/v7 |
| `native` | `latest-native`, `X.Y.Z-native` | signal-cli-native only (no JRE) | `native`, `json-rpc-native` | amd64, arm64 |
The `entrypoint.sh` validates that the requested `MODE` matches binaries available in the running image variant and exits with a clear error if mismatched.
The JRE variant uses `openjdk-25-jre-headless` (not the full `openjdk-25-jre`) to avoid ~280 MB of GUI libraries that a CLI tool never uses.
## Key Environment Variables
| Variable | Default | Purpose |
@ -63,8 +81,8 @@ The receive V1 schemas require an extra step (`add_v1_receive_schemas.go`); see
## Gotchas
- The Dockerfile pins `SIGNAL_CLI_VERSION` and `LIBSIGNAL_CLIENT_VERSION` as build args. After bumping these, verify the `libsignal-client-*.jar` filename still matches.
- Multi-arch build targets: `linux/amd64`, `linux/arm64`, `linux/arm/v7`. The `native` (GraalVM) binary is unavailable on armv7 — code falls back to `normal` mode.
- Multi-arch builds: the `jre` target covers `linux/amd64`, `linux/arm64`, `linux/arm/v7`; the `native` target covers `linux/amd64`, `linux/arm64` only (no armv7 native binary).
- `AUTO_RECEIVE_SCHEDULE` and `SIGNAL_CLI_CMD_TIMEOUT` cause a fatal error in json-rpc mode.
- `RECEIVE_WEBHOOK_URL` is only valid in json-rpc mode; fatal in other modes.
- CI uses Podman for multi-arch builds, not Docker Buildx.
- Release versions are published via `publish.sh` triggering GitHub Actions (dev vs stable tags).
- CI uses Podman for multi-arch builds, not Docker Buildx. Each CI/release workflow builds both `jre` and `native` targets.
- Release versions are published via `publish.sh` triggering GitHub Actions (dev vs stable tags, with `-native` suffix for the native variant).

View File

@ -130,13 +130,9 @@ RUN cd /tmp/signal-cli-rest-api-src/scripts && go build -o jsonrpc2-helper
# build plugin_loader
RUN cd /tmp/signal-cli-rest-api-src && go build -buildmode=plugin -o signal-cli-rest-api_plugin_loader.so plugin_loader.go
# Start a fresh container for release container
# ---- Shared base for both image variants ----
# eclipse-temurin doesn't provide a OpenJDK 21 image for armv7 (see https://github.com/adoptium/containers/issues/502). Until this
# is fixed we use the standard ubuntu image
#FROM eclipse-temurin:21-jre-jammy
FROM ubuntu:noble
FROM ubuntu:noble AS base
ENV GIN_MODE=release
@ -150,31 +146,20 @@ ENV SIGNAL_CLI_REST_API_PLUGIN_SHARED_OBJ_DIR=/usr/bin/
RUN dpkg-reconfigure debconf --frontend=noninteractive \
&& apt-get update \
&& apt-get install -y --no-install-recommends util-linux supervisor openjdk-25-jre curl locales \
&& rm -rf /var/lib/apt/lists/*
&& apt-get install -y --no-install-recommends util-linux curl locales \
&& rm -rf /var/lib/apt/lists/*
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/signal-cli-rest-api /usr/bin/signal-cli-rest-api
COPY --from=buildcontainer /opt/signal-cli-${SIGNAL_CLI_VERSION} /opt/signal-cli-${SIGNAL_CLI_VERSION}
COPY --from=buildcontainer /tmp/signal-cli-native /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli-native
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/scripts/jsonrpc2-helper /usr/bin/jsonrpc2-helper
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/signal-cli-rest-api_plugin_loader.so /usr/bin/signal-cli-rest-api_plugin_loader.so
COPY entrypoint.sh /entrypoint.sh
RUN userdel ubuntu -r \
&& groupadd -g 1000 signal-api \
&& useradd --no-log-init -M -d /home -s /bin/bash -u 1000 -g 1000 signal-api \
&& ln -s /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli /usr/bin/signal-cli \
&& ln -s /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli-native /usr/bin/signal-cli-native \
&& mkdir -p /signal-cli-config/ \
&& mkdir -p /home/.local/share/signal-cli
# remove the temporary created signal-cli-native on armv7, as GRAALVM doesn't support 32bit
RUN arch="$(uname -m)"; \
case "$arch" in \
armv7l) echo "GRAALVM doesn't support 32bit" && rm /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli-native /usr/bin/signal-cli-native ;; \
esac;
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
dpkg-reconfigure --frontend=noninteractive locales && \
update-locale LANG=en_US.UTF-8
@ -192,3 +177,36 @@ ENTRYPOINT ["/entrypoint.sh"]
HEALTHCHECK --interval=20s --timeout=10s --retries=3 \
CMD curl -f http://localhost:${PORT}/v1/health || exit 1
# ---- JRE variant: MODE=normal, json-rpc ----
# Includes headless JRE + signal-cli Java dist. No native binary.
# Supports: linux/amd64, linux/arm64, linux/arm/v7
FROM base AS jre
RUN dpkg-reconfigure debconf --frontend=noninteractive \
&& apt-get update \
&& apt-get install -y --no-install-recommends openjdk-25-jre-headless supervisor \
&& rm -rf /var/lib/apt/lists/*
COPY --from=buildcontainer /opt/signal-cli-${SIGNAL_CLI_VERSION} /opt/signal-cli-${SIGNAL_CLI_VERSION}
RUN ln -s /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli /usr/bin/signal-cli \
&& mkdir -p /home/.local/share/signal-cli
# ---- Native variant: MODE=native, json-rpc-native ----
# Includes signal-cli-native only. No JRE, no Java dist.
# Supports: linux/amd64, linux/arm64 (no arm/v7 — GraalVM doesn't produce 32-bit binaries)
FROM base AS native
RUN dpkg-reconfigure debconf --frontend=noninteractive \
&& apt-get update \
&& apt-get install -y --no-install-recommends supervisor \
&& rm -rf /var/lib/apt/lists/*
COPY --from=buildcontainer /tmp/signal-cli-native /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli-native
RUN mkdir -p /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin \
&& ln -s /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli-native /usr/bin/signal-cli-native \
&& mkdir -p /home/.local/share/signal-cli

View File

@ -1,11 +1,22 @@
services:
# JRE variant (default) -- use with MODE=normal or MODE=json-rpc
signal-cli-rest-api:
image: bbernhard/signal-cli-rest-api:latest
environment:
- MODE=normal #supported modes: json-rpc, native, normal
- MODE=normal #supported modes: normal, json-rpc
#- AUTO_RECEIVE_SCHEDULE=0 22 * * * #enable this parameter on demand (see description below)
ports:
- "8080:8080" #map docker port 8080 to host port 8080.
volumes:
- "./signal-cli-config:/home/.local/share/signal-cli" #map "signal-cli-config" folder on host system into docker container. the folder contains the password and cryptographic keys when a new number is registered
# Native variant -- use with MODE=native or MODE=json-rpc-native
# Uncomment to use the native variant (smaller image, no Java runtime)
# signal-cli-rest-api-native:
# image: bbernhard/signal-cli-rest-api:latest-native
# environment:
# - MODE=native #supported modes: native, json-rpc-native
# ports:
# - "8080:8080"
# volumes:
# - "./signal-cli-config:/home/.local/share/signal-cli"

View File

@ -5,6 +5,23 @@ set -e
[ -z "${SIGNAL_CLI_CONFIG_DIR}" ] && echo "SIGNAL_CLI_CONFIG_DIR environmental variable needs to be set! Aborting!" && exit 1;
# Validate MODE against the binaries available in this image variant
MODE=${MODE:-normal}
if [ "$MODE" = "native" ] || [ "$MODE" = "json-rpc-native" ]; then
if [ ! -x /usr/bin/signal-cli-native ]; then
echo "ERROR: MODE=$MODE requires signal-cli-native, but this image doesn't include it."
echo "Use the -native image tag (e.g., bbernhard/signal-cli-rest-api:latest-native)"
exit 1
fi
fi
if [ "$MODE" = "normal" ] || [ "$MODE" = "json-rpc" ]; then
if ! command -v java >/dev/null 2>&1; then
echo "ERROR: MODE=$MODE requires Java (signal-cli), but this image doesn't include it."
echo "Use the standard image tag (e.g., bbernhard/signal-cli-rest-api:latest)"
exit 1
fi
fi
usermod -u ${SIGNAL_CLI_UID} signal-api
groupmod -o -g ${SIGNAL_CLI_GID} signal-api