Self-hostable relay server for Cinch — Your clipboard. Across every machine.
The relay receives clipboard clips pushed by the CLI (cinch push) and delivers them in real time to connected devices via WebSocket. It is the only component you need to self-host; the CLI and desktop app work with any relay URL.
The relay requires a PostgreSQL database (set DATABASE_URL).
If you already have Postgres, you can run the relay directly:
docker run -p 8080:8080 \
-e DATABASE_URL='postgres://user:pass@host:5432/relay?sslmode=disable' \
ghcr.io/cinchcli/relay:latestThen point the CLI at your relay:
cinch auth login --relay http://your-server:8080This brings up Postgres + relay locally, with media stored on local disk:
services:
postgres:
image: postgres:16
environment:
POSTGRES_USER: relay
POSTGRES_PASSWORD: relay
POSTGRES_DB: relay
volumes:
- relay-pg:/var/lib/postgresql/data
relay:
image: ghcr.io/cinchcli/relay:latest
ports:
- "8080:8080"
environment:
PORT: 8080
DATABASE_URL: postgres://relay:relay@postgres:5432/relay?sslmode=disable
MEDIA_BACKEND: local
MEDIA_LOCAL_DIR: /data/media
BASE_URL: https://relay.example.com
volumes:
- relay-media:/data/media
depends_on:
- postgres
restart: unless-stopped
volumes:
relay-pg:
relay-media:Save as docker-compose.yml and run:
docker compose up -d| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
TCP port the server listens on |
DATABASE_URL |
(required) | PostgreSQL DSN (used with pgx), e.g. postgres://user:pass@host:5432/relay?sslmode=disable |
BASE_URL |
(unset) | Public HTTPS root of the relay, e.g. https://relay.example.com. Required for OAuth sign-in. |
RELAY_REGION |
(unset) | Optional region label returned in health responses |
CORS_ORIGINS |
(unset) | Comma-separated extra allowed CORS origins |
MEDIA_BACKEND |
local |
Media storage backend: local or s3 |
MEDIA_LOCAL_DIR |
media |
Local directory for media objects when MEDIA_BACKEND=local |
MEDIA_ENDPOINT |
(unset) | S3 endpoint host when MEDIA_BACKEND=s3 (e.g. s3.amazonaws.com or MinIO endpoint) |
MEDIA_BUCKET |
(unset) | S3 bucket name when MEDIA_BACKEND=s3 |
MEDIA_REGION |
(unset) | S3 region when MEDIA_BACKEND=s3 |
MEDIA_ACCESS_KEY_ID |
(unset) | S3 access key when MEDIA_BACKEND=s3 (omit when using IAM roles) |
MEDIA_SECRET_ACCESS_KEY |
(unset) | S3 secret key when MEDIA_BACKEND=s3 (omit when using IAM roles) |
MEDIA_USE_SSL |
true |
Set to false to use plain HTTP for S3-compatible endpoints |
GITHUB_CLIENT_ID |
(unset) | GitHub OAuth App client ID (enables GitHub sign-in) |
GITHUB_CLIENT_SECRET |
(unset) | GitHub OAuth App client secret |
GOOGLE_CLIENT_ID |
(unset) | Google OAuth client ID (enables Google sign-in) |
GOOGLE_CLIENT_SECRET |
(unset) | Google OAuth client secret |
LOG_LEVEL |
info |
Log level: debug, info, warn, error |
LOG_FORMAT |
text |
Log format: text (human-readable) or json (structured) |
By default the relay uses a simple device-name form for authentication. To enable Sign in with GitHub / Google:
-
Register a GitHub OAuth App
- Homepage URL:
https://your-relay.example.com - Callback URL:
https://your-relay.example.com/auth/oauth/github/callback
- Homepage URL:
-
Register a Google OAuth Client (optional)
- Redirect URI:
https://your-relay.example.com/auth/oauth/google/callback
- Redirect URI:
-
Set env vars and restart:
BASE_URL=https://your-relay.example.com
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...If neither GITHUB_CLIENT_ID nor GOOGLE_CLIENT_ID is set, the relay falls back to the username form — self-hosters who skip OAuth are unaffected.
See cinchcli.com/docs for production deployment guidance.
| Method | Path | Description |
|---|---|---|
GET |
/health |
Health check — returns {"status":"ok"} |
GET |
/auth/browser |
Device sign-in page (OAuth or username form) |
GET |
/auth/oauth/github/start |
Redirect to GitHub OAuth |
GET |
/auth/oauth/github/callback |
GitHub OAuth callback |
GET |
/auth/oauth/google/start |
Redirect to Google OAuth |
GET |
/auth/oauth/google/callback |
Google OAuth callback |
POST |
/auth/login |
Create/resume account (device-code flow) |
POST |
/auth/pair |
Exchange pair token for device token |
POST |
/v1/clips |
Push a clipboard clip |
GET |
/v1/clips |
Fetch latest clip |
GET |
/v1/stream |
WebSocket real-time clip stream |
Full Connect-RPC service definitions live in proto/cinch/v1/.
The .proto files at proto/cinch/v1/ are vendored from the cinch monorepo. The canonical source of truth lives at crates/client-core/proto/cinch/v1/ in that repo. Changes to the wire schema flow into this repo via an auto-PR from the cinch monorepo's proto-sync-relay.yml workflow.
To regenerate Go bindings after a sync:
make generateTo verify your local proto matches upstream:
make verify-proto # uses ../../cinch/main as upstream
UPSTREAM=/path/to/cinch make verify-proto # custom pathThe generated Go code lives at internal/cinchv1/ (imported as cinchv1 "github.com/cinchcli/relay/internal/cinchv1"). Connect-RPC service stubs are at internal/cinchv1/cinchv1connect/.
git clone https://github.com/cinchcli/relay.git
cd relay
go build -o dist/relay ./cmd/relay
./dist/relay --port 8080Requires Go 1.24+. No CGO needed (CGO_ENABLED=0).
Full docs at cinchcli.com/docs.
Operator runbooks:
- Hosted relay capability management — setting per-user device, retention, storage, clip-size caps, grace periods, and the self-host carve-out.
- cinchcli/cinch — CLI client (
cinch push/pull/auth) - cinchcli/desktop — Tauri v2 desktop app (macOS)
The wire-format DTOs (Clip, Device, push/pull/auth requests, etc.) are
defined in the cinch monorepo at crates/client-core/proto/cinch/v1/*.proto
and vendored into this repo under proto/cinch/v1/. The Rust CLI and
desktop generate their types from the same .proto source via
client-core in cinchcli/cinch.
See Wire Schema above for the sync workflow.
Cinch is dual-licensed:
- AGPL-3.0 — free for personal use, open-source projects, and self-hosted deployments that comply with AGPL terms. See LICENSE.
- Commercial License — for closed-source products, SaaS deployments, or organizations that need a commercial support agreement. See LICENSE-COMMERCIAL or contact jingmuio@gmail.com.