Self-host · free, no limits

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

  1. 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
  2. Fill in .env

    A long random database password and your domain. HTTP_BIND keeps plain HTTP off the network, so nothing gets around the certificate. TRUST_PROXY lets 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
  3. Start it

    This builds the server, starts Postgres and Caddy, and runs the database migrations.

    docker compose --profile https up -d --build
  4. 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.

docker-compose.yml

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 serversync.subby.baby · opens at launch
CostFree, no limits14-day free trial for the family, then €6.99 per phone, once (price not final)
Background syncWhile the app is open, and in the background as often as the phone allows, roughly every 15 minutesSame, plus a “sync now” push on Android. iOS push is still to come
PhotosAs much as your disk holdsUp to 2 GB per family
UpdatesYou pull and rebuildWe handle them
BackupsYou back up two volumesWe 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.