P
Persist

Self-Hosting the Sync Server

Deploy a Persist sync server with Docker, configure TLS, and connect devices.

Overview

The Persist sync server is an optional component that acts as a relay for device-to-device replication. Devices push and pull changes through the server instead of connecting directly. Self-hosting gives you full control over where sync data is stored.

Docker deployment

The sync server is distributed as a Docker image:

docker run -d \
  --name persist-sync \
  -p 8787:8787 \
  -v persist-data:/data \
  -e PERSIST_ADAPTER=sqlite \
  -e PERSIST_PATH=/data/sync.db \
  -e PERSIST_AUTH_SECRET=your-secret-here \
  ghcr.io/cuitty/persist-sync:latest

For production deployments, use Docker Compose:

# docker-compose.yml
services:
  persist-sync:
    image: ghcr.io/cuitty/persist-sync:latest
    ports:
      - "8787:8787"
    volumes:
      - persist-data:/data
    environment:
      PERSIST_ADAPTER: postgres
      DATABASE_URL: postgresql://persist:pass@db:5432/persist
      PERSIST_AUTH_SECRET: ${PERSIST_AUTH_SECRET}
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    volumes:
      - pg-data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: persist
      POSTGRES_USER: persist
      POSTGRES_PASSWORD: ${DB_PASSWORD}

volumes:
  persist-data:
  pg-data:

TLS configuration

In production, always terminate TLS. The sync server does not handle TLS directly. Place it behind a reverse proxy like Caddy, nginx, or Cloudflare Tunnel.

# Caddyfile
sync.example.com {
    reverse_proxy persist-sync:8787
}

Clients connect using the HTTPS URL:

await enableSync(store, {
  remote: "https://sync.example.com",
  authToken: "your-device-token",
});

Authentication

The sync server validates device tokens on every request. Generate tokens using the CLI:

persist server token create --device "alice-laptop"
persist server token create --device "alice-phone"
persist server token list
persist server token revoke <token-id>

Resource requirements

  • CPU: 1 vCPU handles approximately 1,000 sync operations per second.
  • Memory: 256 MB minimum, 512 MB recommended.
  • Disk: depends on data volume. The SQLite backend works well for small deployments (under 10 GB). For larger volumes, use the Postgres backend.

Health check

The server exposes a health endpoint at /health:

curl https://sync.example.com/health
# {"status":"ok","version":"0.1.0","uptime":86400}