5d01c9f564
Separate configuration from data storage and make paths configurable via environment variables and command-line flags. This improves Unix/Linux compliance and supports both development and production deployments. Key changes: - Separate config dir (opal.yml) from data dir (database, logs) - Support XDG Base Directory specification - Add --config-dir and --data-dir flags - Environment variables: OPAL_CONFIG_DIR, OPAL_DATA_DIR, OPAL_DB_PATH - Smart fallback: /etc/opal, /var/lib/opal -> ~/.config/opal, ~/.local/share/opal - Server mode validates required OAuth/JWT environment variables - Update naming from 'jade' to 'opal' throughout - Update systemd service name to 'opal.service' - Add migration guide in README Default paths: - Config: /etc/opal (fallback: ~/.config/opal) - Data: /var/lib/opal (fallback: ~/.local/share/opal) Files modified: - internal/engine/config.go: New directory resolution logic - internal/engine/database.go: Auto-create data directory - cmd/root.go: Add global flags for directory overrides - cmd/server.go: Add configuration validation - cmd/sync.go, internal/sync/*: Use new path helper functions - tests: Update to use directory overrides - docs: Update deployment guide and README
7.2 KiB
7.2 KiB
Opal-Web Deployment Guide
Overview
This guide covers deploying the Opal Task Manager PWA to production on opal.example.com with Caddy as the web server.
Prerequisites
- Server with Caddy installed
- Domain:
opal.example.com(DNS configured) - Authentik OAuth configured at
auth.example.com - Opal Go API server binary built
Architecture
Browser → Caddy (opal.example.com)
├─ / → Static PWA (SvelteKit build)
└─ /api/* → Go API Server (:8080)
Step 1: Build the Frontend
Local Build
cd opal-web
# Install dependencies if needed
bun install
# Build for production
bun run build
# Output will be in: build/
The build creates a static site ready to deploy.
Step 2: Deploy Static Files
Option A: Direct Copy
# On your local machine
rsync -avz --delete build/ user@server:/var/www/opal/
Option B: Server-Side Build
# On the server
cd /opt/opal-web
git pull
bun install
bun run build
cp -r build/* /var/www/opal/
Set Permissions
sudo chown -R www-data:www-data /var/www/opal
sudo chmod -R 755 /var/www/opal
Step 3: Configure Backend
Create Environment File
sudo mkdir -p /etc/opal
sudo nano /etc/opal/opal.env
Add:
# Server
SERVER_ADDR=:8080
# Directory Configuration
OPAL_CONFIG_DIR=/etc/opal
OPAL_DATA_DIR=/var/lib/opal
# OAuth (from Authentik setup)
OAUTH_ENABLED=true
OAUTH_ISSUER=https://auth.example.com/application/o/opal/
OAUTH_CLIENT_ID=your_client_id_from_authentik
OAUTH_CLIENT_SECRET=your_client_secret_from_authentik
OAUTH_REDIRECT_URI=https://opal.example.com/auth/callback
# JWT (generate with: openssl rand -hex 32)
JWT_SECRET=your_generated_jwt_secret_here
JWT_EXPIRY=3600
# Refresh Token
REFRESH_TOKEN_EXPIRY=604800
Note: The config directory (/etc/opal) contains read-only settings, while the data directory (/var/lib/opal) contains the database and mutable state.
Create SystemD Service
sudo nano /etc/systemd/system/opal.service
[Unit]
Description=Opal Task API Server
After=network.target
[Service]
Type=simple
User=opal
Group=opal
WorkingDirectory=/var/lib/opal
EnvironmentFile=/etc/opal/opal.env
ExecStart=/usr/local/bin/opal server start --addr :8080
Restart=always
RestartSec=5
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/opal
ReadOnlyPaths=/etc/opal
[Install]
WantedBy=multi-user.target
Note: The --db flag is no longer needed since the database path is configured via OPAL_DATA_DIR environment variable.
Setup Database and User
# Create user
sudo useradd -r -s /bin/false opal
# Create directories
sudo mkdir -p /var/lib/opal
sudo chown opal:opal /var/lib/opal
sudo chmod 750 /var/lib/opal
# Build and install binary
cd opal-task
go build -o opal main.go
sudo cp opal /usr/local/bin/
sudo chmod 755 /usr/local/bin/opal
# Generate first API key (optional - for CLI access)
sudo -u opal OPAL_DATA_DIR=/var/lib/opal opal server keygen --name "Admin CLI"
# Save the generated key!
# Start service
sudo systemctl daemon-reload
sudo systemctl enable opal
sudo systemctl start opal
sudo systemctl status opal
Step 4: Configure Caddy
Create Caddyfile
sudo nano /etc/caddy/Caddyfile
Add:
opal.example.com {
# Root directory for static PWA
root * /var/www/opal
# API proxy
handle /api/* {
uri strip_prefix /api
reverse_proxy localhost:8080
}
# Static file serving with SPA fallback
handle {
try_files {path} /index.html
file_server
}
# Security headers
header {
# HTTPS only
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Prevent clickjacking
X-Frame-Options "SAMEORIGIN"
# XSS protection
X-Content-Type-Options "nosniff"
# CSP (adjust as needed)
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' https://auth.example.com;"
}
# Logging
log {
output file /var/log/caddy/opal.log
format json
}
# Compression
encode gzip
}
Test and Reload Caddy
# Test configuration
sudo caddy validate --config /etc/caddy/Caddyfile
# Reload
sudo systemctl reload caddy
# Check status
sudo systemctl status caddy
Step 5: Verify Deployment
Check Services
# API server
sudo systemctl status opal
sudo journalctl -u opal -n 50
# Caddy
sudo systemctl status caddy
sudo journalctl -u caddy -n 50
Test Endpoints
# Health check
curl https://opal.example.com/api/health
# OAuth login URL
curl https://opal.example.com/api/auth/login
# Static files
curl -I https://opal.example.com/
Browser Testing
- Navigate to
https://opal.example.com - Should see the Opal login page
- Click "Login with OAuth"
- Should redirect to Authentik
- After login, should redirect back to task list
- Test creating a task
- Test PWA install prompt (mobile/desktop)
Step 6: Update Deployment (Future)
# Frontend update
cd opal-web
git pull
bun install
bun run build
rsync -avz --delete build/ server:/var/www/opal/
# Backend update
cd opal-task
git pull
go build -o opal main.go
scp opal server:/tmp/
ssh server "sudo systemctl stop opal && sudo cp /tmp/opal /usr/local/bin/ && sudo systemctl start opal"
Troubleshooting
API Not Responding
# Check if running
sudo systemctl status opal
# Check logs
sudo journalctl -u opal -f
# Test locally
curl http://localhost:8080/health
OAuth Not Working
- Verify redirect URI in Authentik matches exactly
- Check OAuth client ID and secret in env file
- Ensure JWT secret is set
- Check Caddy is proxying /api/* correctly
PWA Not Installing
- Ensure HTTPS is working
- Check manifest.json is accessible
- Verify service worker is registered (Browser DevTools → Application)
- Icons must be served correctly
Static Files 404
- Check file permissions in /var/www/opal
- Verify Caddy root directive points to correct path
- Ensure index.html exists in root
Monitoring
Logs
# API logs
sudo journalctl -u opal -f
# Caddy logs
sudo tail -f /var/log/caddy/opal.log
# System logs
dmesg | grep opal
Database Backup
# Backup script
#!/bin/bash
BACKUP_DIR="/var/backups/opal"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
sudo -u opal sqlite3 /var/lib/opal/opal.db ".backup '$BACKUP_DIR/opal_$DATE.db'"
# Keep last 7 days
find "$BACKUP_DIR" -name "opal_*.db" -mtime +7 -delete
Add to crontab:
0 2 * * * /usr/local/bin/backup-opal.sh
Security Checklist
- ✅ HTTPS enforced (Caddy auto)
- ✅ OAuth2 authentication configured
- ✅ JWT tokens with expiry
- ✅ API key hashing (bcrypt)
- ✅ SystemD service hardening
- ✅ Database file permissions (750)
- ✅ Security headers (CSP, HSTS, etc.)
- ✅ Regular backups configured
- ⬜ Fail2ban for API rate limiting (optional)
- ⬜ Log monitoring/alerting (optional)
Performance Tips
- Caddy handles compression and HTTP/2
- Service worker caches static assets
- API responses cached by service worker
- Consider CDN for static assets (future)
Support
- Check logs first
- Verify all environment variables
- Test OAuth flow in incognito
- Check network tab in DevTools