building a bad ass nginx reverse proxy for wordpress
nginx makes a bad ass reverse proxy for wordpress

How to Setup NGINX as a Reverse Proxy for WordPress and Apache

I don’t know why I keep torturing myself, but I do. And you get to enjoy the fruits of my labor. Today, we’re going to setup an Nginx reverse proxy for WordPress, running on Apache. Hopefully, you’re already familiar with configuring Apache for WordPress. It’s pretty straight forward. And, once you get used to the syntax, configuring Nginx is pretty straight forward too.

Apache can be tweaked to be pretty damn fast. Nginx is just plain fast. But, Apache is extremely featureful. So, that’s why I’ve decided to set this up this way. Apache will still have access to it’s robust catalog of modules, but Nginx will handle mosts of the requests coming to the web server.

In case you didn’t catch on, I am going to run these services on the same machine. But, yes, you can host them on different machines.

install nginx reverse proxy for wordpress on apache web server

Installing NGINX Reverse Proxy

I really wish I was able to skip this step, but I can’t. Because, if you already have Apache installed and configured (at least, on Debian, my distribution of choice for this project – fuck systemd), you’ll need to stop apache to install nginx using the apt toolchain*.

You could do several other things, like ensure Apache is not listening on port 80, yadda yadda yadda. This one belongs to the package maintainers for Nginx, if you’re wondering (which, since they maintain their own repo, is likely some systemd loving folks.. I’m sure they’re good people either way, much love for everything Open Source).

systemctl stop apache2
apt install nginx-extras
systemctl stop nginx && systemctl start apache2

Configure NGINX Reverse Proxy for WordPress on Apache Web Server

Now we can get into the meat. First we need to tell the Apache web server to listen on a different port and local only. Port 8080 is popular for standard HTTP, which we’ll use. But, I urge you, especially if your Apache web server is on a different host, to use HTTPS and 8443 (or any non-standard port). You can lock it down, so it only allows the proxy to connect directly, if you like. I won’t cover that here.

Let’s edit /etc/apache2/ports.conf as well as the vhost config for our target domain to be proxied. The vhost config is typically located in /etc/apache2/sites-enabled/vhost.conf
Also ports.conf may simply have that some configuration information in /etc/apache2/apache2.conf (or httpd.conf, the folder can be different, the list goes on).

Change the ports to 8080 and 8443 (or your desired non-standard ports). It’s also safe to turn off HTTP, at this point, if you’re using SSL. This webserver isn’t outward facing, ideally. So, you no longer need the redirect (your plugins may complain).

nginx reverse proxy for wordpress /etc/apache2/ports.conf
nginx reverse proxy for wordpress - netstat antlp

netstat new ports reverse proxy wordpress
desired results at this point

Finalizing NGINX configuration for role as a reverse proxy for WordPress on Apache

From here, you can edit /etc/nginx/sites-available/default if you want. Or you can unlink it from /etc/nginx/sites-enabled/default and start your own new configuration file. I chose the latter option. My Nginx reverse proxy for wordpress isn’t going to use much of the default configuration. So, I just preserved it for later. Lets get some proxy basics set up, outside of the server block and a quick redirect. Open a file in /etc/nginx/sites-available/ (can be editing default or a new file) and add the follow before the server block.

proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
proxy_cache_path /var/run/proxy_cache levels=1:2 keys_zone=REVERSE-PROXY:30m max_size=1000m inactive=60m use_temp_path=off;
proxy_cache_key $scheme$host$request_uri;
proxy_buffers 1024 64k;
proxy_buffer_size 128k;
proxy_set_header Proxy "";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Now we’ll turn port 80 into a 301 redirect to port 443 for SSL. This is the appropriate method for forcing SSL on Nginx by the way, you should not have a server block with both 80 and 443 open.

server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$host$request_uri;
nginx cache proxy server block serving apache

New we get to set some rules specifically for WordPress to work:

# wordpress cookies no-cache
if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
set $skip_cache 1;
set $skip_reason Cookie;
# more wordpress love
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|sitemap(_index)?.xml") {
set $skip_cache 1;
set $skip_reason URI;

Finally, the section where we pipe things over to Apache. This should let you know, we’re almost finsihed.

The Actual NGINX Reverse Proxy for WordPress Configuration

the actual proxy - NOTE: you may need to toggle proxy_redirect on or off if you get a redirect loop when logging into admin
location / {
proxy_set_header Host $host;
proxy_redirect off;
proxy_cache REVERSE-PROXY;
proxy_cache_revalidate on;
proxy_ignore_headers Expires Cache-Control;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_404;
proxy_cache_bypass $skip_cache;
proxy_no_cache $skip_cache;
proxy_cache_valid 200 301 302 360m;
proxy_cache_valid 404 5m;
# feel free to rename PURGE, if you want (here and elsewhere)
proxy_cache_purge PURGE from;
proxy_ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
proxy_ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
nginx reverse proxy location block for proxy config and tls certificate

Now start up nginx with service nginx restart and you’re off to the caches, I mean races. Congratulations!

nginx reverse proxy for wordpress