Production Deployment (the deploy/ contract)

The commands in Getting Started launch the development stack (source build, Vite, MailHog, phpMyAdmin). For a production install on a Linux server, Synaplan ships a portable, single-node production contract in the deploy/ directory of the main repository. It uses published images only — no dev services, no source bind mounts.

Authoritative reference: deploy/README.md and docs/INSTALLATION.md in the main repository. This page is the map, those files are the terrain.


Requirements

  • Docker Engine with Docker Compose v2
  • Cloud-AI profile: at least 4 vCPU, 8 GB RAM, and 30 GB free disk
  • Optional local-ai profile: at least 16 GB RAM and substantially more disk
  • A reverse proxy terminating HTTPS in front of 127.0.0.1:8000

First installation

cp deploy/selfhost.env.example deploy/.env
# Set SYNAPLAN_VERSION, the public URL, and BOOTSTRAP_ADMIN_*
# (or leave both admin vars empty and sign up later)
deploy/scripts/prepare.sh
docker compose --env-file deploy/.env -f deploy/compose.yaml pull
deploy/scripts/validate-release.sh
docker compose --env-file deploy/.env -f deploy/compose.yaml up -d
deploy/scripts/smoke-test.sh

After login, the same first-run AI-provider screen applies as in the local install.

Key properties of the contract:

  • Generated secrets. Eight secrets (application secret, database passwords, realtime secrets, …) are generated automatically on first start and written to deploy/data/secrets.env (mode 0600). That file is authoritative from then on and must be part of every backup — a database restored without it cannot be opened again.
  • Bootstrap administrator. BOOTSTRAP_ADMIN_EMAIL / BOOTSTRAP_ADMIN_PASSWORD create the first admin only when none exists; a restart never rotates the account. Leave both empty to sign up later instead.
  • Pinned versions only. prepare.sh rejects placeholders and mutable tags; only a published, immutable SemVer SYNAPLAN_VERSION may be deployed — never latest.
  • Local AI is opt-in. Cloud AI is the default; set COMPOSE_PROFILES=local-ai and redeploy to add Ollama, the embedding model and Whisper.

Data & persistence

All database, cache, vector, upload, model, and backup data lives below deploy/data/:

Path Contents
data/mariadb Relational data
data/redis Durable Redis append-only file
data/qdrant Vector collections
data/uploads Uploaded and generated files (shared by web + worker)
data/ollama, data/whisper Optional local models
data/backups MariaDB dumps and Qdrant collection snapshots
data/secrets.env Generated deployment secrets — required to restore

Only the web service binds a host port (default 127.0.0.1:8000); MariaDB, Redis, Centrifugo, Tika, Qdrant, Ollama, and Whisper stay on the Compose network.

Backups & restore

Back up deploy/data/ only through the lifecycle hooks, so database and vector snapshots are consistent:

deploy/scripts/pre-backup.sh
# Capture deploy/data with your backup system.
deploy/scripts/post-backup.sh

pre-backup.sh pauses writers, creates a single-transaction MariaDB dump, one snapshot per Qdrant collection, and a checksummed upload archive; post-backup.sh resumes services and keeps seven completed portable backups by default. Restore is the mirror image with pre-restore.sh / post-restore.sh.

Updating

Follow Update a Self-Hosted Deployment (or Update on Elestio). The pre-update hook enforces a successful backup before pulling the new pin; roll back by restoring the previous version pin plus the matching pre-update backup.

Platform adapters

Thin adapters translate platform lifecycle events to the same portable scripts:

Adapter What it is
deploy/elestio/ Elestio Docker Compose CI/CD pipeline (managed hosting)
deploy/aws/ AWS Marketplace AMI: Packer build, systemd, Caddy TLS, CloudFormation
deploy/umbrel/ Umbrel App Store package (self-contained compose, documented deviations)

Beyond a single node