commit 790a1908edddffb94148828f8a1e924353d3e762 equwal <truex@equwal.com> 2026-09-22 16:08:23 -0700 Docker: run the server behind Caddy with docker compose compose.yaml builds the image from this source and puts Caddy in front. Caddy gets the TLS certificate for SBM_DOMAIN by itself. sbm-sync uses the network of the caddy container. So Caddy connects on 127.0.0.1, and the sign-in limits see the address of each client. The image holds only the static binary, on distroless, as user nonroot. The data is in the volume sbm-data. The README tells how to run the server with and without Docker, and how to connect the devices to it. This computer has no Docker, so no image was built. Two checks passed: the build command works on the files that the Dockerfile copies, and compose.yaml passes the Compose schema.
.dockerignore | 6 ++++++ .env.example | 16 ++++++++++++++++ Dockerfile | 16 ++++++++++++++++ README.md | 34 +++++++++++++++++++++++++++++++--- compose.yaml | 36 ++++++++++++++++++++++++++++++++++++ contrib/Caddyfile | 8 ++++++++ 6 files changed, 113 insertions(+), 3 deletions(-)
diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..16710e3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +.git +data +demo +testdata +*.exe +.env diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..6ba5917 --- /dev/null +++ b/.env.example @@ -0,0 +1,16 @@ +# Settings of compose.yaml. Copy this file to .env and edit it. The README +# lists all settings. + +# Domain of the server. Its DNS must point to this machine, and ports 80 +# and 443 must be open, so that Caddy can get a certificate. +SBM_DOMAIN=sbm.example.org + +# Optional: email address on the privacy page. +#SBM_CONTACT=you@example.org + +# Optional: new accounts confirm their email address. Needs an SMTP server. +#SBM_SMTP_HOST=smtp.example.org +#SBM_SMTP_PORT=587 +#SBM_SMTP_USER=sbm@example.org +#SBM_SMTP_PASSWORD= +#SBM_MAIL_FROM=sbm Sync <sbm@example.org> diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5f4738b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +# Image of sbm-sync: the static binary on distroless, as user nonroot. +# compose.yaml builds it and puts Caddy in front for TLS. +FROM golang:1.26-alpine AS build +WORKDIR /src +COPY go.mod go.sum ./ +RUN go mod download +COPY *.go pages.html ./ +RUN CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o /sbm-sync . && mkdir /data + +FROM gcr.io/distroless/static-debian13:nonroot +COPY --from=build /sbm-sync /usr/local/bin/sbm-sync +# A new volume on /data gets the owner of this directory: nonroot. +COPY --from=build --chown=65532:65532 /data /data +ENV SBM_ADDR=:8750 SBM_DATA=/data +EXPOSE 8750 +ENTRYPOINT ["/usr/local/bin/sbm-sync"] diff --git a/README.md b/README.md index c608472..d9e4a53 100644 --- a/README.md +++ b/README.md @@ -57,15 +57,43 @@ larger than 4 MB), 429 (too many sign-in attempts). ## Run your own server +This repository has all the source code of the server, under the +AGPL-3.0. You need a machine with a domain name that points to it. + +### With Docker + +Ports 80 and 443 must be open. Caddy gets the TLS certificate by itself. + + git clone https://github.com/equwal/sbm-sync + cd sbm-sync + cp .env.example .env # then set SBM_DOMAIN in .env + docker compose up -d + +The data is in the Docker volume `sbm-data`. To back it up: + + docker compose cp sbm-sync:/data ./backup + +To update, run `git pull`, then `docker compose up -d --build`. + +### Without Docker + go build SBM_URL=https://sbm.example.org ./sbm-sync -Then put it behind a web server that does TLS. `contrib/` has a systemd unit -and an nginx site. With Go installed elsewhere: +Then put it behind a web server that does TLS. `contrib/` has a systemd unit, +an nginx site and a Caddyfile. With Go installed on another computer: GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -Settings, all through the environment: +### Connect the devices + +Sign in with the address of your server: `bm-sync login +https://sbm.example.org` on a computer. In the add-on and the app, type the +address in the field "Sync server". + +### Settings + +All settings come from the environment. With Docker, put them in `.env`. SBM_URL public address of the server (default http://localhost:8750) SBM_ADDR address to listen on (default 127.0.0.1:8750) diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..a8885c2 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,36 @@ +# sbm-sync behind Caddy. Caddy gets and renews the TLS certificate for +# SBM_DOMAIN by itself. Copy .env.example to .env, set SBM_DOMAIN in it, +# then run: docker compose up -d +services: + caddy: + image: caddy:2 + restart: unless-stopped + ports: + - "80:80" + - "443:443" + - "443:443/udp" + environment: + SBM_DOMAIN: ${SBM_DOMAIN:?set SBM_DOMAIN in .env} + volumes: + - ./contrib/Caddyfile:/etc/caddy/Caddyfile:ro + - caddy-data:/data + - caddy-config:/config + + sbm-sync: + build: . + restart: unless-stopped + # sbm-sync uses the network of caddy. Caddy connects to it on + # 127.0.0.1, and sbm-sync trusts X-Real-IP only from 127.0.0.1. So the + # sign-in limits count the address of each client, not of Caddy. + network_mode: service:caddy + env_file: .env + environment: + SBM_URL: https://${SBM_DOMAIN} + SBM_ADDR: 127.0.0.1:8750 + volumes: + - sbm-data:/data + +volumes: + caddy-data: + caddy-config: + sbm-data: diff --git a/contrib/Caddyfile b/contrib/Caddyfile new file mode 100644 index 0000000..b8cc47b --- /dev/null +++ b/contrib/Caddyfile @@ -0,0 +1,8 @@ +# Caddy site for sbm-sync. Caddy gets and renews the TLS certificate by +# itself. compose.yaml uses this file. Without Docker: +# SBM_DOMAIN=sbm.example.org caddy run --config contrib/Caddyfile +{$SBM_DOMAIN} { + reverse_proxy 127.0.0.1:8750 { + header_up X-Real-IP {remote_host} + } +}