Files
cairnquire/.project/specs/deployment-guide.md
2026-06-04 08:50:34 -04:00

4.2 KiB

Deployment Guide

Requirements

  • Docker 24.0+
  • Docker Compose 2.20+
  • A reverse proxy that terminates TLS for the public hostname
  • A writable checkout directory for ./data and ./content

Fresh Deployment

git clone https://github.com/your-org/cairnquire.git
cd cairnquire
cp .env.example .env

Edit .env and set the HTTPS origin that users will open in their browser:

CAIRNQUIRE_PUBLIC_ORIGIN=https://cairnquire.example.com

Start the application and verify the local container health endpoint:

docker compose up -d --build
docker compose ps
curl http://127.0.0.1:8080/health

Compose starts Mailpit for local SMTP capture. Open http://127.0.0.1:8025 to inspect password-reset and notification messages. SMTP is also exposed on 127.0.0.1:1025 for host-run development servers.

Then open https://cairnquire.example.com/setup. On an empty database the first-run wizard:

  1. Creates the initial administrator account.
  2. Sets its password.
  3. Records whether visitors may create their own accounts.
  4. Signs the administrator in.

The setup endpoint is only available until the first administrator has been created. The signup setting can be changed later from the administrator's account page.

Environment Variables

The checked-in Compose file sets the container paths. For a normal single-host deployment, only CAIRNQUIRE_PUBLIC_ORIGIN must be supplied in .env.

Variable Required Compose default Description
CAIRNQUIRE_PUBLIC_ORIGIN Yes None Exact external HTTPS origin. Passkeys and device-flow URLs depend on this value.
CAIRNQUIRE_EMAIL_SMTP_HOST No mailpit SMTP server used for notifications.
CAIRNQUIRE_EMAIL_SMTP_PORT No 1025 SMTP server port.
CAIRNQUIRE_EMAIL_FROM No notifications@cairnquire.local Notification sender address.
CAIRNQUIRE_LOG_LEVEL No INFO Application log level.

The server also accepts these lower-level overrides when it is run outside the checked-in Compose deployment:

Variable Default Description
CAIRNQUIRE_SERVER_ADDR :8080 Listen address.
CAIRNQUIRE_DATABASE_PATH ../../data/db.sqlite Local SQLite/libsql database path.
CAIRNQUIRE_DATABASE_PRIMARY_URL Empty Optional remote libsql primary URL for embedded-replica mode.
CAIRNQUIRE_DATABASE_AUTH_TOKEN Empty Optional auth token for the remote libsql primary.
CAIRNQUIRE_CONTENT_SOURCE_DIR ../../content Writable Markdown source directory.
CAIRNQUIRE_CONTENT_STORE_DIR ../../data/files Content-addressed attachment store.
CAIRNQUIRE_CONFIG Empty Optional JSON configuration file. Environment variables override it.
CAIRNQUIRE_DEV_MODE false Local-only auth shortcut. Never enable this on a deployed server.

Persistent Data

Compose mounts:

  • ./data:/workspace/data for the database and attachments
  • ./content:/workspace/content for editable Markdown source

Both mounts must remain writable because uploads, browser edits, and sync writebacks modify them.

Reverse Proxy

Expose container port 8080 through a TLS-terminating reverse proxy. Preserve the original hostname and forwarded client address headers. The configured CAIRNQUIRE_PUBLIC_ORIGIN must exactly match the external origin, including https://.

Backup And Restore

Stop writes or stop the app container before copying a fully consistent local database backup:

docker compose stop app
tar czf cairnquire-backup.tgz data content
docker compose up -d app

Restore by stopping the app, replacing data and content from the archive, and starting the app again.

Upgrade

docker compose stop app
tar czf cairnquire-backup-before-upgrade.tgz data content
git pull
docker compose up -d --build
curl http://127.0.0.1:8080/health

Database migrations run automatically on startup.

Troubleshooting

docker compose logs -f app
docker compose ps
curl http://127.0.0.1:8080/health

If passkey creation fails after deployment, confirm that the browser URL and CAIRNQUIRE_PUBLIC_ORIGIN are the same HTTPS origin.