Run Subby Sync on your own server.
The sync server is free to run, for as many phones as you like. If you have a home server or a small VPS, it takes a few commands and one Docker Compose file.
Licensed AGPL-3.0; the app itself is MIT. The code goes public on GitHub before launch, and these steps work from then on.
What you need
Any machine that runs Docker
Linux, macOS or Windows, with Docker Compose v2. A home server, a NAS or a small VPS is plenty, as long as it stays on.
A domain name
Pointed at that machine, with ports 80 and 443 open. The app only talks to HTTPS servers.
No certificate hassle
Caddy is included. It gets and renews the HTTPS certificate for you.
Set it up
-
Get the code
Clone the repository and copy the example settings.
git clone [repository link, public before launch] cd subby/apps/server cp docker.env.example .env -
Fill in .env
A long random database password and your domain.
HTTP_BINDkeeps plain HTTP off the network, so nothing gets around the certificate.TRUST_PROXYlets the request limits see each phone instead of Caddy.# openssl rand -hex 24 makes a good one POSTGRES_PASSWORD=[a long random string] DOMAIN=sync.example.com HTTP_BIND=127.0.0.1 TRUST_PROXY=uniquelocal -
Start it
This builds the server, starts Postgres and Caddy, and runs the database migrations.
docker compose --profile https up -d --build -
Point the app at it
On the first phone, before you add the others. Setting up sync uses Subby Sync unless you tap “Use your own server” under the Set up sync button. Recovering works the same way, under “Use a recovery key”.
SettingsSyncUse your own serverhttps://sync.example.com
Only on your home network or a VPN? docker compose up -d --build serves plain HTTP on port 8787. The store version of the app won’t connect to it, though, so HTTPS is the way to go for most people.
Three services, nothing hidden
Postgres keeps the locked boxes and the family lists. The server passes them between phones. Caddy handles HTTPS.
Photos go to a Docker volume on disk, or to any S3-compatible storage if you’d rather.
Shortened here: the real file also has settings for S3, push and request limits. Some names still say “kindred”, the project’s old name. They stay that way so existing installs keep working.
services:
db:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_USER: kindred
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: kindred
volumes:
- db:/var/lib/postgresql/data
server:
build:
context: ../..
dockerfile: apps/server/Dockerfile
restart: unless-stopped
environment:
DATABASE_URL: postgres://kindred:${POSTGRES_PASSWORD}@db:5432/kindred
MODE: ${MODE:-self} # no limits
BLOB_STORE: ${BLOB_STORE:-disk} # or s3
TRUST_PROXY: ${TRUST_PROXY:-}
volumes:
- blobs:/data # encrypted photos
ports:
- "${HTTP_BIND:-0.0.0.0}:${HTTP_PORT:-8787}:8787"
depends_on:
db:
condition: service_healthy
caddy:
image: caddy:2-alpine
profiles: ["https"]
restart: unless-stopped
command: caddy reverse-proxy --from ${DOMAIN:-} --to server:8787
ports:
- "80:80"
- "443:443"
volumes:
- caddy:/data
volumes:
db:
blobs:
caddy:
What’s different from ours
Same code, same encryption. A few things work differently when you run it yourself. And you’re never stuck: Sync › Move to another server takes your family to your server or back to ours, any time. The other phones follow by themselves, nobody pairs again, and the recovery words keep working.
| Your server | sync.subby.baby · opens at launch | |
|---|---|---|
| Cost | Free, no limits | 14-day free trial for the family, then €6.99 per phone, once (price not final) |
| Background sync | While the app is open, and in the background as often as the phone allows, roughly every 15 minutes | Same, plus a “sync now” push on Android. iOS push is still to come |
| Photos | As much as your disk holds | Up to 2 GB per family |
| Updates | You pull and rebuild | We handle them |
| Backups | You back up two volumes | We handle them |
Push only reaches app builds made with the same Firebase project as the server’s key. If you build the app yourself with your own Firebase project, you can turn push on for your server too.
Keeping it running
Check it
docker compose ps
curl https://sync.example.com/v1/info
docker compose logs -f server
Update it
git pull
docker compose --profile https up -d --build
Migrations run by themselves when the server starts.
Back it up
docker compose exec db pg_dump -U kindred kindred \
| gzip > subby-$(date +%F).sql.gz
Plus the blobs volume for photos. It’s all locked boxes, but keep backups private anyway.
The full guide is in the repository README, public before launch.