Skip to main content

Deployment Overview

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:

ServiceWhat it is
postgresPostgreSQL with the pgvector extension (required — it holds app data, cache, jobs, Action Cable, and vector embeddings)
webThe Rails app — Puma behind Thruster
workerBackground 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.

VariableRequiredPurpose
SECRET_KEY_BASEYesRails session/signing key
ACTIVE_RECORD_PRIMARY_KEYYesEncrypts OAuth tokens & AI keys at rest
ACTIVE_RECORD_DETERMINISTIC_KEYYesAs above
ACTIVE_RECORD_KEY_DERIVATION_SALTYesAs above
CAMPBOOKS_DATABASE_PASSWORDYesPassword for the bundled Postgres
APP_HOSTYesThe hostname you reach the app on (must match the Host header)
FORCE_SSLYestrue behind a TLS proxy, false for plain-HTTP local use
SELF_HOSTEDYes1 — 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

  1. Point a domain at the server and set APP_HOST, FORCE_SSL=true, and WEB_PORT in .env.
  2. Put a TLS-terminating reverse proxy in front (with Caddy it's a two-line config — automatic HTTPS).
  3. 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.