Migrating Apache to Nginx — the translation patterns and playbook we use
May 17, 2026 · 1 min read · by Sudhanshu K.
Apache-to-Nginx migrations almost always stall at the same point: .htaccess. The application owner believes the file is doing something irreplaceable. Nine times out of ten it's a RewriteRule chain that translates to two lines of Nginx config. The other one time, it's a mod_rewrite rule so labyrinthine that the safer answer is to fix the application instead.
This is the translation table, the runbook, and the gotchas list we use on every Apache-to-Nginx engagement.
The translation table — the rules that cover 90% of cases
# Apache: RewriteRule ^(.*)$ /index.php?route=$1 [L]
location / {
try_files $uri $uri/ /index.php?route=$request_uri;
}
# Apache: Order Deny,Allow / Deny from all
location ~ /\.git { deny all; return 404; }
# Apache: AuthType Basic / AuthUserFile
location /admin/ {
auth_basic "restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
}.htaccess does not have a clean equivalent in Nginx — and that's a feature. Configuration lives in one place, not scattered across every directory in your webroot.
The full write-up covers:
- The
mod_rewritepatterns that map directly, and the ones that need rethinking - PHP-FPM wiring — the FastCGI block we copy onto every site
- Apache vs Nginx logging quirks (combined format differences, error log levels)
- Sticky-session and cookie-affinity patterns when load-balancing
- The dual-running cutover (Apache on :8080, Nginx on :443, traffic shaped at the edge)
- The 24-hour smoke test we run after cutover before we declare done
Reach out if you'd like a second pair of eyes on yours.
Full article available
Read the full article