Aller au contenu

Run the sync server

Ce contenu n’est pas encore disponible dans votre langue.

Run your own sync server with Docker starts the server on one computer with the release’s docker-compose.yml and a .env file. This page covers what it needs before other people and devices use it. Run the docker compose commands below in the folder that holds those two files. Every setting is listed in Environment variables.

The server reads its settings from environment variables, which the docker-compose.yml of each release takes from the .env file next to it. STERNWAY_VERSION picks the image, ghcr.io/kuscko/sternway-server:<version>. One line per variable:

Terminal window
STERNWAY_VERSION=0.1.0-alpha.56
STERNWAY_SERVER_SECRET=<the secret you keep>
STERNWAY_PUBLIC_URL=https://sternway.example.com
STERNWAY_TRUST_PROXY=172.18.0.1
STERNWAY_SMTP_URL=smtp://user:password@mail.example.com:587

After changing .env, run docker compose up -d again; Compose recreates the server’s container with the new values.

  • STERNWAY_SERVER_SECRET must stay the same. Changing it makes stored two-factor secrets unreadable: those users set up two-factor again.
  • Keep .env readable only by you (chmod 600 .env): it holds the secret and any passwords you put there.
  • The database lives in a Docker volume. docker compose down and a later up -d keep it; docker compose down -v deletes it.
  • For anything the Compose file does not have, such as mounting the licence file, put a docker-compose.override.yml next to it. Docker Compose reads it automatically together with docker-compose.yml, and you keep it when you replace the Compose file of a newer release.

The server speaks plain HTTP on 127.0.0.1:8080, and the apps refuse plain http:// for anything but a server on the same computer (the phone always). Put a TLS reverse proxy in front of it (Caddy, nginx, Traefik and the like) that:

  • passes every request, the WebSocket upgrades on /api/v1/ws and /api/v1/relay/ included, to 127.0.0.1:8080;
  • passes /api/v1/auth/saml/… too, if teams use SAML: identity providers post sign-ins there;
  • sets X-Forwarded-For.

With Caddy on the same machine, for example, this is the whole site block (Caddy gets a certificate and passes WebSockets by itself):

sternway.example.com {
reverse_proxy 127.0.0.1:8080
}

Then set on the server:

  • STERNWAY_PUBLIC_URL to the https:// address people use. Invite links, passkeys, SAML and the licence are built from it; changing it later breaks every team’s SAML set-up and every passkey outside the new domain.
  • STERNWAY_TRUST_PROXY to the address the server sees your proxy’s requests come from, and nothing else. With the proxy on the host and the server in Docker, that is the gateway of the Compose project’s network, not 127.0.0.1 (docker network inspect on the server’s network shows it). With a CDN in front of the proxy, list both. Without it, every user shares the proxy’s address and its request limits, and the server logs a warning the first time a request comes through a proxy.

curl -sf https://sternway.example.com/healthz from another machine should answer {"ok":true,…}.

The server allows 300 requests a minute per signed-in account, from any address, and the same per client address for everything else (signing up, signing in); one address also has a ceiling of 3,000 a minute over all its requests. That is why STERNWAY_TRUST_PROXY matters: the limits count real client addresses only when the server can see them.

Run one server process per database. Short-lived state (single-use WebSocket tickets, pending single sign-on and passkey sign-ins, failed sign-in counts) lives in that process’s memory, so a second instance would not know tickets the first one issued. A restart only loses that state; the apps ask again.

The database holds every account’s encrypted vault data, wrapped keys and metadata. Back it up like any production database. In the folder with docker-compose.yml:

Terminal window
docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > sternway-$(date +%F).sql

To restore into an empty database:

Terminal window
docker compose exec -T postgres sh -c 'psql -U "$POSTGRES_USER" "$POSTGRES_DB"' < sternway-2026-10-23.sql

A restore brings every account back as it was at the dump. Keep .env (with STERNWAY_SERVER_SECRET) with the backups: without the secret, two-factor secrets in the dump cannot be read.

  1. Back up the database (above).

  2. In .env, set STERNWAY_VERSION to the new version.

  3. Run:

    Terminal window
    docker compose pull
    docker compose up -d

The server applies its database migrations itself when it starts. If a release’s notes say its docker-compose.yml changed, download that one too (https://downloads.sternway.dev/<version>/docker-compose.yml) and check it against that version’s SHA256SUMS; .env and docker-compose.override.yml stay as they are.

Set STERNWAY_SMTP_URL (smtp://user:password@mail.example.com:587) to send invite emails and passkey notices and to let people verify their email address with a mailed code. Without it everything else works; invites go by link.

Passkeys are bound to a domain: by default the host of STERNWAY_PUBLIC_URL, with that URL’s origin as the only accepted origin.

  • STERNWAY_WEBAUTHN_RP_ID names a parent domain instead (example.com for https://sync.example.com), so passkeys keep working if the server moves to another subdomain.
  • STERNWAY_WEBAUTHN_ORIGINS adds origins when the server is reached under more than one address.

Passkeys need HTTPS. Moving the server outside the domain makes every passkey stop working; people then sign in with their password and add their passkeys again. See Sign in with a passkey.

Teams set up SAML themselves in the desktop app; the server needs nothing but a correct STERNWAY_PUBLIC_URL and a proxy that passes /api/v1/auth/saml/…. Server-wide OpenID Connect is STERNWAY_OIDC. See Set up single sign-on.

Business and Enterprise features of teams on a self-hosted server need a licence file. Put it next to the Compose file, mount it into the server’s container with a docker-compose.override.yml, and point STERNWAY_LICENCE at it:

services:
server:
environment:
STERNWAY_LICENCE: /licence/sternway.licence
volumes:
- ./sternway.licence:/licence/sternway.licence:ro

Then docker compose up -d. The server reads the file at start and every hour, so a newer file takes effect within the hour. The licence is bound to the server’s address: STERNWAY_PUBLIC_URL must be one of the addresses it names, or it counts as expired. Teams › Licence in the app shows its state. What a licence covers and what happens when it runs out: Licensing of self-hosted servers.

If the server’s clock was wrong and you fixed it, the licence’s own record of the time may keep it from counting the corrected time. Reset that record with the server’s licence reset-clock command, run in its container:

Terminal window
docker compose exec server node_modules/.bin/tsx apps/server/src/index.ts licence reset-clock

The reset is recorded in the audit log.

STERNWAY_AUDIT_PUSH_URL (and STERNWAY_AUDIT_PUSH_TOKEN) sends every audit event to an HTTPS endpoint, with a licence that includes it. See Export the audit log.

STERNWAY_DELEGATED_SIGNING=off makes the server refuse every team change an admin signs, at once, while the owners’ changes still go through. It undoes nothing already kept. Use it if you suspect an admin’s account is compromised.

  • Revoking a device (Settings › Account & Sync › Devices › Revoke) signs it out. Its own hosts and keys stay on it; its copies of team vaults are removed the next time it reaches the server.
  • Removing a team member rotates the key of each vault they could open, so they receive nothing new. It cannot take back what they already had on their devices. If they may have seen credentials that matter, change those credentials (new keys, new passwords).

Item contents, session logs, vault names and wrapped keys are encrypted; the server cannot read them. It does see and keep: accounts’ email, name and handle, device names and platforms, team names and members, the signed member lists (with a team’s policy values and reasons), item ids, types, sizes, revision numbers and times, and client IP addresses. See What leaves your device and Threat model.

© 2026 IRONPINE LABS LLC
ALL RIGHTS RESERVED.