ating a WordPress site from Apache to Nginx without downtime
WordPress powers a huge slice of the Australian web, from small business sites in Brisbane cafés to enterprise portals running out of Sydney data centres. Most of these installations started life on Apache because shared hosting providers such as VentraIP and Netregistry default to cPanel, which has historically bundled Apache as its workhorse web server. When traffic grows or administrators want better static file handling, lower memory footprints and tighter control over caching, Nginx becomes the natural next step. The catch is that swapping web servers while a live site serves visitors feels risky, especially for sites where every minute of downtime costs real revenue.
The trick that experienced sysadmins use is not a hard cutover but a staged migration. Apache keeps serving requests from the public while Nginx is brought in alongside it, tested, warmed up and finally promoted to the front line. Only when Nginx is confirmed healthy does DNS, load balancer configuration or the reverse proxy chain flip. This approach sidesteps the classic scenario where a poorly translated rewrite rule sends every URL into a 404 loop the moment the new server takes over.
Australian teams often have an extra wrinkle to consider. Maintenance windows need to align with AEDT or AEST, which puts local operators roughly four to sixteen hours away from their biggest source of traffic if they host for US or UK clients. That asymmetry makes any rolling-cutover strategy even more appealing, because traffic can stay live while engineers work an arvo shift from Melbourne rather than burning the small hours.
This walkthrough covers the practical steps to retire Apache from a WordPress stack without taking the site offline. It assumes a VPS or dedicated server running a modern Linux distribution, root access, and a willingness to spend a weekend tinkering. By the end, the site will be running on Nginx with PHP-FPM, FastCGI caching, and a clean configuration that no longer depends on .htaccess files for routing.
Inventorying the existing Apache stack
Before touching anything on the live server, take a full inventory of what Apache is actually doing. WordPress itself only needs a handful of core features: URL rewriting, PHP execution, static file serving and HTTPS termination. Most .htaccess files contain little more than the standard WordPress pretty-permalink block, but plugins often add their own rules. WP Super Cache, W3 Total Cache, security plugins and membership plugins all leave fingerprints in the rewrite map. Capture every custom rule so nothing falls through the cracks when Nginx takes over.
Backups are non-negotiable. Snapshot the entire server or, at minimum, tarball the document root, the Apache configuration directory, the MySQL databases and the /etc/letsencrypt folder if Let’s Encrypt is in use. Store the archive somewhere off the server — a cloud bucket in a Sydney region keeps latency low and data sovereignty straightforward for AU-based operators. Confirm the snapshot actually restores by spinning up a clone in a staging environment before touching production.
Audit the running services and listening ports. Apache typically binds to 80 and 443, MySQL or MariaDB to 3306, and possibly a mail service to 25, 465 or 587. Knowing which ports Apache owns tells you where to point Nginx later and whether anything else will need to move. Run ss -tlnp or netstat -tlnp and record the output; it is the kind of detail that saves hours during the cutover.
Bringing Nginx in as a reverse proxy
The cleanest zero-downtime path is to install Nginx and let it sit behind Apache initially, listening on an internal port and forwarding only a small slice of traffic. Install Nginx from the distribution’s official repository to get a current stable build with security patches. On Ubuntu and Debian this is a matter of apt install nginx; on Rocky, Alma and CentOS Stream, dnf install nginx after enabling the EPEL or AppStream module. Start the service but do not enable port 80 yet.
Configure Nginx as a reverse proxy for Apache by setting proxy_pass http://127.0.0.1:8080; inside a temporary server block. Apache is then reconfigured to listen on 8080 instead of 80, freeing the standard ports for Nginx later. Test the proxy chain locally with curl -H 'Host: example.com.au' http://127.0.0.1/ and verify the response includes WordPress headers and the correct theme assets. If something breaks here, Apache is still on port 80 for end users and you can fix the proxy without panic.
While Apache still owns the public IP, point a small percentage of traffic to Nginx through the hosts file on a developer machine, or use a load balancer such as HAProxy if one is already in front of the stack. This staged approach lets you compare Apache and Nginx responses for the same URL, catch edge cases in real time and roll back instantly by reverting the proxy weight. Many Aussie hosting providers running WHM and cPanel clusters already have HAProxy fronting web traffic, which makes this step almost trivial.
Translating rewrite rules and configuring PHP-FPM
WordPress pretty permalinks rely on Apache’s mod_rewrite and the famous .htaccess block that starts with # BEGIN WordPress. Nginx does not read .htaccess, so the equivalent logic has to live in the server block. The standard translation is the try_files directive: try_files $uri $uri/ /index.php?$args;. That single line covers categories, tags, custom post types and pagination for the vast majority of WordPress installs.
Plugins add the complications. WooCommerce often registers rewrite rules for product attributes, account endpoints and order tracking. Membership plugins rewrite download URLs and protected content routes. The safest way to discover the full rewrite map is to install the “Rewrite Rules Inspector” plugin on staging, export the rule list and translate each custom rule into an Nginx location block. Anything ending in (.?.+?)(/|$) in WordPress usually becomes a rewrite directive pointing back to index.php.
PHP-FPM replaces mod_php and tends to use noticeably less memory per worker, which matters on the smaller VPS plans common among Australian freelancers and small agencies. Install php-fpm for the same PHP version Apache was running, then configure a location ~ \.php$ block that forwards requests to the FPM socket or TCP port. Set fastcgi_pass to unix:/run/php/php8.2-fpm.sock on Debian-family systems or 127.0.0.1:9000 on RPM-based ones. Watch out for cgi.fix_pathinfo; leave it at 0 to close off a common file-handling vulnerability flagged by the ACSC. A community-maintained boilerplate at https://myeasyprojects.net/ covers the same baseline and adds WordPress-specific tweaks worth borrowing.
A quick checklist before promoting Nginx:
/wp-admin/loads without redirect loops- Permalinks return 200 across post types
- Admin-ajax requests complete in under 300 ms
- Uploads directory serves images directly, not via PHP
SSL, caching and static asset handling
Once PHP-FPM is healthy, turn attention to TLS and caching. If Let’s Encrypt is already issuing certificates via Certbot, switch from the Apache authenticator to the Nginx one. Run certbot --nginx -d example.com.au -d www.example.com.au and Certbot will patch the server block with a hardened SSL configuration that scores A or A+ on Qualys SSL Labs. HSTS, OCSP stapling and modern cipher suites are added in one shot, which helps sites meet the ACSC Essential Eight maturity goals.
FastCGI caching is where Nginx pulls well ahead of Apache for WordPress. Wrap the PHP location block in a cache zone, set sensible bypass rules for logged-in users and admin requests, and define a short TTL such as 30 seconds for pages that change often and a longer one for static archives. A reasonable starting configuration looks like:
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:10m max_size=1g inactive=60m;fastcgi_cache_bypass $skip_cache $cookie_logged_in;fastcgi_no_cache $skip_cache;fastcgi_cache_valid 200 301 302 30m;
Static assets deserve their own treatment. WordPress themes and plugins ship CSS, JavaScript, web fonts and images that rarely change. Serve them directly from Nginx with a long expires header and Cache-Control: public, immutable for fingerprinted filenames. Gzip or, preferably, Brotli compression cuts the weight of those assets before they hit the NBN connection of a typical visitor, and HTTP/2 multiplexing keeps the rest of the page snappy on the higher-latency links common outside the Sydney and Melbourne metro areas.
The DNS cutover and rollback plan
With Nginx healthy and Apache still answering on port 8080, the cutover is mostly a routing change rather than a configuration change. On a single-server setup, edit the main Nginx server block to listen on 80 and 443, stop Apache and reload Nginx. On a multi-server fleet, flip the load balancer weight from 100 percent Apache to 100 percent Nginx. If HAProxy or a cloud load balancer is in front, the change takes seconds and is reversible in the same window.
Lower TTL on the authoritative DNS records to 300 seconds at least 24 hours before the cutover so any cached resolver picks up the new IP quickly. Once Nginx is confirmed live, raise the TTL back to 3600 or whatever the standard value is. For sites behind Cloudflare or a similar CDN, purge the cache after the swap to force a fresh fetch from origin.
Keep the old Apache stack ready to go for at least a week. A simple systemctl start httpd brings it back if a critical bug surfaces, and keeping the configuration files in /etc/apache2/ means rollback is genuinely a five-minute affair. Run nginx -T to dump the full configuration, store it in version control and tag the commit so future operators can see exactly what changed and why. Edge cases will still pop up months later, and threads on the developer forum are a useful place to compare notes with other operators who have walked the same path.
After a full business day of clean logs, retire Apache for good. Remove the package, drop the configuration directory and reclaim the memory it consumed. The site now runs on a leaner, faster stack, and the next migration — whether to a new VPS provider in Perth or a managed Kubernetes cluster — starts from a much simpler baseline.