Skip to content

Docker

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.

Create server/.env (or update the existing file) so the compose file can load it. At minimum set:

# Runtime
NODE_ENV=production
PORT=3001
DATABASE_URL=sqlite:///app/server/data/chat.db
# Security / encryption
API_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 config
APP_URL=http://localhost:3001

Generate 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.

Terminal window
docker compose build

The 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.

Terminal window
docker compose up -d

This 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.

  1. Visit http://localhost:3001/login.
  2. Switch to the “Create Account” tab, enter the setup token value (the app sends it via x-setup-token automatically when you add setupToken to the request body—update the UI if you prefer prompting for it), and create the initial admin.
  3. Immediately after that, /api/auth/register is permanently disabled, so all additional users must be created through the admin UI/API.

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.

Terminal window
# View logs
docker compose logs -f
# Stop the service
docker compose down
# Remove containers but keep the persistent volume
docker compose down --remove-orphans

That’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.

If you encounter issues, try rebuilding without cache:

Terminal window
docker compose build --no-cache

To reset the database while keeping the container:

Terminal window
docker compose down
docker volume rm faster-chat_chat-data
docker compose up -d

Check what’s using the port:

Terminal window
lsof -ti:8787 | xargs kill -9

The Dockerfile uses a two-stage build:

  1. Builder (oven/bun:1.3-debian) - Fast dependency install, frontend build
  2. Runner (node:22-bookworm-slim) - Lightweight production runtime

Bun SQLite is used for the database, providing better performance than better-sqlite3.

For production deployments, consider:

  1. Reverse proxy (Caddy, nginx, Traefik) for HTTPS - see docs/https/
  2. Proper environment variables for API keys
  3. Volume backups for the SQLite database
  4. Resource limits in docker-compose.yml:
services:
faster-chat:
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '1'
memory: 512M