Why Switch from Apache to Nginx
If you have a WordPress site that’s starting to struggle under heavy traffic, Apache is probably the culprit. Nginx consumes 4 times less memory and can handle 10 times more simultaneous connections. It’s not magic, it’s architecture: Apache creates a process or thread for each connection, while Nginx uses an event-driven model.
For WordPress, the Nginx + PHP-FPM combination is ideal. Nginx efficiently handles static files and proxying, while PHP-FPM gives you complete control over PHP processes. You can run multiple PHP versions simultaneously, allocate resources differently per project, and restart PHP without stopping the web server.
This migration seems complicated, but with the right method you can do it without a single second of downtime. Let’s see how.
What You Need Before Starting
The first step is to install Nginx alongside Apache, not instead of it. Both can run simultaneously on different ports. Apache stays on ports 80 and 443, while Nginx will temporarily use 8080 for testing.
Install Nginx and PHP-FPM:
apt update && apt install nginx php8.2-fpm php8.2-mysql php8.2-curl php8.2-gd php8.2-mbstring php8.2-xml php8.2-zip
Verify that PHP-FPM starts automatically:
systemctl enable php8.2-fpm && systemctl start php8.2-fpm
PHP-FPM communicates through a UNIX socket (faster than TCP). The default socket is /run/php/php8.2-fpm.sock. Verify it exists and is readable by www-data.
Configuring Nginx for WordPress
Create a configuration file for your site in /etc/nginx/sites-available/. Here’s an optimal WordPress configuration:
server {
listen 8080;
server_name example.com;
root /var/www/wordpress;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
location ~ /\.ht {
deny all;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
expires 365d;
add_header Cache-Control "public, immutable";
}
}
Enable the configuration and test:
ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
nginx -t
If everything is okay, start Nginx:
systemctl start nginx
Optimizing PHP-FPM for Performance
The default PHP-FPM configuration isn’t enough for a site with decent traffic. Open /etc/php/8.2/fpm/pool.d/www.conf and adjust the values:
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
These values work well for a server with 4GB RAM. If you have more, you can increase pm.max_children to 100. Simple formula: available RAM for PHP divided by 50MB per PHP process (WordPress consumes an average of 30-50MB per process).
Enable status page for monitoring:
pm.status_path = /fpm-status
Restart PHP-FPM:
systemctl restart php8.2-fpm
Testing Configuration on Port 8080
Before moving traffic, verify everything works on port 8080. Add the port to your local hosts file or test directly via IP:
curl -H "Host: example.com" http://SERVER-IP:8080
Test all critical functionality: WordPress login, publishing articles, uploading images, important plugin functionality. If you have cache (Redis, Memcached), verify it connects correctly.
Check response times with curl -w "@curl-format.txt" -o /dev/null -s http://SERVER-IP:8080. You should see responses under 200ms for uncached pages.
Zero-Downtime Migration
Now comes the important part: how to move traffic from Apache to Nginx without losing a single visit.
The safest method is to use Apache as a temporary reverse proxy. Modify Apache configuration to send requests to Nginx on 8080:
a2enmod proxy proxy_http
systemctl restart apache2
Then add to Apache’s VirtualHost:
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
Now Apache sends all requests to Nginx, but remains on port 80. Clients see exactly the same site. Monitor both servers’ logs for errors:
tail -f /var/log/nginx/error.log /var/log/apache2/error.log
If everything works perfectly after a few hours (or days, if you want to be sure), stop Apache and move Nginx to port 80:
systemctl stop apache2
systemctl disable apache2
Modify in /etc/nginx/sites-available/example.com:
listen 80;
listen [::]:80;
For HTTPS, copy SSL certificates and add:
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
Reload Nginx:
nginx -s reload
Monitoring and Final Optimization
After migration, monitor resource consumption with htop. You should see much less memory usage compared to Apache. Nginx processes consume only 2-5MB each, versus 20-50MB for Apache.
Configure separate logs for errors and access. Enable log rotation so it doesn’t fill the disk:
/var/log/nginx/*.log {
daily
rotate 14
compress
delaycompress
}
If you want to optimize even more, enable FastCGI cache in Nginx. Add to the server block:
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:100m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
In the location ~ \.php$ block:
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 60m;
This configuration dramatically reduces database load. Pages are served from RAM cache without executing PHP.
Conclusion
Migrating from Apache to Nginx isn’t a leap into the unknown. With the reverse proxy method, you do it gradually and safely. The result is a server that consumes fewer resources, responds faster, and scales better.
If you manage your own server, this is one of the best optimizations you can make. The difference is immediately noticeable in response times and the ability to handle high traffic.