Docker
Docker Deployment Guide
Section titled “Docker Deployment Guide”This repo ships with a production-ready Dockerfile plus a docker-compose.yml that bundles the Hono API and the Vite frontend into a single service. The Hono server serves the built SPA from frontend/dist, so only one container/port is needed.
1. Required environment variables
Section titled “1. Required environment variables”Create server/.env (or update the existing file) so the compose file can load it. At minimum set:
# RuntimeNODE_ENV=productionPORT=3001DATABASE_URL=sqlite:///app/server/data/chat.db
# Security / encryptionAPI_KEY_ENCRYPTION_KEY=<32-byte hex string>ADMIN_SETUP_TOKEN=<one-time secret used for the first admin signup>TRUST_PROXY=false # set to true only when running behind a trusted reverse proxy
# Optional app configAPP_URL=http://localhost:3001Generate a key with node -e "console.log(require('crypto').randomBytes(32).toString('hex'))". The ADMIN_SETUP_TOKEN gates the bootstrap /api/auth/register endpoint—share it only with whoever will create the very first administrator account. Remove or rotate it after bootstrap if desired.
2. Build the container
Section titled “2. Build the container”docker compose buildThe multi-stage build uses bun install to hydrate the workspaces, compiles the Vite frontend, and copies everything into a slim Node 20 runtime layer. No extra steps are required.
3. Run the stack
Section titled “3. Run the stack”docker compose up -dThis publishes port 3001 by default (override using the PORT env var). SQLite data lives at /app/server/data/chat.db, which is mapped to the named volume chat-data so your chat history and settings persist across container restarts.
4. First-time bootstrap
Section titled “4. First-time bootstrap”- Visit
http://localhost:3001/login. - Switch to the “Create Account” tab, enter the setup token value (the app sends it via
x-setup-tokenautomatically when you addsetupTokento the request body—update the UI if you prefer prompting for it), and create the initial admin. - Immediately after that,
/api/auth/registeris permanently disabled, so all additional users must be created through the admin UI/API.
5. Reverse proxy / HTTPS
Section titled “5. Reverse proxy / HTTPS”If you terminate TLS in front of the container (e.g., Traefik, Nginx, or Cloudflare Tunnel), set TRUST_PROXY=true to let the server honor X-Forwarded-For when applying rate limits. Leave it false when the container faces the client directly.
6. Common commands
Section titled “6. Common commands”# View logsdocker compose logs -f
# Stop the servicedocker compose down
# Remove containers but keep the persistent volumedocker compose down --remove-orphansThat’s it—ship the container wherever Docker runs (local machine, NAS, VPS, or K8s) and it will serve both the UI and /api from the same port. Adjust the compose file to add Traefik labels, bind-mount a custom frontend/dist, or swap the SQLite volume for Postgres if you expand beyond a single-host deployment.
7. Troubleshooting
Section titled “7. Troubleshooting”Rebuilding from scratch
Section titled “Rebuilding from scratch”If you encounter issues, try rebuilding without cache:
docker compose build --no-cacheDatabase reset
Section titled “Database reset”To reset the database while keeping the container:
docker compose downdocker volume rm faster-chat_chat-datadocker compose up -dPort already in use
Section titled “Port already in use”Check what’s using the port:
lsof -ti:8787 | xargs kill -9Build architecture notes
Section titled “Build architecture notes”The Dockerfile uses a two-stage build:
- Builder (
oven/bun:1.3-debian) - Fast dependency install, frontend build - Runner (
node:22-bookworm-slim) - Lightweight production runtime
Bun SQLite is used for the database, providing better performance than better-sqlite3.
8. Production checklist
Section titled “8. Production checklist”For production deployments, consider:
- Reverse proxy (Caddy, nginx, Traefik) for HTTPS - see
docs/https/ - Proper environment variables for API keys
- Volume backups for the SQLite database
- Resource limits in docker-compose.yml:
services: faster-chat: deploy: resources: limits: cpus: '2' memory: 2G reservations: cpus: '1' memory: 512M