# Deploying Deadhead The production stack runs on one machine with Docker Compose: Postgres, the API server and Caddy. Caddy serves the web app, proxies `/api` to the server and gets HTTPS certificates for the domain automatically. ## Before the first start 1. **DNS:** point an `A` record for `deadhead.belowland.com` at the public IP of the network the server is on. 2. **Router:** forward TCP ports 80 and 443 (and UDP 443 for HTTP/3) to the server. Let's Encrypt checks port 80 before it issues a certificate. 3. **Docker:** Docker Engine with the Compose plugin (`docker compose version`). 4. **Settings:** in this folder, `cp .env.example .env` and fill in `POSTGRES_PASSWORD` and `BETTER_AUTH_SECRET` (the comments say how to make them). Keep `.env` private; it is ignored by git. ## Start and update From this folder, on the server: ```sh git pull APP_BUILD=$(git rev-parse --short HEAD) docker compose up -d --build ``` The server applies database migrations on every start, then begins serving. `docker compose ps` shows each service's health; `docker compose logs -f server` follows the API log. The About screen in Settings shows the build you deployed. ## On a LAN only (no domain) Set `SITE_ADDRESS=:80` and `PUBLIC_URL=http://` in `.env`. Caddy then serves plain HTTP. Installing the app to a phone home screen needs HTTPS, so this is for testing. ## Check a build before deploying ```sh deploy/check.sh ``` This builds and starts the whole stack under a separate project name with throwaway secrets, on port 8088. It checks the API, the app, caching, a guest sign-up with a tutorial run, and a backup restored into a fresh database. Then it removes everything. It never touches the real stack. ## Backups The `backup` service writes a compressed dump of the database every night at `BACKUP_HOUR`:00 (`TZ`, default UTC) to `BACKUP_DIR`, and deletes dumps older than `BACKUP_KEEP_DAYS`. Point `BACKUP_DIR` at a folder that lives on another disk, such as a NAS share mounted on the server (for example through `/etc/fstab`). Make sure the share is mounted before Docker starts, or the dumps land on the server's own disk. Take a backup now: ```sh docker compose exec backup /scripts/backup.sh ``` Test a restore without touching the live data. This loads the newest dump into a separate `deadhead_restore` database: ```sh docker compose exec backup /scripts/restore.sh ``` Recover the live database from a dump (stop the server first so nothing writes while it loads): ```sh docker compose stop server docker compose exec backup /scripts/restore.sh /backups/deadhead-.dump deadhead docker compose start server ```