# 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: ```bash # 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 `.env` file - Creates the `Caddyfile` with your domains - Creates the Authentik production blueprint - Removes the development blueprint - Builds the frontend with production URLs After running the script, start the stack: ```bash 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: 1. **URL**: `https://auth.your-domain.com/if/admin/` 2. **Username**: `akadmin` 3. **Password**: The password shown when you ran `setup-prod.sh` (stored as `AUTHENTIK_BOOTSTRAP_PASSWORD` in `.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: ```bash # 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. - A registered domain name (e.g., `example.com`). - DNS A records pointing your domains to your server (see below). - A Google Gemini API key (optional, for AI quiz generation). ## DNS Configuration You need two DNS records pointing to your server's IP address. You can use either: - **Subdomains**: `kaboot.example.com` + `auth.example.com` (recommended) - **Apex + subdomain**: `example.com` + `auth.example.com` ### Finding Your Server's IP ```bash # On your server, run: curl -4 ifconfig.me ``` ### Namecheap Setup 1. Log in to [Namecheap](https://www.namecheap.com/) and go to **Domain List** 2. Click **Manage** next to your domain 3. Go to the **Advanced DNS** tab 4. Add the following **A Records**: | Type | Host | Value | TTL | |------|------|-------|-----| | A Record | `kaboot` | `YOUR_SERVER_IP` | Automatic | | A Record | `auth` | `YOUR_SERVER_IP` | Automatic | > **Note**: The "Host" field is the subdomain prefix only. For `kaboot.example.com`, enter just `kaboot`. ### Cloudflare Setup 1. Log in to [Cloudflare](https://dash.cloudflare.com/) and select your domain 2. Go to **DNS** → **Records** 3. Click **Add record** and create: | Type | Name | IPv4 address | Proxy status | |------|------|--------------|--------------| | A | `kaboot` | `YOUR_SERVER_IP` | DNS only (gray cloud) | | A | `auth` | `YOUR_SERVER_IP` | DNS only (gray cloud) | > **Important**: Set proxy status to "DNS only" (gray cloud) for both records. Caddy handles SSL, and Cloudflare's proxy can interfere with certificate generation. ### Other Providers (GoDaddy, Google Domains, etc.) The process is similar for most providers: 1. Find the **DNS Management** or **DNS Settings** section 2. Add two **A Records**: - **Name/Host**: `kaboot` → **Value/Points to**: `YOUR_SERVER_IP` - **Name/Host**: `auth` → **Value/Points to**: `YOUR_SERVER_IP` 3. Set TTL to automatic or 300 seconds ### Verify DNS Propagation After adding records, verify they're working (may take 5-30 minutes): ```bash # Check if DNS resolves to your server dig kaboot.example.com +short dig auth.example.com +short # Or use nslookup nslookup kaboot.example.com nslookup auth.example.com ``` Both should return your server's IP address. You can also use [dnschecker.org](https://dnschecker.org/) to verify global propagation. ## 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 ```env # 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/api` - `VITE_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: ```bash cp Caddyfile.example Caddyfile ``` Edit `Caddyfile` and replace `kaboot.example.com` and `auth.example.com` with your actual domains: ```caddyfile 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** ```bash npm run build ``` This creates the `dist/` directory with production assets. **Step 3: Start with Caddy** Use both compose files together: ```bash 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: ```bash docker compose -f docker-compose.prod.yml -f docker-compose.caddy.yml ps ``` View Caddy logs: ```bash docker logs kaboot-caddy ``` Check Authentik blueprint was applied: ```bash docker compose -f docker-compose.prod.yml logs authentik-server | grep -i blueprint ``` **Stopping the Stack** ```bash 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. ```nginx 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: ```bash ./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: ```bash # 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 1. **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/callback` - `https://kaboot.example.com/silent-renew.html` - `https://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: ```bash 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: ```bash docker exec kaboot-postgresql pg_dump -U authentik authentik > authentik_backup_$(date +%F).sql ``` ## Security Checklist - [ ] Run `./scripts/setup-prod.sh` to generate strong secrets (don't use defaults). - [ ] Ensure `NODE_ENV` is set to `production`. - [ ] Use HTTPS for all connections (Caddy handles this automatically). - [ ] Set `CORS_ORIGIN` to your specific frontend domain (e.g., `https://kaboot.example.com`). - [ ] Update `OIDC_ISSUER` and `OIDC_JWKS_URI` to use your auth domain with HTTPS. - [ ] Regularly back up the `kaboot.db` and 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.