11 KiB
Production Deployment Guide
This guide provides instructions for deploying Kaboot to a production environment with Caddy reverse proxy and automatic HTTPS.
Quick Start (Automated Setup)
The easiest way to deploy Kaboot is using the automated setup script:
# Run the production setup script with your domains
./scripts/setup-prod.sh --domain kaboot.example.com --auth-domain auth.example.com
# Or run interactively (will prompt for domains)
./scripts/setup-prod.sh
This script automatically:
- Generates all required secrets (database passwords, API tokens, etc.)
- Creates the production
.envfile - Creates the
Caddyfilewith your domains - Creates the Authentik production blueprint
- Removes the development blueprint
- Builds the frontend with production URLs
After running the script, start the stack:
docker compose -f docker-compose.prod.yml -f docker-compose.caddy.yml up -d
Accessing Authentik Admin
After the stack is running, you can access the Authentik admin interface:
- URL:
https://auth.your-domain.com/if/admin/ - Username:
akadmin - Password: The password shown when you ran
setup-prod.sh(stored asAUTHENTIK_BOOTSTRAP_PASSWORDin.env)
From the admin interface you can:
- Manage users and groups
- View application access logs
- Configure additional OAuth providers
- Set up email for password recovery
- Customize the login/signup UI
Manual Setup
If you prefer to configure manually, follow these steps:
# 1. Generate secrets
./scripts/setup.sh
# 2. Configure production blueprint
cp authentik/blueprints/kaboot-setup-production.yaml.example \
authentik/blueprints/kaboot-setup-production.yaml
# Edit the blueprint - update domains in the 'context' section:
# kaboot_domain: your-app.com
# auth_domain: auth.your-app.com
# Remove dev blueprint to avoid conflicts
rm authentik/blueprints/kaboot-setup.yaml
# 3. Configure Caddyfile
cp Caddyfile.example Caddyfile
# Edit Caddyfile - replace example.com with your domains
# 4. Update .env with production values
# - OIDC_ISSUER=https://auth.your-app.com/application/o/kaboot/
# - OIDC_JWKS_URI=https://auth.your-app.com/application/o/kaboot/jwks/
# - CORS_ORIGIN=https://your-app.com
# 5. Build frontend with production URLs
VITE_API_URL=https://your-app.com/api \
VITE_OIDC_AUTHORITY=https://auth.your-app.com/application/o/kaboot/ \
npm run build
# 6. Start the stack
docker compose -f docker-compose.prod.yml -f docker-compose.caddy.yml up -d
# 7. Verify
docker compose -f docker-compose.prod.yml -f docker-compose.caddy.yml ps
Prerequisites
- A Linux server with Docker and Docker Compose installed.
- Two registered domain names (e.g.,
kaboot.example.comandauth.example.com). - DNS A records pointing both domains to your server.
- A Google Gemini API key.
Architecture Overview
In production, the stack consists of:
- Caddy: Reverse proxy with automatic HTTPS via Let's Encrypt.
- Authentik: Identity Provider for OAuth2/OIDC authentication.
- Kaboot Backend: Express server for quiz logic and SQLite storage.
- Kaboot Frontend: Static assets served via Caddy.
- PostgreSQL: Database for Authentik.
- Redis: Cache and task queue for Authentik.
Environment Variables
The setup-prod.sh script generates the .env file automatically. If you need to create it manually, here's the required configuration:
Backend & Authentik Configuration
# Database (generate with: openssl rand -base64 36)
PG_PASS=your_strong_postgres_password
PG_USER=authentik
PG_DB=authentik
# Authentik Secrets (generate with: openssl rand -base64 60)
AUTHENTIK_SECRET_KEY=your_strong_authentik_secret
# Bootstrap credentials - used for initial Authentik setup
# AUTHENTIK_BOOTSTRAP_PASSWORD: Admin password (generate with: openssl rand -base64 24)
# AUTHENTIK_BOOTSTRAP_TOKEN: API token (generate with: openssl rand -hex 32)
AUTHENTIK_BOOTSTRAP_PASSWORD=your_admin_password
AUTHENTIK_BOOTSTRAP_TOKEN=your_api_token
# OIDC Production Settings (update with your domains)
OIDC_ISSUER=https://auth.example.com/application/o/kaboot/
OIDC_JWKS_URI=https://auth.example.com/application/o/kaboot/jwks/
# Security
CORS_ORIGIN=https://kaboot.example.com
NODE_ENV=production
LOG_REQUESTS=true
Frontend Configuration
The frontend requires environment variables at build time (not runtime):
VITE_API_URL:https://kaboot.example.com/apiVITE_OIDC_AUTHORITY:https://auth.example.com/application/o/kaboot/
The setup-prod.sh script sets these automatically when building.
Docker Compose Files
The project includes pre-configured compose files:
docker-compose.prod.yml- Production services (Authentik, Backend, PostgreSQL, Redis)docker-compose.caddy.yml- Caddy reverse proxy overlay
These files are ready to use - no need to create your own.
HTTPS and Reverse Proxy
Choose one of the following reverse proxy options. Caddy is recommended for its simplicity and automatic HTTPS.
Option 1: Caddy (Recommended)
Caddy automatically obtains and renews SSL certificates from Let's Encrypt.
A separate docker-compose.caddy.yml is provided to add Caddy to your stack.
Step 1: Create the Caddyfile
Copy and customize the example Caddyfile:
cp Caddyfile.example Caddyfile
Edit Caddyfile and replace kaboot.example.com and auth.example.com with your actual domains:
kaboot.example.com {
root * /srv/frontend
file_server
try_files {path} /index.html
handle /api/* {
reverse_proxy kaboot-backend:3001
}
handle /health {
reverse_proxy kaboot-backend:3001
}
}
auth.example.com {
reverse_proxy authentik-server:9000 {
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Host {host}
transport http {
keepalive 30s
}
}
}
Step 2: Build the Frontend
npm run build
This creates the dist/ directory with production assets.
Step 3: Start with Caddy
Use both compose files together:
docker compose -f docker-compose.prod.yml -f docker-compose.caddy.yml up -d
This will:
- Start all Kaboot services (backend, Authentik, PostgreSQL, Redis)
- Start Caddy as a reverse proxy on ports 80 and 443
- Automatically obtain SSL certificates from Let's Encrypt
Step 4: Verify
Check that all services are running:
docker compose -f docker-compose.prod.yml -f docker-compose.caddy.yml ps
View Caddy logs:
docker logs kaboot-caddy
Check Authentik blueprint was applied:
docker compose -f docker-compose.prod.yml logs authentik-server | grep -i blueprint
Stopping the Stack
docker compose -f docker-compose.prod.yml -f docker-compose.caddy.yml down
Option 2: Nginx
Use Nginx as a reverse proxy with manual SSL certificate management.
server {
listen 443 ssl;
server_name kaboot.example.com;
ssl_certificate /etc/letsencrypt/live/kaboot.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/kaboot.example.com/privkey.pem;
location / {
root /var/www/kaboot/frontend;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://localhost:3001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /health {
proxy_pass http://localhost:3001/health;
}
}
server {
listen 443 ssl;
server_name auth.example.com;
ssl_certificate /etc/letsencrypt/live/auth.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.example.com/privkey.pem;
location / {
proxy_pass http://localhost:9000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Authentik Configuration for Production
Option A: Automated Setup (Recommended)
The setup-prod.sh script handles all Authentik configuration automatically:
./scripts/setup-prod.sh --domain your-app.com --auth-domain auth.your-app.com
This creates the production blueprint with your domains and removes the development blueprint.
Option B: Manual Blueprint Setup
If configuring manually:
# 1. Copy and configure the production blueprint
cp authentik/blueprints/kaboot-setup-production.yaml.example \
authentik/blueprints/kaboot-setup-production.yaml
# 2. Edit the blueprint and update the domains
# Find the 'context' section and change:
# - kaboot_domain: kaboot.example.com -> your-app.com
# - auth_domain: auth.example.com -> auth.your-app.com
# 3. Remove the development blueprint (prevents conflicts)
rm authentik/blueprints/kaboot-setup.yaml
# 4. Start the stack - blueprint applies automatically
docker compose -f docker-compose.prod.yml up -d
Option C: Manual UI Configuration
- Update Redirect URIs: In the Authentik Admin interface, go to Applications > Providers > Kaboot OAuth2. Update the Redirect URIs to use your production domain:
https://kaboot.example.com/callbackhttps://kaboot.example.com/silent-renew.htmlhttps://kaboot.example.com
Email Configuration
To enable password recovery, configure SMTP settings in Authentik. In the Admin interface, go to System > Settings and update the Email section. - Host: your SMTP server - Port: 587 or 465 - Username/Password: your credentials - Use TLS/SSL: Enabled
Database Backup Strategy
Kaboot uses SQLite, making backups straightforward.
SQLite (Kaboot Data)
The database file is located in the kaboot-data volume at /data/kaboot.db. To back it up:
docker exec kaboot-backend sqlite3 /data/kaboot.db ".backup '/data/backup_$(date +%F).db'"
Then, copy the backup file from the volume to a secure location.
PostgreSQL (Authentik Data)
For Authentik's metadata:
docker exec kaboot-postgresql pg_dump -U authentik authentik > authentik_backup_$(date +%F).sql
Security Checklist
- Run
./scripts/setup-prod.shto generate strong secrets (don't use defaults). - Ensure
NODE_ENVis set toproduction. - Use HTTPS for all connections (Caddy handles this automatically).
- Set
CORS_ORIGINto your specific frontend domain (e.g.,https://kaboot.example.com). - Update
OIDC_ISSUERandOIDC_JWKS_URIto use your auth domain with HTTPS. - Regularly back up the
kaboot.dband PostgreSQL data. - Monitor logs by setting
LOG_REQUESTS=true. - Keep Docker images updated to the latest stable versions.
- Configure firewall to only allow ports 80 and 443 from the internet.