Single host (Docker Compose)
The Quick start gets you running on localhost.
This page turns that setup into a public, always-on instance on one server, the
right size for most communities.
The shape of a single-host deployment
Section titled “The shape of a single-host deployment” Internet (HTTPS) │ ┌───────▼────────┐ │ reverse proxy │ (Caddy / nginx / Cloudflare Tunnel) │ + TLS certs │ └───┬────────┬───┘ client.example.com backend.example.com │ │ ┌─────▼───┐ ┌────▼──────┐ ┌────────────┐ │ client │ │ backend │──▶│ PostgreSQL │ │ :8080 │ │ :8000 │ └────────────┘ └─────────┘ └───────────┘Two services you run (client and backend), one database, and a TLS-terminating reverse proxy in front. Optionally the proxy (on free edge hosting, not your server) and the extension (in visitors’ browsers).
Step 1: Pick your domains
Section titled “Step 1: Pick your domains”You need two hostnames on a domain you control, e.g.:
crimson.example.com→ the clientbackend.crimson.example.com→ the backend
Keeping them on the same registrable domain keeps cookies, CORS and CSP simple. See Domains, TLS & Cloudflare for DNS and TLS.
Step 2: Run the backend
Section titled “Step 2: Run the backend”cd crimson-backend# .env with at least: TMDB_API_KEY, DATABASE_URL (or POSTGRES_*),# PROXY_SECRET, SIGNUP_INVITE_CODE, ADMIN_EMAILS, ALLOWED_ORIGINSdocker compose up -dSet these production values in .env:
REQUIRE_LOGIN=trueALLOWED_ORIGINS=https://crimson.example.comPROXY_SECRET=<stable 32-byte hex, shared with the proxy if you run one>Step 3: Build and run the client
Section titled “Step 3: Build and run the client”cd ../crimson-clientgit submodule update --init --recursive # optional: without sources, the stub is usedVITE_API_BASE_URL=https://backend.crimson.example.com docker compose up --build -dStep 4: Put a reverse proxy in front
Section titled “Step 4: Put a reverse proxy in front”Any of these works; Caddy is the simplest (automatic HTTPS):
# Caddyfilecrimson.example.com { reverse_proxy localhost:8080}backend.crimson.example.com { reverse_proxy localhost:8000}caddy run --config ./CaddyfileCaddy fetches and renews Let’s Encrypt certificates for you. For nginx or a Cloudflare Tunnel, see Domains, TLS & Cloudflare.
Step 5: First admin and invites
Section titled “Step 5: First admin and invites”Follow First login & admin: set ADMIN_EMAILS,
register your admin account, then mint invites for your members.
Keeping it healthy
Section titled “Keeping it healthy”| Task | How |
|---|---|
| Updates | git pull each repo, then docker compose up -d --build. Check out a release tag instead if you want stability over latest. |
| Backups | Back up PostgreSQL (see The database). It is the one thing you can’t recreate. |
| Logs | docker compose logs -f. The backend’s /health endpoint reports database status. |
| Resources | A 1–2 GB RAM box handles a small community, because video bytes don’t flow through it. |
When one box isn’t enough, move to the Swarm deployment.
