BREAKING: JWT keys are now auto-managed by Better Auth (EdDSA/Ed25519) - Remove all JWT_PRIVATE_KEY, JWT_PUBLIC_KEY, JWT_SECRET references - Keys stored in auth.jwks database table (auto-generated on first run) - Delete obsolete generate-keys.sh and generate-staging-secrets.sh scripts - Clean up legacy AUTH_*.md analysis files from root Security Improvements: - Add security_events table for audit logging - Add SecurityEventsService for tracking auth events - Enhanced security headers (HSTS, CSP, X-Frame-Options) - Rate limiting configuration Monitoring Setup: - Add auth-health-check.sh for automated testing - Add generate-dashboard.sh for HTML status dashboard - Tests: health endpoint, JWKS (EdDSA), security headers, response time - Ready for Hetzner cron deployment Documentation: - Update deployment docs with Better Auth notes - Update environment variable references - Add security improvements documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
10 KiB
CI/CD Setup Guide
Step-by-step guide to configure the CI/CD pipeline for the manacore-monorepo.
Quick Start
- Configure GitHub Secrets
- Set Up Docker Registry
- Configure Deployment Servers
- Enable GitHub Actions
- Test the Pipeline
GitHub Secrets
Navigate to Secrets
- Go to your GitHub repository
- Click
Settings>Secrets and variables>Actions - Click
New repository secret
Required Secrets
Docker Registry (3 secrets)
DOCKER_USERNAME=your-docker-hub-username
DOCKER_PASSWORD=your-docker-hub-password-or-token
DOCKER_REGISTRY=wuesteon
How to get Docker credentials:
- Create account at https://hub.docker.com
- Go to Account Settings > Security
- Create Access Token
- Use token as DOCKER_PASSWORD
SSH Keys (2 secrets per environment)
Generate SSH keys:
# Generate new key pair
ssh-keygen -t ed25519 -C "github-actions-staging" -f ~/.ssh/github-actions-staging
# Display private key (copy this to GitHub secret)
cat ~/.ssh/github-actions-staging
# Display public key (add this to server)
cat ~/.ssh/github-actions-staging.pub
Add to GitHub:
STAGING_SSH_KEY=<private-key-content>
PRODUCTION_SSH_KEY=<private-key-content>
Server Access (2 secrets per environment)
STAGING_HOST=staging.manacore.app
STAGING_USER=deploy
PRODUCTION_HOST=api.manacore.app
PRODUCTION_USER=deploy
Database Configuration (Staging)
STAGING_POSTGRES_HOST=postgres
STAGING_POSTGRES_PORT=5432
STAGING_POSTGRES_DB=manacore
STAGING_POSTGRES_USER=postgres
STAGING_POSTGRES_PASSWORD=<generate-secure-password>
Generate secure password:
openssl rand -base64 32
Redis Configuration (Staging)
STAGING_REDIS_HOST=redis
STAGING_REDIS_PORT=6379
STAGING_REDIS_PASSWORD=<generate-secure-password>
Supabase Configuration (Staging)
STAGING_SUPABASE_URL=https://xxxxx.supabase.co
STAGING_SUPABASE_ANON_KEY=<your-anon-key>
STAGING_SUPABASE_SERVICE_ROLE_KEY=<your-service-role-key>
How to get Supabase credentials:
- Go to https://supabase.com
- Open your project
- Go to Project Settings > API
- Copy
URL,anon public, andservice_rolekeys
Azure OpenAI Configuration (Staging)
STAGING_AZURE_OPENAI_ENDPOINT=https://xxxxx.openai.azure.com
STAGING_AZURE_OPENAI_API_KEY=<your-api-key>
STAGING_AZURE_OPENAI_API_VERSION=2024-12-01-preview
JWT Configuration
Note: JWT keys are managed automatically by Better Auth (EdDSA/Ed25519).
Keys are auto-generated on first startup and stored in the auth.jwks database table.
No manual key generation or configuration is required.
Production Secrets
For production, configure the same secrets as staging with PRODUCTION_ prefix.
Use different values for production - never reuse staging credentials.
Optional: Turbo Cache
For faster builds with remote caching:
TURBO_TOKEN=<vercel-token>
TURBO_TEAM=<team-name>
Get these from https://vercel.com
Optional: Code Coverage
CODECOV_TOKEN=<codecov-token>
Get from https://codecov.io
Docker Registry
Option 1: Docker Hub (Recommended)
- Sign up at https://hub.docker.com
- Create access token (Account Settings > Security)
- Add credentials to GitHub secrets
- Create repository for each service:
wuesteon/mana-core-authwuesteon/chat-backendwuesteon/maerchenzauber-backend- etc.
Option 2: GitHub Container Registry
# In .github/workflows/ci-main.yml, change:
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Change image names to:
ghcr.io/${{ github.repository_owner }}/service-name
Option 3: Private Registry
Update workflows to use your registry URL:
registry: registry.example.com
Deployment Servers
Server Requirements
- OS: Ubuntu 20.04+ or Debian 11+
- RAM: 4GB minimum, 8GB recommended
- Storage: 50GB minimum, 100GB recommended
- CPU: 2 cores minimum, 4 cores recommended
Server Setup
1. Create Deploy User
# On server
sudo adduser deploy
sudo usermod -aG docker deploy
sudo su - deploy
2. Install Docker
# Update system
sudo apt update && sudo apt upgrade -y
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Install Docker Compose
sudo apt install docker-compose-plugin
# Verify installation
docker --version
docker compose version
3. Configure SSH Access
# On server, as deploy user
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Add GitHub Actions public key to authorized_keys
echo "ssh-ed25519 AAAAC3... github-actions-staging" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
4. Test SSH Access
# From your local machine
ssh -i ~/.ssh/github-actions-staging deploy@staging.manacore.app
# Should login without password prompt
5. Create Deployment Directories
# On server
mkdir -p ~/manacore-staging
mkdir -p ~/manacore-staging/logs
mkdir -p ~/manacore-staging/backups
# Or for production
mkdir -p ~/manacore-production
mkdir -p ~/manacore-production/logs
mkdir -p ~/manacore-production/backups
6. Configure Firewall
# Allow SSH
sudo ufw allow 22/tcp
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Allow specific service ports (optional, if not using reverse proxy)
sudo ufw allow 3001/tcp # Mana Core Auth
sudo ufw allow 3002/tcp # Maerchenzauber Backend
# Enable firewall
sudo ufw enable
7. Set Up Reverse Proxy (Optional)
If using Nginx as reverse proxy:
sudo apt install nginx
# Create configuration
sudo nano /etc/nginx/sites-available/manacore
server {
listen 80;
server_name api.manacore.app;
location /api/v1/ {
proxy_pass http://localhost:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /health {
proxy_pass http://localhost:3002;
proxy_set_header Host $host;
}
}
# Enable site
sudo ln -s /etc/nginx/sites-available/manacore /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
GitHub Environments
Create Environments
- Go to repository Settings > Environments
- Create two environments:
stagingproduction-approval
Configure Production Approval
- Go to
production-approvalenvironment - Add required reviewers
- Set wait timer (optional): 5 minutes
- Add environment secrets (if any differ from repository secrets)
Enable GitHub Actions
1. Check Workflow Permissions
- Go to Settings > Actions > General
- Scroll to "Workflow permissions"
- Select "Read and write permissions"
- Check "Allow GitHub Actions to create and approve pull requests"
- Click Save
2. Enable Workflows
Workflows are automatically enabled when files are pushed to .github/workflows/
3. Configure Branch Protection
- Go to Settings > Branches
- Add rule for
mainbranch:- ✅ Require status checks to pass
- Select:
All PR Checks Complete - ✅ Require branches to be up to date
- ✅ Require conversation resolution
- ✅ Do not allow bypassing
Test the Pipeline
1. Test PR Workflow
# Create test branch
git checkout -b test/ci-pipeline
# Make a small change
echo "# CI/CD Test" >> README.md
# Commit and push
git add README.md
git commit -m "test: verify CI pipeline"
git push origin test/ci-pipeline
# Create PR on GitHub
# Watch GitHub Actions tab for workflow execution
Expected Results:
- ✅ Detect changed files
- ✅ Format check passes
- ✅ Type check passes
- ✅ Build completes
- ✅ Tests run
2. Test Main Branch Workflow
# Merge the PR
# Watch GitHub Actions for:
Expected Results:
- ✅ Full validation passes
- ✅ Docker images built
- ✅ Images pushed to registry
- ✅ Staging deployment triggered
3. Test Staging Deployment
Check staging server:
ssh deploy@staging.manacore.app
cd ~/manacore-staging
docker compose ps
Expected Results:
- All services running
- Health checks passing
4. Test Production Deployment
- Go to Actions > CD - Production Deployment
- Click "Run workflow"
- Select:
- Service:
all - Environment:
production - Confirm:
deploy
- Service:
- Click "Run workflow"
- Approve when prompted
Expected Results:
- ✅ Backup created
- ✅ Deployment completes
- ✅ Health checks pass
Troubleshooting
Workflow Not Triggering
Issue: PR workflow doesn't run
Solution:
- Check workflow file syntax
- Verify branch protection rules
- Check repository permissions
Docker Build Fails
Issue: Image build fails in CI
Solution:
# Test build locally
docker buildx build --file apps/chat/apps/backend/Dockerfile .
# Check for syntax errors
yamllint .github/workflows/ci-main.yml
SSH Connection Fails
Issue: Can't connect to server from GitHub Actions
Solution:
- Verify SSH key is correct
- Check server firewall
- Verify user has docker permissions
# Test locally
ssh -i ~/.ssh/github-actions-staging deploy@staging.manacore.app 'docker ps'
Missing Secrets
Issue: Workflow fails with "secret not found"
Solution:
- Go to Settings > Secrets
- Verify secret name matches exactly
- Check for typos
- Ensure secret has value
Maintenance
Rotate SSH Keys
Every 90 days, rotate SSH keys:
# Generate new keys
ssh-keygen -t ed25519 -C "github-actions-$(date +%Y%m)" -f ~/.ssh/github-actions-new
# Add new public key to server
ssh deploy@staging.manacore.app
echo "ssh-ed25519 NEW_KEY..." >> ~/.ssh/authorized_keys
# Update GitHub secret with new private key
# Test new key works
# Remove old key from authorized_keys
Update Docker Credentials
Rotate Docker access tokens annually:
- Generate new token in Docker Hub
- Update
DOCKER_PASSWORDsecret - Test by triggering workflow
Monitor Workflow Usage
Check Actions usage:
- Go to Settings > Billing
- Review Actions minutes used
- Set spending limits if needed
Next Steps
- Read Deployment Guide
- Configure monitoring
- Set up alerts
- Document runbooks
- Train team on deployment process