# Extra Operations and Domain Changes **Audience**: DevOps Engineers, Infrastructure Team **Time to Complete**: Varies by operation **Prerequisites**: Completed guides 01-07 (full MaplePress deployment) --- ## Overview This guide covers additional operations and changes that you might need to perform on your production infrastructure: 1. **Domain Changes** - Changing backend domain (e.g., `getmaplepress.ca` → `getmaplepress.net`) - Changing frontend domain (e.g., `getmaplepress.com` → `getmaplepress.app`) 2. **SSL Certificate Management** 3. **Scaling Operations** 4. **Backup and Recovery** --- ## Table of Contents 1. [Change Backend Domain](#operation-1-change-backend-domain) 2. [Change Frontend Domain](#operation-2-change-frontend-domain) 3. [Change Both Domains](#operation-3-change-both-domains-at-once) 4. [Force SSL Certificate Renewal](#operation-4-force-ssl-certificate-renewal) 5. [Scale Backend Horizontally](#operation-5-scale-backend-horizontally) --- ## Operation 1: Change Backend Domain **Scenario:** Changing backend API domain from `getmaplepress.ca` → `getmaplepress.net` **Impact:** - ✅ Backend becomes available at new domain - ❌ Old domain stops working - ⚠️ Frontend needs CORS update to allow new backend domain - ⚠️ SSL certificate automatically obtained for new domain - ⚠️ Downtime: ~2-5 minutes during redeployment ### Step 1: DNS Configuration **First, point the new domain to worker-6:** 1. Log into your DNS provider (DigitalOcean, Cloudflare, etc.) 2. Create DNS A records for new domain: ``` Type: A Record Name: getmaplepress.net Value: TTL: 300 (5 minutes) Type: A Record Name: www.getmaplepress.net Value: TTL: 300 ``` 3. Wait for DNS propagation (5-60 minutes): ```bash # Test DNS from your local machine dig getmaplepress.net +short # Should show: dig www.getmaplepress.net +short # Should show: # Alternative test nslookup getmaplepress.net ``` ### Step 2: Update Backend Caddyfile **On manager node:** ```bash ssh dockeradmin@ cd ~/stacks/caddy-config # Backup old Caddyfile cp Caddyfile Caddyfile.backup.$(date +%Y%m%d) # Edit Caddyfile vi Caddyfile ``` **Change this:** ```caddy # OLD DOMAIN getmaplepress.ca www.getmaplepress.ca { reverse_proxy maplepress-backend:8000 { # ... config ... } } ``` **To this:** ```caddy # NEW DOMAIN getmaplepress.net www.getmaplepress.net { reverse_proxy maplepress-backend:8000 { header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} header_up X-Forwarded-Host {host} # IMPORTANT: Preserve Origin header for CORS header_up Origin {http.request.header.Origin} } log { output stdout format json level INFO } header { X-Frame-Options "SAMEORIGIN" X-Content-Type-Options "nosniff" X-XSS-Protection "1; mode=block" Strict-Transport-Security "max-age=31536000; includeSubDomains" Referrer-Policy "strict-origin-when-cross-origin" -Server } } ``` Save: `Esc`, `:wq`, `Enter` ### Step 3: Update CORS Configuration **Update the stack file to allow the frontend to call the new backend domain:** ```bash # Still on manager node cd ~/stacks vi maplepress-stack.yml ``` **Find this line:** ```yaml - SECURITY_CORS_ALLOWED_ORIGINS=https://getmaplepress.com,https://www.getmaplepress.com ``` **No change needed** - The CORS config is for what origins can call the backend, not the backend's domain itself. The frontend (`getmaplepress.com`) will now call `getmaplepress.net` instead of `getmaplepress.ca`. ### Step 4: Redeploy Backend Stack ```bash # Remove old stack docker stack rm maplepress sleep 10 # Remove old config (contains old domain) docker config rm maplepress_caddyfile # Deploy with new domain docker stack deploy -c maplepress-stack.yml maplepress # Watch services come up docker service ps maplepress_backend docker service ps maplepress_backend-caddy ``` ### Step 5: Verify SSL Certificate **Caddy will automatically obtain SSL certificates for the new domain:** ```bash # Watch Caddy logs for certificate acquisition docker service logs -f maplepress_backend-caddy # You should see logs like: # "certificate obtained successfully" # "serving https://getmaplepress.net" ``` **Test from local machine:** ```bash # Test new domain with HTTPS curl -I https://getmaplepress.net/health # Should return: HTTP/2 200 # Verify SSL certificate curl -vI https://getmaplepress.net/health 2>&1 | grep "subject:" # Should show: subject: CN=getmaplepress.net # Test CORS curl -v -H "Origin: https://getmaplepress.com" https://getmaplepress.net/health 2>&1 | grep "access-control-allow-origin" # Should show: access-control-allow-origin: https://getmaplepress.com ``` ### Step 6: Update Frontend to Use New Backend Domain **On your local machine:** ```bash cd ~/go/src/codeberg.org/mapleopentech/monorepo/web/maplepress-frontend # Update production environment file vi .env.production ``` **Change:** ```bash # OLD VITE_API_BASE_URL=https://getmaplepress.ca # NEW VITE_API_BASE_URL=https://getmaplepress.net ``` **Rebuild and redeploy frontend:** ```bash # Build with new backend URL npm run build # Verify the new URL is in the build grep -r "getmaplepress.net" dist/assets/*.js | head -2 # Should show: getmaplepress.net # SSH to worker-7 and update the frontend build ssh dockeradmin@ cd /var/www/monorepo/web/maplepress-frontend # Pull latest code git pull origin main # Rebuild npm run build # Verify symlink ls -la /var/www/maplepress-frontend # Should point to: /var/www/monorepo/web/maplepress-frontend/dist exit ``` ### Step 7: Test End-to-End ```bash # Visit frontend in browser open https://getmaplepress.com # Open DevTools (F12) → Network tab # Verify API calls now go to: https://getmaplepress.net # Verify status: 200 (not 0 or CORS errors) ``` ### Step 8: (Optional) Keep Old Domain Working If you want both domains to work temporarily: ```bash # Edit Caddyfile to include BOTH domains vi ~/stacks/caddy-config/Caddyfile ``` ```caddy # Support both old and new domains getmaplepress.ca www.getmaplepress.ca, getmaplepress.net www.getmaplepress.net { reverse_proxy maplepress-backend:8000 { # ... same config ... } } ``` Then redeploy as in Step 4. ### Rollback Procedure If something goes wrong: ```bash # 1. Restore old Caddyfile cd ~/stacks/caddy-config cp Caddyfile.backup.YYYYMMDD Caddyfile # 2. Redeploy cd ~/stacks docker stack rm maplepress sleep 10 docker config rm maplepress_caddyfile docker stack deploy -c maplepress-stack.yml maplepress # 3. Restore frontend .env.production cd ~/go/src/codeberg.org/mapleopentech/monorepo/web/maplepress-frontend # Change back to: VITE_API_BASE_URL=https://getmaplepress.ca # Rebuild and redeploy ``` **✅ Backend domain change complete!** --- ## Operation 2: Change Frontend Domain **Scenario:** Changing frontend domain from `getmaplepress.com` → `getmaplepress.app` **Impact:** - ✅ Frontend becomes available at new domain - ❌ Old domain stops working - ⚠️ Backend CORS needs update to allow new frontend domain - ⚠️ SSL certificate automatically obtained for new domain - ⚠️ Downtime: ~2-5 minutes during redeployment ### Step 1: DNS Configuration **Point the new domain to worker-7:** ``` Type: A Record Name: getmaplepress.app Value: TTL: 300 Type: A Record Name: www.getmaplepress.app Value: TTL: 300 ``` **Test DNS propagation:** ```bash dig getmaplepress.app +short # Should show: nslookup getmaplepress.app ``` ### Step 2: Update Frontend Caddyfile **On manager node:** ```bash ssh dockeradmin@ cd ~/stacks/maplepress-frontend-caddy-config # Backup cp Caddyfile Caddyfile.backup.$(date +%Y%m%d) # Edit vi Caddyfile ``` **Change this:** ```caddy # OLD DOMAIN getmaplepress.com www.getmaplepress.com { root * /var/www/maplepress-frontend # ... config ... } ``` **To this:** ```caddy # NEW DOMAIN getmaplepress.app www.getmaplepress.app { root * /var/www/maplepress-frontend file_server try_files {path} /index.html encode gzip log { output stdout format json level INFO } header { X-Frame-Options "SAMEORIGIN" X-Content-Type-Options "nosniff" X-XSS-Protection "1; mode=block" Strict-Transport-Security "max-age=31536000; includeSubDomains" Referrer-Policy "strict-origin-when-cross-origin" -Server } @static { path *.js *.css *.png *.jpg *.jpeg *.gif *.svg *.woff *.woff2 *.ttf *.eot *.ico } header @static Cache-Control "public, max-age=31536000, immutable" } ``` Save: `Esc`, `:wq`, `Enter` ### Step 3: Update Backend CORS Configuration **CRITICAL:** The backend needs to allow the new frontend domain: ```bash cd ~/stacks vi maplepress-stack.yml ``` **Find this line:** ```yaml - SECURITY_CORS_ALLOWED_ORIGINS=https://getmaplepress.com,https://www.getmaplepress.com ``` **Change to:** ```yaml - SECURITY_CORS_ALLOWED_ORIGINS=https://getmaplepress.app,https://www.getmaplepress.app ``` **If you want to support BOTH old and new domains temporarily:** ```yaml - SECURITY_CORS_ALLOWED_ORIGINS=https://getmaplepress.com,https://www.getmaplepress.com,https://getmaplepress.app,https://www.getmaplepress.app ``` ### Step 4: Redeploy Backend (for CORS update) ```bash # Backend CORS config changed, must redeploy docker stack rm maplepress sleep 10 docker config rm maplepress_caddyfile docker stack deploy -c maplepress-stack.yml maplepress # Verify backend running docker service ps maplepress_backend ``` ### Step 5: Redeploy Frontend ```bash # Remove frontend stack docker stack rm maplepress-frontend sleep 10 docker config rm maplepress-frontend_caddyfile # Deploy with new domain docker stack deploy -c maplepress-frontend-stack.yml maplepress-frontend # Watch it come up docker service ps maplepress-frontend_caddy ``` ### Step 6: Verify SSL Certificate **Test from local machine:** ```bash # Test new frontend domain curl -I https://getmaplepress.app # Should return: HTTP/2 200 # Verify SSL certificate curl -vI https://getmaplepress.app 2>&1 | grep "subject:" # Should show: subject: CN=getmaplepress.app ``` ### Step 7: Test CORS from New Frontend ```bash # Visit new frontend in browser open https://getmaplepress.app # Open DevTools (F12) # Network tab: Verify API calls succeed # Console tab: Should be NO CORS errors ``` ### Step 8: Verify Backend Accepts New Origin ```bash # Test CORS from backend perspective curl -v -H "Origin: https://getmaplepress.app" https://getmaplepress.ca/health 2>&1 | grep "access-control-allow-origin" # Should show: access-control-allow-origin: https://getmaplepress.app ``` ### Rollback Procedure ```bash # 1. Restore old frontend Caddyfile cd ~/stacks/maplepress-frontend-caddy-config cp Caddyfile.backup.YYYYMMDD Caddyfile # 2. Restore old backend CORS config cd ~/stacks vi maplepress-stack.yml # Change back to: https://getmaplepress.com,https://www.getmaplepress.com # 3. Redeploy both docker stack rm maplepress docker stack rm maplepress-frontend sleep 10 docker config rm maplepress_caddyfile docker config rm maplepress-frontend_caddyfile docker stack deploy -c maplepress-stack.yml maplepress docker stack deploy -c maplepress-frontend-stack.yml maplepress-frontend ``` **✅ Frontend domain change complete!** --- ## Operation 3: Change Both Domains at Once **Scenario:** Changing both domains simultaneously: - Backend: `getmaplepress.ca` → `api.maplepress.io` - Frontend: `getmaplepress.com` → `app.maplepress.io` **Benefits:** - Single maintenance window - Coordinated cutover - Clean brand migration **Downtime:** ~5-10 minutes ### Complete Process ```bash # ============================================================================== # STEP 1: DNS Configuration (Do this first, wait for propagation) # ============================================================================== # Backend DNS: # A Record: api.maplepress.io → # A Record: www.api.maplepress.io → # Frontend DNS: # A Record: app.maplepress.io → # A Record: www.app.maplepress.io → # Test DNS dig api.maplepress.io +short # Should show worker-6 IP dig app.maplepress.io +short # Should show worker-7 IP # ============================================================================== # STEP 2: Update Backend Caddyfile # ============================================================================== ssh dockeradmin@ cd ~/stacks/caddy-config cp Caddyfile Caddyfile.backup.$(date +%Y%m%d) vi Caddyfile # Change domain from getmaplepress.ca to api.maplepress.io # (Keep all other config the same) # ============================================================================== # STEP 3: Update Frontend Caddyfile # ============================================================================== cd ~/stacks/maplepress-frontend-caddy-config cp Caddyfile Caddyfile.backup.$(date +%Y%m%d) vi Caddyfile # Change domain from getmaplepress.com to app.maplepress.io # (Keep all other config the same) # ============================================================================== # STEP 4: Update Backend CORS for New Frontend Domain # ============================================================================== cd ~/stacks vi maplepress-stack.yml # Change: # - SECURITY_CORS_ALLOWED_ORIGINS=https://app.maplepress.io,https://www.app.maplepress.io # ============================================================================== # STEP 5: Update Frontend .env.production for New Backend # ============================================================================== ssh dockeradmin@ cd /var/www/monorepo/web/maplepress-frontend vi .env.production # Change: # VITE_API_BASE_URL=https://api.maplepress.io # Rebuild npm run build # Verify new URL in build grep -r "api.maplepress.io" dist/assets/*.js | head -2 exit # ============================================================================== # STEP 6: Coordinated Deployment (Back on Manager) # ============================================================================== ssh dockeradmin@ cd ~/stacks # Remove both stacks docker stack rm maplepress docker stack rm maplepress-frontend sleep 10 # Remove configs docker config rm maplepress_caddyfile docker config rm maplepress-frontend_caddyfile # Deploy both stacks docker stack deploy -c maplepress-stack.yml maplepress docker stack deploy -c maplepress-frontend-stack.yml maplepress-frontend # ============================================================================== # STEP 7: Verify Both Services # ============================================================================== docker service ls | grep maplepress # Should show 3 services all 1/1: # maplepress_backend # maplepress_backend-caddy # maplepress-frontend_caddy # ============================================================================== # STEP 8: Test End-to-End (Local Machine) # ============================================================================== # Test backend curl -I https://api.maplepress.io/health # Should return: HTTP/2 200 # Test frontend curl -I https://app.maplepress.io # Should return: HTTP/2 200 # Test CORS curl -v -H "Origin: https://app.maplepress.io" https://api.maplepress.io/health 2>&1 | grep "access-control" # Should show: access-control-allow-origin: https://app.maplepress.io # Test in browser open https://app.maplepress.io # DevTools → Network: Verify calls to api.maplepress.io succeed ``` **✅ Both domain changes complete!** --- ## Operation 4: Force SSL Certificate Renewal **Scenario:** You need to manually renew SSL certificates (rarely needed - Caddy auto-renews) ### When You Might Need This - Testing certificate renewal process - Certificate was revoked - Manual intervention required after failed auto-renewal ### Backend Certificate Renewal ```bash # SSH to worker-6 ssh dockeradmin@ # Get Caddy container ID docker ps | grep maplepress_backend-caddy # Access Caddy container docker exec -it sh # Inside container - force certificate renewal caddy reload --config /etc/caddy/Caddyfile --force # Or restart Caddy to trigger renewal exit # Back on worker-6 docker service update --force maplepress_backend-caddy # Watch logs for certificate acquisition docker service logs -f maplepress_backend-caddy | grep -i certificate ``` ### Frontend Certificate Renewal ```bash # SSH to worker-7 ssh dockeradmin@ # Get Caddy container ID docker ps | grep maplepress-frontend # Force reload docker exec caddy reload --config /etc/caddy/Caddyfile --force # Or force restart exit docker service update --force maplepress-frontend_caddy # Watch logs docker service logs -f maplepress-frontend_caddy | grep -i certificate ``` ### Verify New Certificate ```bash # From local machine openssl s_client -connect getmaplepress.ca:443 -servername getmaplepress.ca < /dev/null 2>/dev/null | openssl x509 -noout -dates # Should show: # notBefore=Nov 5 12:00:00 2025 GMT # notAfter=Feb 3 12:00:00 2026 GMT ``` --- ## Operation 5: Scale Backend Horizontally **Scenario:** Your backend needs to handle more traffic - add more replicas ### Considerations - Each replica needs database connections - Cassandra can handle the load (QUORUM with 3 nodes) - Redis connections are pooled - Stateless design allows easy horizontal scaling ### Scale to 3 Replicas ```bash # On manager node cd ~/stacks vi maplepress-stack.yml # Find backend service, change replicas # FROM: # deploy: # replicas: 1 # TO: # deploy: # replicas: 3 # Redeploy docker stack deploy -c maplepress-stack.yml maplepress # Watch replicas come up watch docker service ps maplepress_backend # Press Ctrl+C when all show Running # Verify all healthy docker service ps maplepress_backend --filter "desired-state=running" # Should show 3 replicas ``` ### Load Balancing Caddy automatically load balances between replicas: ```bash # Test load balancing for i in {1..10}; do curl -s https://getmaplepress.ca/health sleep 1 done # Check which replicas handled requests docker service logs maplepress_backend | grep "GET /health" | tail -20 # You should see different container IDs handling requests ``` ### Scale Back Down ```bash # Edit stack file vi ~/stacks/maplepress-stack.yml # Change back to replicas: 1 # Redeploy docker stack deploy -c maplepress-stack.yml maplepress # Verify docker service ps maplepress_backend # Should show only 1 replica running, others Shutdown ``` --- ## Quick Reference: Domain Change Checklist ### Backend Domain Change - [ ] Update DNS A records (point new domain to worker-6) - [ ] Wait for DNS propagation (5-60 minutes) - [ ] Backup Caddyfile: `cp Caddyfile Caddyfile.backup.$(date +%Y%m%d)` - [ ] Update backend Caddyfile with new domain - [ ] Redeploy backend stack - [ ] Verify SSL certificate obtained for new domain - [ ] Update frontend `.env.production` with new backend URL - [ ] Rebuild and redeploy frontend - [ ] Test CORS end-to-end ### Frontend Domain Change - [ ] Update DNS A records (point new domain to worker-7) - [ ] Wait for DNS propagation - [ ] Backup frontend Caddyfile - [ ] Update frontend Caddyfile with new domain - [ ] **Update backend CORS** in `maplepress-stack.yml` - [ ] Redeploy backend (for CORS) - [ ] Redeploy frontend stack - [ ] Verify SSL certificate - [ ] Test in browser (no CORS errors) --- ## Troubleshooting Domain Changes ### Problem: SSL Certificate Not Obtained **Symptom:** After domain change, HTTPS doesn't work ```bash # Check Caddy logs docker service logs maplepress_backend-caddy --tail 100 | grep -i "acme\|certificate" # Common issues: # 1. DNS not propagated - wait longer # 2. Port 80 not accessible - check firewall # 3. Let's Encrypt rate limit - wait 1 hour ``` **Fix:** ```bash # Verify DNS resolves dig +short # Must show correct worker IP # Verify port 80 accessible curl http:// # Should redirect to HTTPS # If rate limited, wait and retry # Let's Encrypt limit: 5 certificates per domain per week ``` ### Problem: CORS Errors After Domain Change **Symptom:** Frontend shows CORS errors in browser console **Cause:** Forgot to update backend CORS configuration **Fix:** ```bash # Check backend CORS config cat ~/stacks/maplepress-stack.yml | grep CORS # Should include NEW frontend domain # Update if needed vi ~/stacks/maplepress-stack.yml # Add new frontend domain to SECURITY_CORS_ALLOWED_ORIGINS # Redeploy backend docker stack rm maplepress sleep 10 docker config rm maplepress_caddyfile docker stack deploy -c maplepress-stack.yml maplepress # Test CORS curl -v -H "Origin: https://" https:///health 2>&1 | grep "access-control" ``` ### Problem: Old Domain Still Works **Symptom:** Both old and new domains work **Cause:** Caddyfile includes both domains **Expected Behavior:** This is fine during migration - you can support both **To Remove Old Domain:** ```bash # Edit Caddyfile and remove old domain vi ~/stacks/caddy-config/Caddyfile # Remove old domain from the domain list # Redeploy docker stack rm maplepress sleep 10 docker config rm maplepress_caddyfile docker stack deploy -c maplepress-stack.yml maplepress ``` --- **Last Updated**: November 2025 **Maintained By**: Infrastructure Team