430 lines
13 KiB
Markdown
430 lines
13 KiB
Markdown
# 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.
|