# Production Deployment Guide This document outlines the changes made to prepare JMP Server for production deployment on a server. ## Key Changes Summary ### 1. **Removed Direct Port Exposures** - Removed direct port mappings for: - `homepage:3001` (was exposing internal port) - `bookstack:6875` (was exposing internal port) - `actual_server:5006` (was exposing internal port) - All services now route exclusively through Traefik reverse proxy - Only SSH port `2222` (Gitea) exposed directly for Git operations ### 2. **Resource Limits & Reservations** All containers now have CPU and memory limits: - **Traefik**: 2 CPU / 512M limit, 0.5 CPU / 256M reserved - **Gitea**: 2 CPU / 1G limit, 1 CPU / 512M reserved - **Gitea Runner**: 4 CPU / 2G limit (for CI/CD workloads) - **Bookstack**: 2 CPU / 512M limit, 1 CPU / 256M reserved - **Databases**: 2 CPU / 1G limit, 1 CPU / 512M reserved - **OpenCloud**: 4 CPU / 4G limit, 2 CPU / 2G reserved Adjust these based on your server's available resources. ### 3. **Health Checks** All services now include health checks: - **Databases**: `pg_isready` or `mysqladmin ping` checks - **Web services**: HTTP endpoint checks - Service dependencies now use `condition: service_healthy` instead of just `depends_on` This ensures proper startup ordering and service reliability. ### 4. **Log Rotation** Configured JSON file logging with rotation: - Max file size: 50-100MB per log file - Max files retained: 3-5 files - Prevents logs from filling disk ### 5. **Traefik Authentication** - **Before**: Had invalid placeholder `$$apr1$$...` - **After**: Uses environment variable `${TRAEFIK_BASICAUTH_USERS}` **Generate credentials:** ```bash openssl passwd -apr1 admin # Output: $apr1$r61.qW2G$Lc3uT7c5p... ``` Set in `.env`: ``` TRAEFIK_BASICAUTH_USERS=admin:$apr1$r61.qW2G$Lc3uT7c5p... ``` ### 6. **Database Restart Policies** - **Databases**: Changed to `restart: always` (critical services) - **Applications**: Keep `restart: unless-stopped` (graceful restart handling) ### 7. **OpenCloud Network Configuration** Fixed network issues for OpenCloud: - Explicitly declared `proxy_net` as external in opencloud-compose - Added network driver specification - Prevents network conflicts when deploying separately ### 8. **Container Dependencies** Updated all service dependencies to use health conditions: ```yaml depends_on: gitea-db: condition: service_healthy ``` This ensures services wait for databases to be healthy before starting. ### 9. **Actual Server Configuration** - Removed direct port exposure `5006:5006` - Fixed Traefik loadbalancer port (was `5232`, now `5006`) - Added to `proxy_net` network - Added health check ## Environment Variables ### Required Changes for Production Copy `.env.production.example` to `.env` and update: 1. **DOMAIN**: Your actual domain name 2. **TRAEFIK_BASICAUTH_USERS**: Generated htpasswd hash 3. **All database passwords**: Strong, random passwords 4. **API keys & tokens**: Generate new secure values 5. **OpenCloud settings**: Domain and admin password ### Sensitive Variables These should **never** be committed to git: - All `*PASSWORD*` variables - `*TOKEN*` variables - `*SECRET*` variables - `APP_KEY` values Keep `.env` in `.gitignore` and use `.env.production.example` as template. ## Pre-Deployment Checklist - [ ] Copy `.env.production.example` to `.env` - [ ] Generate Traefik basicauth credentials with `openssl passwd -apr1` - [ ] Set all database passwords (random, 16+ characters) - [ ] Generate API tokens (Gitea runner, Vaultwarden admin, etc.) - [ ] Configure domain in `.env` (DOMAIN variable) - [ ] Review resource limits for your server capacity - [ ] Ensure backup storage path is accessible (`./backups/`) - [ ] Verify SSL/TLS certificates will work (Let's Encrypt requirements) ## Deployment Steps 1. **Prepare server**: ```bash mkdir -p ~/jmp-server cd ~/jmp-server # Copy all files here ``` 2. **Configure environment**: ```bash cp .env.production.example .env # Edit .env with your values ``` 3. **Start services**: ```bash ./start.sh # or: docker compose up -d ``` 4. **Verify health**: ```bash docker compose ps # Check all services are "Up" and health checks pass docker compose logs -f traefik # Watch for ACME certificate provisioning ``` 5. **Test routing**: ```bash curl https://traefik.${DOMAIN}/ curl https://gitea.${DOMAIN}/ curl https://bookstack.${DOMAIN}/ ``` ## Monitoring & Maintenance ### View Service Status ```bash docker compose ps docker compose stats ``` ### Check Health ```bash docker compose exec gitea-db pg_isready -h localhost -U ${POSTGRES_USER_GITEA} docker compose exec bookstack-db mysqladmin ping -h localhost -u root -p${MYSQL_PASSWORD_BOOKSTACK} ``` ### View Logs ```bash # Traefik routing docker compose logs -f traefik # Gitea docker compose logs -f gitea # Backup status docker compose logs -f backup ``` ### Backup Management Backups are automated (see `backup.env`). Stored in `./backups/`. ## Security Considerations 1. **Firewall**: Only expose ports 80, 443, and 2222 (SSH) to internet 2. **HTTPS**: Let's Encrypt certificates auto-renewed by Traefik 3. **Database access**: Internal networks prevent direct DB access 4. **Secrets**: Never store passwords in compose files; use `.env` only 5. **Log retention**: Configure log rotation in Docker daemon or use central logging 6. **Backups**: Store backups on separate storage/cloud ## Troubleshooting ### Service won't start ```bash docker compose logs -f [service_name] # Check: Missing dependencies, failed health checks, port conflicts ``` ### Services can't communicate ```bash docker network ls docker network inspect proxy_net # Verify all services are on correct networks ``` ### Traefik routing issues ```bash docker compose exec traefik traefik api dashboard # Check router/service configurations ``` ### Memory/CPU pressure ```bash docker compose stats # Review resource limits in docker-compose.yaml # Adjust based on actual usage ``` ## Resource Recommendations For a typical small server (4GB RAM, 2 CPU): - **Gitea + Runner**: 3G RAM, 2.5 CPU - **OpenCloud**: 2G RAM, 2 CPU - **Other services**: 1G RAM, 1.5 CPU - **Total**: ~6G RAM recommended, 6 CPU recommended Adjust limits down if server is smaller, test under load for your workload. ## Next Steps 1. Configure OpenCloud separately if needed: `docker compose -f opencloud-compose/docker-compose.yml up -d` 2. Set up external backup storage for production data protection 3. Configure monitoring/alerting (optional external monitoring) 4. Document your domain names and admin credentials securely