
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Moving a live web server from Apache to Nginx requires translating process-based logic into an event-driven architecture without breaking existing functionality. This Apache to Nginx migration step by step guide provides the exact workflow I use in production environments to ensure configuration parity and zero downtime. Before touching any production configs, review our Nginx vs Apache performance comparison to validate that the architectural trade-offs align with your specific application requirements and traffic patterns.
How do you prepare for an Apache to Nginx migration step by step?
Preparation prevents the most common migration failures. You cannot simply uninstall Apache and install Nginx; the configuration paradigms are fundamentally different. Apache relies heavily on distributed .htaccess files and per-directory overrides, while Nginx uses centralized server blocks and location directives. Before writing a single line of Nginx config, you must inventory exactly what Apache is doing.
Audit active Apache modules and configurations
Run the following commands to capture your current Apache state. This output becomes your migration checklist:
# List all loaded Apache modules
apachectl -M | sort
# Find all .htaccess files in your web root
find /var/www/html -name ".htaccess" -exec echo "=== {} ===" \; -exec cat {} \;
# Dump current virtual host configurations
apachectl -S Categorize every module into three buckets: native Nginx equivalent (e.g., mod_rewrite → ngx_http_rewrite_module), requires external tool (e.g., mod_security → ModSecurity-nginx or WAF), or no longer needed. Many legacy Apache modules handled tasks that modern application frameworks now manage internally. Do not migrate obsolete functionality.
Map .htaccess rules to Nginx directives
This is where most migrations stall. Nginx does not read .htaccess files. Every rewrite rule, access restriction, and header manipulation must be translated into the appropriate server or location block. Create a spreadsheet mapping each Apache directive to its Nginx counterpart before touching configuration files. For complex rewrite logic, test translations in isolation using curl against a staging instance before applying them to production configs.
How do you configure Nginx alongside Apache safely?
The safest approach runs both servers simultaneously during the validation phase. Apache continues serving production traffic on port 80/443 while Nginx listens on an alternate port (typically 8080/8443). This parallel setup lets you verify behavior without risking user-facing outages. If you are setting up a fresh environment rather than migrating in place, consult our guide to installing Nginx on Ubuntu for baseline hardening steps.
Install Nginx without disrupting Apache
On Ubuntu/Debian systems, install Nginx but prevent it from starting automatically:
sudo apt update
sudo apt install nginx
# Stop Nginx immediately after install
sudo systemctl stop nginx
sudo systemctl disable nginx
# Verify Apache still owns port 80
sudo ss -tlnp | grep ':80' Edit /etc/nginx/sites-available/default (or create a new site file) to bind to port 8080 initially. Change every listen 80; to listen 8080; and listen 443 ssl; to listen 8443 ssl;. Start Nginx manually and confirm it binds correctly:
sudo nginx -t
sudo systemctl start nginx
curl -I http://localhost:8080 Configure PHP-FPM integration correctly
Nginx does not embed PHP like Apache's mod_php. It delegates processing to PHP-FPM via FastCGI. Ensure PHP-FPM is installed and running independently of Apache:
sudo apt install php8.3-fpm
sudo systemctl enable --now php8.3-fpm In your Nginx server block, add the PHP handler within the appropriate location block. Note the use of the Unix socket for lower latency compared to TCP:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
} A common mistake is forgetting fastcgi_param SCRIPT_FILENAME. Without it, PHP-FPM receives no file path and returns a blank page or 404. Always test PHP execution explicitly with a simple info.php file before proceeding.
How do you translate Apache rewrite rules and SSL to Nginx?
Rewrite rules and SSL certificates are the two highest-risk translation points. Errors here cause broken links, SEO damage, or security warnings. Treat this phase methodically.
Convert mod_rewrite to Nginx try_files and rewrite
Apache's RewriteRule often handles front-controller routing for frameworks like Laravel or WordPress. In Nginx, try_files is usually cleaner and more performant:
# Apache: RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !-d
# RewriteRule ^(.*)$ index.php?$query_string [L,QSA]
# Nginx equivalent:
location / {
try_files $uri $uri/ /index.php?$query_string;
} For redirects (301/302), use Nginx's return directive instead of rewrite when possible. return is processed earlier in the request cycle and avoids regex overhead:
# Permanent redirect
return 301 https://example.com$new_uri;
# Regex rewrite (only when necessary)
rewrite ^/old-path/(.*)$ /new-path/$1 permanent; Migrate SSL certificates and TLS settings
Copy your existing certificate and key files to Nginx's expected location. Update permissions so only root can read the private key. Configure modern TLS settings that match or exceed your Apache configuration. Refer to our SSL certificate installation guide for Let's Encrypt automation if your certs need renewal during migration.
server {
listen 8443 ssl http2;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.pem;
ssl_certificate_key /etc/ssl/private/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
} How do you validate and cut over without downtime?
Never switch production traffic based on manual browser checks alone. Automated validation catches edge cases humans miss. Only after parity is confirmed should you perform the final cutover.
Automated response comparison testing
Write a script that sends identical requests to both Apache (port 80) and Nginx (port 8080), then compares status codes, headers, and response bodies. Tools like diff, curl, or dedicated HTTP comparison utilities work well. Pay special attention to:
- Redirect chains and final destination URLs
- Cache-Control and security headers
- Cookie paths and domains
- Response body content for dynamic pages
- Error page rendering (404, 500)
If discrepancies exist, fix them in Nginx config and re-test. Do not proceed until automated tests pass for all critical paths.
| Migration Risk Area | Common Failure Mode | Validation Method | Rollback Strategy |
|---|---|---|---|
| Rewrite Rules | Broken internal links, 404s | Automated URL crawl + status diff | Re-enable Apache on port 80 |
| PHP Execution | Blank pages, wrong SCRIPT_FILENAME | Test endpoint returning phpinfo() | Verify FPM socket path and perms |
| SSL/TLS | Certificate mismatch, weak ciphers | SSL Labs test + curl -v comparison | Restore original cert files |
| Headers & Cookies | Session loss, CORS failures | Header diff script on auth endpoints | Add missing add_header directives |
| File Permissions | 403 Forbidden on uploads/assets | Recursive ls -la comparison | chown/chgrp to www-data |
Execute the final cutover
Once validation passes, schedule a maintenance window. The cleanest cutover swaps ports atomically:
- Stop Apache:
sudo systemctl stop apache2 - Update Nginx config to listen on 80/443 (remove 8080/8443)
- Test config:
sudo nginx -t - Reload Nginx:
sudo systemctl reload nginx - Run smoke tests immediately against production URLs
- Monitor error logs for 30 minutes:
tail -f /var/log/nginx/error.log
Keep Apache installed and configured for at least two weeks post-migration. If a critical issue surfaces that you cannot quickly resolve in Nginx, reverting takes seconds: stop Nginx, start Apache. Only decommission Apache after confirming stability across multiple deployment cycles.
Finalizing Your Apache to Nginx Migration Step by Step
A successful Apache to Nginx migration step by step hinges on disciplined preparation, parallel validation, and atomic cutover—not on speed. The performance and resource efficiency gains are substantial, but only if configuration parity is verified before production traffic touches the new stack. Document every translated directive, maintain rollback capability during the transition period, and integrate Nginx configuration into your infrastructure-as-code pipeline to prevent future drift. If your team needs hands-on support planning or executing this migration for a production workload, reach out to discuss your specific environment.