Single host (Docker Compose)
The Quick start gets you running on localhost.
This page hardens that same setup into a real, 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 + backend), one database, and a TLS-terminating reverse proxy in front. Optionally the proxy (hosted on free edge, 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 + 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-minded values in .env:
REQUIRE_LOGIN=trueALLOWED_ORIGINS=https://crimson.example.comPROXY_SECRET=<stable 32-byte hex, shared with the proxy if you run one>FORWARDED_ALLOW_IPS=* # trust the reverse proxy's forwarded headersStep 3 — Build & run the client
Section titled “Step 3 — Build & run the client”cd ../crimson-clientgit submodule update --init --recursive # or your sources stubVITE_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 gentlest (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. Prefer nginx or a Cloudflare Tunnel? Both are covered in Domains, TLS & Cloudflare.
Step 5 — First admin + invites
Section titled “Step 5 — First admin + 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”- Updates:
git pulleach repo, then re-rundocker compose up -d --build. Pin to release tags if you want stability over latest. - Backups: back up PostgreSQL (see The database). This is the one thing you can’t recreate.
- Logs:
docker compose logs -f. The backend’s/healthendpoint reports DB status. - Resources: a 1–2 GB RAM box handles a small community comfortably, because video bytes don’t flow through it.
When one box isn’t enough, graduate to the Swarm deployment.