# CMC Sales Deployment Guide with Caddy ## Overview This guide covers deploying the CMC Sales application to a Debian 12 VM using Caddy as the reverse proxy with automatic HTTPS. ## Architecture - **Production**: `https://cmc.springupsoftware.com` - **Staging**: `https://staging.cmc.springupsoftware.com` - **Reverse Proxy**: Caddy (running on host) - **Applications**: Docker containers - CakePHP legacy app - Go modern app - MariaDB database - **SSL**: Automatic via Caddy (Let's Encrypt) - **Authentication**: Basic auth configured in Caddy ## Prerequisites ### 1. Server Setup (Debian 12) ```bash # Update system sudo apt update && sudo apt upgrade -y # Install Docker sudo apt install -y docker.io docker-compose-plugin sudo systemctl enable docker sudo systemctl start docker # Add user to docker group sudo usermod -aG docker $USER # Log out and back in # Create directories sudo mkdir -p /var/backups/cmc-sales sudo chown $USER:$USER /var/backups/cmc-sales ``` ### 2. Install Caddy ```bash # Run the installation script sudo ./scripts/install-caddy.sh # Or manually install sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install caddy ``` ### 3. DNS Configuration Ensure DNS records point to your server: - `cmc.springupsoftware.com` → Server IP - `staging.cmc.springupsoftware.com` → Server IP ## Initial Deployment ### 1. Clone Repository ```bash cd /home/cmc git clone git@code.springupsoftware.com:cmc/cmc-sales.git cmc-sales sudo chown -R $USER:$USER cmc-sales cd cmc-sales ``` ### 2. Environment Configuration ```bash # Copy environment files cp .env.staging go-app/.env.staging cp .env.production go-app/.env.production # Edit with actual passwords nano .env.staging nano .env.production # Create credential directories mkdir -p credentials/staging credentials/production ``` ### 3. Setup Basic Authentication ```bash # Generate password hashes for Caddy ./scripts/setup-caddy-auth.sh # Or manually caddy hash-password # Copy the hash and update Caddyfile ``` ### 4. Configure Caddy ```bash # Copy Caddyfile sudo cp Caddyfile /etc/caddy/Caddyfile # Edit to update passwords and email sudo nano /etc/caddy/Caddyfile # Validate configuration caddy validate --config /etc/caddy/Caddyfile # Start Caddy sudo systemctl start caddy sudo systemctl status caddy ``` ### 5. Gmail OAuth Setup Same as before - set up OAuth credentials for each environment: - Staging: `credentials/staging/credentials.json` - Production: `credentials/production/credentials.json` ### 6. Database Initialization ```bash # Start database containers docker compose -f docker-compose.caddy-staging.yml up -d db-staging docker compose -f docker-compose.caddy-production.yml up -d db-production # Wait for databases sleep 30 # Restore production database (if you have a backup) ./scripts/restore-db.sh production /path/to/backup.sql.gz ``` ## Deployment Commands ### Starting Services ```bash # Start staging environment docker compose -f docker-compose.caddy-staging.yml up -d # Start production environment docker compose -f docker-compose.caddy-production.yml up -d # Reload Caddy configuration sudo systemctl reload caddy ``` ### Updating Applications ```bash # Pull latest code git pull origin main # Update staging docker compose -f docker-compose.caddy-staging.yml down docker compose -f docker-compose.caddy-staging.yml build --no-cache docker compose -f docker-compose.caddy-staging.yml up -d # Test staging, then update production docker compose -f docker-compose.caddy-production.yml down docker compose -f docker-compose.caddy-production.yml build --no-cache docker compose -f docker-compose.caddy-production.yml up -d ``` ## Caddy Management ### Configuration ```bash # Edit Caddyfile sudo nano /etc/caddy/Caddyfile # Validate configuration caddy validate --config /etc/caddy/Caddyfile # Reload configuration (zero downtime) sudo systemctl reload caddy ``` ### Monitoring ```bash # Check Caddy status sudo systemctl status caddy # View Caddy logs sudo journalctl -u caddy -f # View access logs sudo tail -f /var/log/caddy/cmc-production.log sudo tail -f /var/log/caddy/cmc-staging.log ``` ### SSL Certificates Caddy handles SSL automatically! To check certificates: ```bash # List certificates sudo ls -la /var/lib/caddy/.local/share/caddy/certificates/ # Force certificate renewal (rarely needed) sudo systemctl stop caddy sudo rm -rf /var/lib/caddy/.local/share/caddy/certificates/* sudo systemctl start caddy ``` ## Container Port Mapping | Service | Container Port | Host Port | Access | |---------|---------------|-----------|---------| | cmc-php-staging | 80 | 8091 | localhost only | | cmc-go-staging | 8080 | 8092 | localhost only | | cmc-db-staging | 3306 | 3307 | localhost only | | cmc-php-production | 80 | 8093 | localhost only | | cmc-go-production | 8080 | 8094 | localhost only | | cmc-db-production | 3306 | - | internal only | ## Monitoring and Maintenance ### Health Checks ```bash # Check all containers docker ps # Check application health curl -I https://cmc.springupsoftware.com curl -I https://staging.cmc.springupsoftware.com # Internal health checks (from server) curl http://localhost:8094/api/v1/health # Production Go curl http://localhost:8092/api/v1/health # Staging Go ``` ### Database Backups Same backup scripts work: ```bash # Manual backup ./scripts/backup-db.sh production ./scripts/backup-db.sh staging # Automated backups sudo crontab -e # Add: # 0 2 * * * /home/cmc/cmc-sales/scripts/backup-db.sh production # 0 3 * * * /home/cmc/cmc-sales/scripts/backup-db.sh staging ``` ## Security Benefits with Caddy 1. **Automatic HTTPS**: No manual certificate management 2. **Modern TLS**: Always up-to-date TLS configuration 3. **OCSP Stapling**: Enabled by default 4. **Security Headers**: Easy to configure 5. **Rate Limiting**: Built-in support ## Troubleshooting ### Caddy Issues ```bash # Check Caddy configuration caddy validate --config /etc/caddy/Caddyfile # Check Caddy service sudo systemctl status caddy sudo journalctl -u caddy -n 100 # Test reverse proxy curl -v http://localhost:8094/api/v1/health ``` ### Container Issues ```bash # Check container logs docker compose -f docker-compose.caddy-production.yml logs -f # Restart specific service docker compose -f docker-compose.caddy-production.yml restart cmc-go-production ``` ### SSL Issues ```bash # Caddy automatically handles SSL, but if issues arise: # 1. Check DNS is resolving correctly dig cmc.springupsoftware.com # 2. Check Caddy can reach Let's Encrypt sudo journalctl -u caddy | grep -i acme # 3. Ensure ports 80 and 443 are open sudo ufw status ``` ## Advantages of Caddy Setup 1. **Simpler Configuration**: Caddyfile is more readable than nginx 2. **Automatic HTTPS**: No certbot or lego needed 3. **Zero-Downtime Reloads**: Config changes without dropping connections 4. **Better Performance**: More efficient than nginx for this use case 5. **Native Rate Limiting**: Built-in without additional modules 6. **Automatic Certificate Renewal**: No cron jobs needed ## Migration from Nginx If migrating from the nginx setup: 1. Stop nginx containers: `docker compose -f docker-compose.proxy.yml down` 2. Install and configure Caddy 3. Start new containers with caddy compose files 4. Update DNS if needed 5. Monitor logs during transition ## File Structure ``` /home/cmc/cmc-sales/ ├── docker-compose.caddy-staging.yml ├── docker-compose.caddy-production.yml ├── Caddyfile ├── credentials/ │ ├── staging/ │ └── production/ ├── scripts/ │ ├── backup-db.sh │ ├── restore-db.sh │ ├── install-caddy.sh │ └── setup-caddy-auth.sh └── .env files /etc/caddy/ └── Caddyfile (deployed config) /var/log/caddy/ ├── cmc-production.log └── cmc-staging.log ```