server-ovh-prod-01-main/migrations/completed/landhometeam.md

6.1 KiB

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

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:

    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

ssh jared@15.204.247.153 "docker ps | grep landhometeam"

View Logs

ssh jared@15.204.247.153 "docker logs landhometeam_web --tail 50"

Update HTML Content

# 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

# 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

  • Deploy container to OVH server
  • Configure Traefik routing and SSL
  • Update DNS to point to 15.204.247.153
  • Configure Cloudflare proxy (SSL mode: Full)
  • Fix redirect loop issue
  • 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.