# LandHomeTeam.com Migration - COMPLETED **Migration Date**: 2025-10-08 **Status**: ✅ LIVE IN PRODUCTION **URL**: https://landhometeam.com ## Migration Summary Successfully migrated landhometeam.com from WordPress on DigitalOcean (ServerPilot) to a lightweight static "Coming Soon" page on OVHcloud VPS. This eliminates WordPress maintenance overhead, reduces attack surface, and allows decommissioning of the old server. ## Final Configuration ### Docker Services - **Web Container**: `landhometeam_web` (nginx:alpine) - **Reverse Proxy**: Traefik v3.0 (SSL via Let's Encrypt) - **CDN/Proxy**: Cloudflare (DDoS protection, global caching) ### Access Details - **Production URL**: https://landhometeam.com - **Server IP**: 15.204.247.153 - **Service Path**: `~/services/landhometeam/` - **Resources**: ~10-20MB RAM (minimal footprint) ### Architecture - Static HTML served from read-only volume mount - Automatic HTTP → HTTPS redirect via Traefik - Cloudflare proxy enabled (SSL mode: Full) - Both apex and www domains configured ## Key Learnings 1. **Traefik Middleware Requirement**: The `redirect-to-https@file` middleware must exist in `dynamic.yml` before being referenced in Docker labels - Added redirect-to-https middleware to Traefik's dynamic.yml - Without it, causes configuration errors or unexpected behavior 2. **Cloudflare Proxy Benefits**: Keep Cloudflare proxy enabled (orange cloud) for: - DDoS protection - Global CDN caching - Origin IP hiding - Free WAF and bot protection 3. **Cloudflare SSL Mode**: Must use "Full" or "Full (strict)" mode when proxying to HTTPS backend - "Flexible" mode causes redirect loops - Server uses Let's Encrypt via Traefik, Cloudflare proxies with its own cert 4. **DNS vs IP Testing**: Testing via direct IP with Host header (`curl -H "Host: domain.com" https://IP`) helps isolate DNS/proxy issues 5. **Static Site Simplicity**: No database, no PHP, no admin panel = zero maintenance and minimal security risk ## Deployment Files ### docker-compose.yml ```yaml services: nginx: image: nginx:alpine container_name: landhometeam_web restart: unless-stopped volumes: - ./html:/usr/share/nginx/html:ro networks: - traefik labels: - "traefik.enable=true" - "traefik.docker.network=traefik" # HTTP Router - redirect to HTTPS - "traefik.http.routers.landhometeam.rule=Host(`landhometeam.com`) || Host(`www.landhometeam.com`)" - "traefik.http.routers.landhometeam.entrypoints=web" - "traefik.http.routers.landhometeam.middlewares=redirect-to-https@file" # HTTPS Router - "traefik.http.routers.landhometeam-secure.rule=Host(`landhometeam.com`) || Host(`www.landhometeam.com`)" - "traefik.http.routers.landhometeam-secure.entrypoints=websecure" - "traefik.http.routers.landhometeam-secure.tls=true" - "traefik.http.routers.landhometeam-secure.tls.certresolver=letsencrypt" - "traefik.http.services.landhometeam.loadbalancer.server.port=80" networks: traefik: external: true ``` ### Traefik Dynamic Configuration Addition Added to `~/services/traefik/dynamic.yml`: ```yaml redirect-to-https: redirectScheme: scheme: https permanent: true ``` ## Troubleshooting: Redirect Loop **Problem**: Redirect loop error when accessing via Cloudflare proxy **Root Causes**: 1. Missing `redirect-to-https` middleware in Traefik's dynamic.yml 2. Cloudflare SSL mode potentially set to "Flexible" **Solution**: 1. Added redirect middleware to Traefik configuration 2. Set Cloudflare SSL/TLS mode to "Full" 3. Restarted Traefik: `cd ~/services/traefik && docker compose restart` ## Maintenance Commands ### View Container Status ```bash ssh jared@15.204.247.153 "docker ps | grep landhometeam" ``` ### View Logs ```bash ssh jared@15.204.247.153 "docker logs landhometeam_web --tail 50" ``` ### Update HTML Content ```bash # Edit locally nano deployments/landhometeam/html/index.html # Deploy changes scp deployments/landhometeam/html/index.html jared@15.204.247.153:~/services/landhometeam/html/ # No restart needed - changes are live immediately (Nginx serves from volume) ``` ### Container Management ```bash # Restart container ssh jared@15.204.247.153 "cd ~/services/landhometeam && docker compose restart" # Update Nginx image ssh jared@15.204.247.153 "cd ~/services/landhometeam && docker compose pull && docker compose up -d" # Stop/remove service ssh jared@15.204.247.153 "cd ~/services/landhometeam && docker compose down" ``` ## Migration Metrics - **Migration Time**: ~1 hour (including troubleshooting) - **Downtime**: Zero (DNS cutover to working site) - **Resource Usage**: 10-20MB RAM (vs ~200MB+ for WordPress) - **Monthly Savings**: ~$25+ (can decommission DigitalOcean server + ServerPilot) - **Annual Savings**: ~$300+ ## Post-Migration Tasks - [x] Deploy container to OVH server - [x] Configure Traefik routing and SSL - [x] Update DNS to point to 15.204.247.153 - [x] Configure Cloudflare proxy (SSL mode: Full) - [x] Fix redirect loop issue - [x] Verify site loads correctly - [ ] Monitor for 7 days - [ ] Export any remaining data from old server - [ ] Cancel ServerPilot subscription - [ ] Delete DigitalOcean droplet ## Security Benefits 1. **No Database**: No SQL injection risk 2. **No PHP/WordPress**: No plugin/theme vulnerabilities 3. **Read-Only Volume**: HTML served from read-only mount 4. **Minimal Attack Surface**: Just static HTML + Nginx 5. **Automatic SSL**: Traefik handles certificate renewal 6. **No Admin Panel**: Nothing to hack or brute force 7. **Cloudflare WAF**: Additional layer of DDoS/bot protection ## Future Expansion Options If site needs to be built out later: ### Option A: Add Contact Form - Use external service (Formspree, Basin, etc.) - No backend needed - services email form submissions ### Option B: Static Site Generator - Build with Astro, Hugo, or similar - Deploy to same `html/` directory - Keep same Docker/Traefik setup ### Option C: Full Application - Add backend container (Node.js, Python, etc.) - Connect to internal network - Still behind Traefik with same SSL/routing All options work with existing architecture - no major infrastructure changes needed.