Deployment Overview
:::warning Legacy Rails version This page documents the older Rails version of Campbooks. It is unstable and unmaintained, and it no longer gets fixes. Campbooks is being rebuilt from scratch in Rust: for new installs, see Self-hosting. :::
Campbooks deploys as a self-contained Docker Compose stack. docker compose up runs the whole app on a single server — there's no Node build, no Redis, and no external services to wire up beyond a TLS-terminating reverse proxy.
Want the step-by-step? This page is the lay of the land. The Self-Hosting guide walks through a real production server end to end.
The stack
docker compose up starts three containers:
| Service | What it is |
|---|---|
postgres | PostgreSQL with the pgvector extension (required — it holds app data, cache, jobs, Action Cable, and vector embeddings) |
web | The Rails app — Puma behind Thruster |
worker | Background jobs — email scanning, AI, indexing, calendar sync (Solid Queue) |
A fourth service, opensearch, is optional (enabled with the search profile) and only powers contact full-text autocomplete. Everything else — email search, document search, the Cmd+K palette — uses Postgres + pgvector.
Uploaded files (email attachments saved as Documents) live on a local Docker volume by default, or in S3-compatible object storage if you configure it.
What you need
- A server with Docker and the Docker Compose plugin (Docker Engine ≥ 24)
- About 2 GB RAM for the default stack (add ~1 GB if you enable OpenSearch)
- A domain name and a reverse proxy that terminates TLS (Caddy, Traefik, or nginx)
Configuration
Everything is configured through environment variables in .env. bin/generate-secrets fills the required secrets; the rest are optional and each unlocks one integration. The annotated list lives in .env.example.
| Variable | Required | Purpose |
|---|---|---|
SECRET_KEY_BASE | Yes | Rails session/signing key |
ACTIVE_RECORD_PRIMARY_KEY | Yes | Encrypts OAuth tokens & AI keys at rest |
ACTIVE_RECORD_DETERMINISTIC_KEY | Yes | As above |
ACTIVE_RECORD_KEY_DERIVATION_SALT | Yes | As above |
CAMPBOOKS_DATABASE_PASSWORD | Yes | Password for the bundled Postgres |
APP_HOST | Yes | The hostname you reach the app on (must match the Host header) |
FORCE_SSL | Yes | true behind a TLS proxy, false for plain-HTTP local use |
SELF_HOSTED | Yes | 1 — open registration + reads AI keys from env |
You don't need config/master.key. Self-hosting reads SECRET_KEY_BASE from the environment. Generate the required secrets with bin/generate-secrets.
Going to production
- Point a domain at the server and set
APP_HOST,FORCE_SSL=true, andWEB_PORTin.env. - Put a TLS-terminating reverse proxy in front (with Caddy it's a two-line config — automatic HTTPS).
docker compose up -d --build. The entrypoint runs database migrations on boot.
Never expose the app over plain HTTP on the internet. With FORCE_SSL=false sessions and cookies travel unencrypted. Always sit behind a TLS proxy in production.
Updates
git pull
docker compose up -d --build # the entrypoint runs migrations on boot
Back up the database first.
Health check
Campbooks exposes a health endpoint at /up (returns 200 when healthy). Use it for load-balancer probes and monitoring — it stays reachable over plain HTTP even with FORCE_SSL=true.
See the Self-Hosting guide for the full walkthrough, including backups and every integration.