Self-hosting the Relay
The relay server is a single Go binary that handles HTTP push and WebSocket delivery, backed by Postgres for clip rows and a configurable media store (local disk or S3-compatible) for binary clips.
The Cinch-hosted relay is free while the project grows, but it is best-effort infrastructure for onboarding and demos. Self-host when you need your own uptime target, private network boundary, custom retention, or operational control.
What you need
Section titled “What you need”- A Postgres database (any 14+ release; managed services like Supabase, Neon, RDS work).
- A persistent directory or S3-compatible bucket for binary media.
- At least one OAuth provider (GitHub or Google) or the self-host username form fallback. Without OAuth credentials, sign-in still works via the username form on the browser page.
- A TLS terminator in front of the relay (Caddy, nginx, Cloudflare Tunnel), or a tailnet-only front door via Tailscale Serve. The relay itself speaks plain HTTP.
Docker Compose (recommended)
Section titled “Docker Compose (recommended)”services: db: image: postgres:16 environment: POSTGRES_USER: cinch POSTGRES_PASSWORD: secret POSTGRES_DB: cinch volumes: - cinch-db:/var/lib/postgresql/data restart: unless-stopped
relay: image: ghcr.io/cinchcli/relay:latest depends_on: [db] ports: - "8080:8080" volumes: - cinch-media:/var/lib/cinch/media environment: DATABASE_URL: postgres://cinch:secret@db:5432/cinch?sslmode=disable BASE_URL: https://relay.example.com MEDIA_LOCAL_DIR: /var/lib/cinch/media # Optional — enable OAuth sign-in: GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID} GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET} restart: unless-stopped
volumes: cinch-db: cinch-media:See Relay Configuration for the full list of environment variables.
Optional: Cloudflare Tunnel
Section titled “Optional: Cloudflare Tunnel”Cloudflare Tunnel is a good fit when the relay runs on a home server, lab box, or private VM without an inbound public port.
- Bind the relay to localhost:
ports: - "127.0.0.1:8080:8080"- Run
cloudflaredon the same machine and point a hostname at the relay:
cloudflared tunnel create cinch-relaycloudflared tunnel route dns cinch-relay relay.example.comcloudflared tunnel run cinch-relay --url http://127.0.0.1:8080- Set the relay
BASE_URLto the public hostname and log in against it:
cinch auth login --relay https://relay.example.comIf you enable OAuth, add the generated callback URLs for your hostname:
https://relay.example.com/auth/oauth/github/callbackhttps://relay.example.com/auth/oauth/google/callback
Optional: Fly.io
Section titled “Optional: Fly.io”Fly.io works well for a small public relay with managed Postgres.
fly launch --name cinch-relay --no-deployfly postgres create --name cinch-dbfly postgres attach --app cinch-relay cinch-dbfly secrets set BASE_URL=https://cinch-relay.fly.devfly deployFor binary media, use an S3-compatible backend instead of instance-local disk if you run more than one instance.
Move from hosted to self-hosted
Section titled “Move from hosted to self-hosted”- Deploy your relay and confirm
https://your-relay.example.com/healthreturns OK. - Sign in against the new relay:
cinch auth login --relay https://your-relay.example.com- Add your other machines again with
cinch fleet add user@hostorcinch auth login --relay .... - Keep the old hosted relay configured on one device until any clips you still need have been pulled locally.
Hosted relay retention remains 7 days by default, so treat migration as a re-pairing flow, not a durable hosted archive export.
Optional: Tailscale (tailnet-only)
Section titled “Optional: Tailscale (tailnet-only)”If you already use Tailscale, you can keep the relay off the public internet and still serve HTTPS by putting it behind tailscale serve on a node in your tailnet.
- Bind the relay to localhost so it is not publicly reachable. With Docker Compose, bind the port to
127.0.0.1:
ports: - "127.0.0.1:8080:8080"-
Configure Tailscale to terminate TLS and proxy to the relay at
http://127.0.0.1:8080. -
Set
BASE_URLto your MagicDNS hostname:
environment: BASE_URL: https://relay.<your-tailnet>.ts.net- Point clients at the same URL:
cinch auth login --relay https://relay.<your-tailnet>.ts.net
# For non-interactive usage:CINCH_RELAY_URL=https://relay.<your-tailnet>.ts.net cinch sendOAuth redirect URIs are derived from BASE_URL. If you enable OAuth, allow these callbacks:
https://relay.<your-tailnet>.ts.net/auth/oauth/github/callbackhttps://relay.<your-tailnet>.ts.net/auth/oauth/google/callback
Notes:
- The browser you use during sign-in must be connected to the same tailnet (otherwise it cannot reach the relay URL).
- Google OAuth commonly requires domain verification; if
.ts.netblocks you, use GitHub OAuth or the username fallback sign-in.
Bootstrapping the first admin
Section titled “Bootstrapping the first admin”A fresh relay has no users. To mint the first invite without an existing admin, set RELAY_BOOTSTRAP_INVITE_CODE on the relay container at first boot:
docker run -d ... \ -e RELAY_BOOTSTRAP_INVITE_CODE='one-shot-code' \ ghcr.io/cinchcli/relay:latestThe code is consumed once on startup and recorded as an invite. The first user to sign in with that invite becomes the admin. Remove the env var on the next deploy.
To gate sign-ups behind invites afterward, use the relay invite / relay user subcommands on the binary, or the cinch admin invite / cinch admin user CLI commands once you have an admin device.
S3-compatible media backend
Section titled “S3-compatible media backend”For multi-instance deployments, store media in S3-compatible object storage instead of a local volume:
environment: DATABASE_URL: postgres://... MEDIA_BACKEND: s3 MEDIA_ENDPOINT: fra1.digitaloceanspaces.com MEDIA_BUCKET: cinch-media MEDIA_REGION: fra1 MEDIA_ACCESS_KEY_ID: ${SPACES_KEY} MEDIA_SECRET_ACCESS_KEY: ${SPACES_SECRET}Works with AWS S3, DigitalOcean Spaces, Cloudflare R2, MinIO, etc. Set MEDIA_USE_SSL=false for plain-HTTP endpoints during local testing.
Build from source
Section titled “Build from source”git clone https://github.com/cinchcli/relay.gitcd relaymake buildDATABASE_URL=postgres://localhost/cinch ./dist/relayWas this page helpful?