Deploy with Docker
The forum ships as a Docker image built on python:3.13-slim, running as a
non-root user. This page covers running it in production.
Minimum to boot
Section titled “Minimum to boot”Provide the contract settings and point the web server at a TCP port so your proxy can reach it:
docker run -d --name bluset \ -e DATABASE_URL='postgresql://user:pass@db:5432/bluset' \ -e SECRET_KEY='<a long random string>' \ -e GUNICORN_BIND='0.0.0.0:8000' \ -e BLUSET_REDIS_URL='redis://redis:6379' \ -e BLUSET_REDIS_ENABLED='True' \ -e BLUSET_MAIL_SERVER='smtp.example.com' \ -e BLUSET_MAIL_PORT='587' -e BLUSET_MAIL_USE_TLS='True' \ -e BLUSET_MAIL_USERNAME='...' -e BLUSET_MAIL_PASSWORD='...' \ -e BLUSET_MAIL_DEFAULT_SENDER='noreply@example.com' \ -p 127.0.0.1:8000:8000 \ <your-image-reference>Run Postgres and Redis either as their own containers on the same network (a Compose file is the usual way) or as managed services you point the URLs at.
First-boot install
Section titled “First-boot install”The image runs its install/migrate/seed steps idempotently on every start, but it will not create an administrator with default credentials. Create the first admin explicitly:
docker exec -it bluset bluset create-admin \ -u admin -e admin@example.com -p '<a strong password>'See the CLI reference for install,
seed-features, and more.
Health checks
Section titled “Health checks”The container exposes a health blueprint:
GET /up/— liveness.GET /up/databases— deep check (Redis + database).GET /up/ready— readiness alias.
Point your orchestrator’s health check at /up/ (the image’s default) and your
load balancer’s deep check at /up/databases.
Migrations
Section titled “Migrations”By default (BLUSET_AUTO_MIGRATE=True) the container applies migrations on
start, so a new image version migrates itself when it boots. If you prefer to
control exactly when schema changes land, set BLUSET_AUTO_MIGRATE=False and
run them yourself before starting the new version:
docker exec -it bluset bluset db upgradeRunning migrations twice is safe (they’re idempotent) — pick one approach and be consistent.
Put a reverse proxy in front
Section titled “Put a reverse proxy in front”The container serves plain HTTP; you terminate TLS. Any reverse proxy works (nginx, Caddy, Traefik, a cloud load balancer). The essentials:
- Terminate HTTPS at the proxy and forward to the container’s
0.0.0.0:8000. - Forward the
Hostheader and the standardX-Forwarded-*headers so the app builds correct absolute URLs and treats the connection as secure. - Serve on your own domain; production mode already marks cookies Secure, so the site must be reachable over HTTPS.
Backups
Section titled “Backups”You own backups. At minimum, back up the PostgreSQL database and any
uploaded files on a schedule, store them off the host, and rehearse a
restore before you need one. Test that a restored copy boots and serves
/up/databases green.
Upgrading
Section titled “Upgrading”- Pull the new image tag.
- Run
bluset db upgrade(or rely onBLUSET_AUTO_MIGRATE). - Recreate the container on the new tag.
- Verify
/up/databasesand log in.
Keep the previous image tag handy so you can roll back by recreating the container on it if an upgrade misbehaves.