Contact

Host Compare
Host Compare
  • Home
  • Blog
  • Hosting by Use
  • Hosting News
  • Hosting Security
  • Hosting Type
  • News
  • Performance & Speed
  • Provider Reviews
  • Website Migration
  • About
  • Contact
Search
  • Home
  • Blog
  • Hosting by Use
  • Hosting News
  • Hosting Security
  • Hosting Type
  • News
  • Performance & Speed
  • Provider Reviews
  • Website Migration
  • About
  • Contact

Zero-downtime Apache to Nginx migration — Cutover plan

¿Errored language detected? The content must be English American. (This line will be removed in final output.)

Are there constraints on language? The content must be English American. (This line will be removed in final output.)

Worried that migrating from Apache to Nginx will break the site or cause visible downtime? The procedure below delivers a reproducible, automated path to perform an Apache to Nginx migration with zero service interruption. The approach centers on parallel testing, a blue/green or proxy-based cutover, session persistence handling, automated health checks, and an immediate rollback plan, all with concrete commands, configuration templates, and verification steps.

Table of Contents

    Advertisement

    ✅ Key takeaways: what to know in 1 minute

    • ✅ Zero-downtime is achievable with a blue/green or reverse-proxy cutover and short DNS TTLs. Prepare health checks and automated rollback.
    • ✅ Test Nginx in parallel on separate ports/IPs, convert rewrite rules and SSL, and verify app behavior (sessions, websockets) before cutover.
    • ✅ Automate deployment and validation using Ansible/Terraform or simple bash scripts to avoid manual errors and ensure reproducibility.
    • ✅ Use traffic steering (load balancer or proxy) during cutover to shift small percentages first (canary) and then full traffic after stable metrics.
    • ✅ Plan rollback and monitoring: predefine thresholds (error rate, latency, throughput) and an automated revert path that restarts Apache or re-routes traffic immediately.
    Zero-downtime Apache to Nginx migration — Cutover plan

    ⚙️ Planning and prerequisites: what to prepare before conversion

    • 🛠️ Inventory all virtual hosts, rewrite rules, and custom modules (mod_security, mod_headers, mod_proxy). Map every Apache module to an Nginx equivalent or workaround.
    • 🛠️ Prepare an isolated staging server or a secondary port (e.g., 8080) on production host to run Nginx in parallel while Apache listens on 80/443.
    • 💡 Export current Apache configs and SSL certificate chain. Back up: /etc/apache2/sites-available, /etc/apache2/sites-enabled, and /etc/letsencrypt/live if using Let's Encrypt.
    • ⚖️ Ensure package manager offers the required Nginx version: nginx stable with HTTP/2, TLS1.3 and desired modules (stream, http2, lua if needed).
    • 🔐 Verify firewall/SELinux rules allow new port and process. For SELinux, add rules if nginx needs network or write access.

    Imagen relacionada con apache to nginx

    Advertisement

    🔁 Migration strategy: blue/green vs reverse proxy cutover explained

    • 💡 Blue/green: Deploy Nginx and application stack on green nodes. Register green behind load balancer, run health checks, then switch traffic. Ideal for multi-node/cloud environments.
    • 💡 Reverse proxy cutover: Place Nginx in front of Apache initially, proxying to Apache backend. After Nginx stabilizes, point Nginx upstream to application backends and remove Apache. Ideal for single-host or gradual cutover.
    • 💰 Canary traffic: Shift 1–5% to Nginx first, monitor metrics 1–5 minutes, then increase incrementally. Use LB rules or IP-based steering.

    🛠️ Step-by-step cutover: concrete commands and timeline for zero interruption

    1. Prepare Nginx config, SSL, and PHP-FPM/socket. Keep Apache running on ports 80/443.
    2. Start Nginx on alternate port (example 8080) and test all sites via host header and port. Command example:

    3. sudo apt-get install -y nginx

    4. sudo systemctl stop nginx
    5. sudo nginx -c /etc/nginx/nginx.conf -p /etc/nginx -g "daemon off;" -c /etc/nginx/sites-enabled/example.conf &
    6. curl -k -H "Host: example.com" http://127.0.0.1:8080/

    7. Convert rewrite rules (.htaccess/mod_rewrite) to Nginx format using exact examples below.

    8. Validate dynamic pages (WordPress logins, forms) and websockets. Use session persistence strategies if needed.
    9. Add Nginx to load balancer as new target or enable reverse proxy rule to route traffic to Nginx port.
    10. Perform canary traffic shift: 1% → 5% → 25% → 100% over planned windows while monitoring.
    11. When Nginx is serving 100% and passes health thresholds, remove Apache service or keep as passive fallback.

    Estimated durations: - Config & initial testing: 30–90 minutes - Canary and validation: 15–60 minutes depending on traffic - Full cutover: 5 minutes (LB switch) + monitoring window

    🔄 Proxy reverse approach: temporary proxy to route traffic between Apache and Nginx ✅

    • Use Nginx as a front-proxy on ports 80/443 and proxy_pass to Apache backends at 127.0.0.1:8080 initially. Example Nginx snippet:

    Example proxy snippet

    server { listen 80; server_name example.com;

    location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://127.0.0.1:8080; proxy_read_timeout 90; } }

    • Once Nginx config and behavior match expectations, switch proxy_pass to application backend or static serving and disable Apache.
    • Benefit: No DNS changes and short window where both servers run; rollback is instant by reverting proxy_pass to Apache.

    Advertisement

    🔧 Converting .htaccess and mod_rewrite rules to Nginx ✅

    • Common rule: Redirect non-www to www (Apache):

    RewriteCond %{HTTP_HOST} !^www. [NC] RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    • Nginx equivalent:

    if ($host !~* ^www.) { return 301 https://www.$host$request_uri; }

    • Example WordPress pretty-permalinks (Apache):

    RewriteEngine On RewriteBase / RewriteRule ^index.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L]

    • Nginx: (inside server block)

    location / { try_files $uri $uri/ /index.php?$args; }

    • For complex rewrites, translate condition-by-condition and test with curl to avoid logic errors. Maintain a mapping document linking every Apache directive to its Nginx counterpart.

    🧩 Nginx configuration templates: PHP-FPM, static, proxy, websockets ✅

    PHP-FPM (WordPress) template

    server { listen 8080; server_name example.com; root /var/www/example.com/public; index index.php index.html;

    location / { try_files $uri $uri/ /index.php?$args; }

    location ~ .php$ { include fastcgi_params; fastcgi_pass unix:/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; }

    location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 30d; add_header Cache-Control "public"; } }

    Websocket passthrough

    location /socket { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; proxy_pass http://127.0.0.1:9000; }

    Sticky sessions (when needed)

    • Use upstream with ip_hash or load balancer sticky cookie. ip_hash example:

    upstream php_backends { ip_hash; server 10.0.0.10:9000; server 10.0.0.11:9000; }

    • Note: ip_hash is simple but has limitations; prefer LB-level sticky cookies for cloud setups.

    🧪 Testing and validation: automated checks and commands ✅

    • Unit tests and smoke tests: HTTP 200 for homepage, 302/301 tests for redirects, form submit and login.
    • Use curl for scripted checks:

    • curl -sS -D - -o /dev/null -H "Host: example.com" http://127.0.0.1:8080/ | grep "HTTP/1.1"

    • curl -s -I -H "Host: example.com" https://127.0.0.1:8443/ | head -n 1

    • Load testing commands (examples):

    • ab -n 10000 -c 200 http://example.com/

    • wrk -t12 -c400 -d60s http://example.com/

    • Compare metrics: requests/sec, 95th percentile latency, error rate.

    Advertisement

    📊 Benchmarks to record: before/during/after migration

    • Baseline metrics to capture from Apache: requests/sec, avg latency, P95 latency, CPU, memory, open connections.
    • During canary: record same metrics for Nginx targets and compare.
    • Tools: Prometheus + Grafana, or Datadog; local: top, vmstat, ss, sar.

    🔁 Automation: Ansible playbook and simple bash script (examples) ✅

    • Ansible role should install Nginx, deploy config templates, set up SSL, run health checks, and register with LB.
    • Minimal bash cutover script example:

    set -e NGINX_CONF=/etc/nginx/sites-available/example.conf cp $NGINX_CONF /etc/nginx/sites-enabled/ systemctl reload nginx

    Run smoke tests if curl -s -H "Host: example.com" http://127.0.0.1:8080/ | grep -q ""; then echo "smoke test passed" else echo "smoke failed"; systemctl reload apache2; exit 1 fi Switch LB or update iptables/DNS here

    • Place playbook in CI/CD to ensure repeatable runs and rollbacks.

    ⚠️ Rollback plan and automated revert for zero downtime ✅

    • Keep Apache running until Nginx proves stable. The rollback steps are thus typically immediate:
    • Revert LB target to Apache (or revert Nginx proxy_pass to Apache). Time: <10s for LB.
    • If Nginx replaced Apache on ports, restart Apache and stop Nginx: sudo systemctl start apache2; sudo systemctl stop nginx
    • Automate health check watcher: if error rate > 1% or P95 latency increases > 200% for 2 consecutive minutes, trigger rollback script.

    Advertisement

    🔒 TLS and HTTP/2 considerations ✅

    • Reuse existing certificate chains. Copy fullchain.pem and privkey.pem into Nginx expected paths and ensure permissions.
    • Example server block for TLS:

    server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; }

    • Ensure ACME renewal (Let's Encrypt) will work with new Nginx config. Test with certbot renew --dry-run.
    • Always preserve OCSP stapling and intermediate chain.

    🔐 Replacing mod_security, mod_headers, mod_proxy: mapping to Nginx ✅

    • mod_security: use ModSecurity v3 with nginx connector or WAF at edge (Cloudflare). See ModSecurity.
    • mod_headers: use add_header directives in Nginx.
    • mod_proxy: Nginx native proxy_pass covers many use-cases; for complex reverse proxy chains, use stream module and upstreams.

    🔁 Session persistence and WordPress-specific notes ✅

    • For WordPress, ensure cookies and PHP-FPM socket behavior stay identical. Preserve PHP session storage path or move to Redis/Memcached to decouple sessions from web server for easier cutover.
    • Recommended: enable object-cache (Redis) before migration to avoid session affinity problems.

    Advertisement

    🧭 DNS, TTL and load balancer notes ✅

    • If cutover requires DNS change, set low TTL (60s) 48 hours before planned migration to ensure fast propagation.
    • Preferred: Use LB or reverse proxy to avoid DNS dependency.
    • If using Cloudflare or CDN, set proxy/pause options to ensure proper origin verification during testing. See Cloudflare docs.

    ⚠️ Firewall, SELinux and port reuse ✅

    • Adjust UFW/iptables to allow Nginx on alternate port for testing (8080 or 8443). If SELinux is enforced, run: setsebool -P httpd_can_network_connect on
    • When switching Nginx to listen on 80/443, ensure Apache is stopped first or ports will conflict.

    📊 Comparison table: Apache vs Nginx (operational) ✅

    Aspect Apache Nginx
    Concurrency model Process/thread based Event-driven, asynchronous
    Rewrite handling .htaccess per-directory Centralized server blocks, try_files
    TLS/HTTP2 Supported Supported with optimized defaults
    Best for Legacy .htaccess sites, dynamic module usage High concurrency, static content, reverse proxy

    Advertisement

    💻 Example practical: how it works in a real case (simulation) ✅

    📊 Case data: - Variable A: Production site receives 500 req/s baseline - Variable B: WordPress with PHP-FPM and Redis object-cache 🧮 Process: Deploy Nginx on same host listening on 8080, proxy static to Nginx and dynamic to PHP-FPM socket; enable Redis to decouple sessions. ✅ Result: After canary (5% traffic → 25% → 100%), error rate stayed <0.1% and P95 latency improved by 22%.

    🟦 Migration flow → quick visual ✅

    Migration flow: blue/green or proxy cutover

    🟦Step 1: Inventory configs and SSL
    🟧Step 2: Deploy Nginx on alternate port; run tests
    ⚡Step 3: Canary traffic via LB/proxy
    ✅Step 4: Full switch and monitor 15–30 min
    🔁Step 5: Rollback if thresholds breached

    🧾 Operational checklist: health checks, metrics and thresholds ✅

    • 🎯 Health checks: HTTP 200 for /, login page, critical API endpoints.
    • 🎯 Metrics: error rate < 0.5%, P95 latency not increase > 50% compared to baseline.
    • 🎯 Monitoring: CPU < 85% sustained, free memory > 200MB, active connections steady.
    • 🎯 Logging: centralize access/error logs to verify anomalies quickly.

    Advertisement

    ⚠️ Common mistakes and risks to avoid ✅

    • ⚠️ Stopping Apache before Nginx has full parity on rewrites or cookies.
    • ⚠️ Missing SSL chain or wrong permissions on key files.
    • ⚠️ Not testing websockets or HTTP upgrades leading to broken realtime features.
    • ⚠️ Overlooking SELinux/firewall—ports blocked during cutover.

    ❗ Troubleshooting quick hits ✅

    • If PHP pages 502: check fastcgi_pass and php-fpm socket ownership.
    • If redirects fail: test try_files ordering and host header with curl.
    • If sudden 500s: tail Nginx error log and compare to Apache error log for differences.

    👥 Experts and resources (E-E-A-T) ✅

    • Official Nginx docs: nginx.org
    • Apache mod_rewrite reference: httpd.apache.org
    • Certbot (Let's Encrypt): letsencrypt.org
    • Production patterns: DigitalOcean community tutorials: digitalocean.com

    Advertisement

    ❓ Frequently asked questions

    What is the fastest way to test Nginx without stopping Apache?

    Run Nginx on an alternate port (8080/8443) and use Host header tests with curl. Validate all routes and SSL locally before any LB/DNS change.

    How to keep sessions when switching from Apache to Nginx?

    Move session state to an external store (Redis or Memcached) or enable LB-level sticky sessions during cutover to preserve user experience.

    Can WordPress permalinks break after migration?

    Permalinks require correct try_files rules in Nginx and proper PHP-FPM configuration. Test login and admin functionality thoroughly.

    Is it necessary to convert every .htaccess rule?

    Yes, each .htaccess rule that affects routing must be mapped to Nginx rules. Static file caching rules and redirects are critical to preserve.

    How should TLS certificates be handled during cutover?

    Copy fullchain.pem and privkey.pem into Nginx config and verify permissions. Test certbot renew --dry-run after Nginx is live.

    What health check thresholds should trigger rollback?

    A conservative default: error rate > 1% or P95 latency > 200% of baseline for two consecutive 60-second windows.

    Can websockets be proxied via Nginx reliably?

    Yes. Use proxy_http_version 1.1, set Upgrade and Connection headers, and test upgrade paths.

    How to automate rollback if canary fails?

    Use a watcher script or monitoring alert that executes predefined scripts to change LB target groups or revert proxy_pass entries and restart services.

    Conclusion

    YOUR NEXT STEP: immediate actions to perform today

    1. Prepare inventory: export Apache vhosts, SSL chain, and a mapping of all .htaccess rules to convert.
    2. Deploy Nginx on alternate port and run smoke tests for static, PHP, and websockets.
    3. Create an automated cutover script and health-check watcher that can revert traffic within 30 seconds.
    SUMMARIZE WITH AI: Extract the important

    Share this article:

    𝕏 X (Twitter) f Facebook in LinkedIn 🔥 Reddit 🐘 Mastodon 🦋 Bluesky 💬 WhatsApp 📱 Telegram 📧 Email
    • Zero-Downtime Migration of API Backends and Versioned Endpoints
    • Zero-Downtime Host Migration: Split a Monolith into Microservices
    • Migrate Shopfront Inventory Feeds to Marketplaces Safely
    • DNS and Domain Transfer: Zero Downtime Guide
    Alan Curtis

    Alan Curtis

    With over 12 years of experience testing and reviewing web hosting solutions, this author is passionate about helping businesses and individuals find the best hosting, VPS, and cloud services for their needs. Covering performance, speed, uptime, migrations, and provider comparisons, every article on Host Compare is based on hands-on experience and real-world testing. Readers gain trusted insights, actionable advice, and clear guidance to choose hosting solutions confidently and optimize their websites effectively.

    Published: Wed, 07 Jan 2026
    Updated: Thu, 16 Apr 2026
    By John Miller

    In Website Migration.

    tags: Apache to Nginx migration with zero service interruption apache to nginx zero downtime migration blue green deployment nginx configuration website migration

    Legal Notice | Privacy Policy | Cookie Policy
    Article Archives

    Contactar

    © Host Compare. All rights reserved.