Apache is not known for its speed. On the contrary, Apache has garnered a reputation for being rather bloated and performing well under high traffic. However, Apache is still the most popular web server around the world and is used by many hosting companies due to its familiarity and htaccess. If you still love Apache for some reason and want to speed up your WordPress site you can put an nginx reverse proxy caching solution in front of Apache to give your users a faster experience.
nginx reverse proxy cache works by sitting in front of Apache. nginx listens on port 80 and Apache listens on port 8080. nginx will serve any content it can cache while all other requests are sent to Apache for PHP processing with MySQL or MariaDB.
Note: This guide will not work ideally for WooCommerce, a new guide may be published for an nginx proxy cache that works for WooCommerce. If you want me to make you one contact me.
Configure nginx Reverse Proxy WordPress Cache for Apache
Installation Overview
How to Configure Apache for nginx Reverse Proxy
Open Apache ports file
Change port to 8080
Open your Apache virtual host
Change Virtualhost port to 8080
Ctrl+X, Y and Enter to save
You will need to change all of your Apache virtual hosts to listen on port 8080.
Apache will be restarted after nginx is installed and configured to avoid any downtime.
Install nginx
Install nginx and the nginx-extras
package to get the ngx_cache_purge module which will make it easier to manage then nginx proxy cache.
Create nginx configuration
Paste the nginx configuration, we need the proxy_buffer
values at the top to prevent this error (source)
upstream sent too big header while reading response header from upstream errors with buffers
Here is the actual nginx proxy cache configuration, note that this is not optimized for WooCommerce.
Remember to change Web.Server.IP
with your server’s IP address.
Ctrl+X, Y and Enter
Symlink the nginx reverse proxy cache for WordPress virtual host so it will be enabled when we restart nginx
Unlink the default nginx virtual host
Restart Apache and nginx
Testing the nginx Reverse Proxy Cache
We can use cURL to test that the nginx reverse proxy is caching our WordPress site
Now cURL is installed we can start testing the nginx reverse proxy in front of Apache
Use SSH on the Web server to run these cURL commands. This will test if your homepage is cached by the reverse proxy, the -I
flag ensures we get the response headers back from the reverse proxy server
The key value here is the WP-Bullet-Proxy-Cache
status
HTTP/1.1 200 OK
Server: nginx/1.8.1
Date: Wed, 30 Mar 2016 17:32:24 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
WP-Bullet-Proxy-Cache: HIT
If the home page isn’t cached you will get a MISS
in the WP-Bullet-Proxy-Cache
response
HTTP/1.1 200 OK
Server: nginx/1.8.1
Date: Wed, 30 Mar 2016 17:35:53 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
WP-Bullet-Proxy-Cache: MISS
Sometimes you may need to cURL the same URL twice to get a HIT response.
How nginx Stores Cache
If you look in the proxy_cache_path
folder you will see a bunch of seemingly random letters and numbers which are decided by the levels=1:2
. This can seem confusing initially since nginx stores cache as md5 hashes of the URLs based on the proxy_cache_key
. we are using $scheme$host$uri
here
$scheme
=http$host
=domain$request_uri
=URL
So for this page https://guides.wp-bullet.com/about
$scheme
is https$host
is guides.wp-bullet.com$request_uri
is /about
We can pass this through an md5 generator on Debian
It generates this md5 sum
c301d2e9d39fa7434a56322a09dbab17
which nginx uses to create the folder structure based on the proxy_cache_path levels=1:2
.
Here the 1
in 1:2
refers to the 7
, the character all the way to the right at the end of the original md5 hash.
The 2
in 1:2
refers to the b1
which are the characters to the left of the top level key 1
(here 7
).
c301d2e9d39fa7434a56322a09dbab17
From levels=1:2
, the 1 (the 7
) becomes the top level folder and the 2 (b1
) becomes its sub directory, with the original md5 hash as the filename
/var/run/proxy-cache/7/b1/c301d2e9d39fa7434a56322a09dbab17
Knowing how nginx cache works means we can selectively deleted items from the reverse proxy cache.
Purging and Invalidating the nginx Reverse Proxy cache
Thanks to the ngx_cache_purge module which is included in the nginx-extras module we have several ways to invalidate cache selectively. Our goal is to have the entire site cached using this plugin so your WordPress site is completely cached and always fast. When we update content we only want to empty the cache for those posts, pages or categories which are changed and replace those old items with fresh new ones immediately so your users get the fastest possible experience.
The WP Bullet nginx cache plugin allows you to refresh the cache using all of these methods except the PURGE method.
- nginx proxy cache is stored in a folder structure in the
/var/run/proxy-cache
folder which we can selectively delete specific items from or delete everything to empty the entire cache - BYPASS lets you force a refresh of the post or page by asking the Web server serving WordPress for a new version
- The refreshed item will replace the old outdated item in the nginx reverse proxy cache
- PURGE method, the
proxy_cache_purge
lets you use non-RFC HTTP methods to purge specific items from cache - /purge URL method lets you append a URL to the purge location to empty a specific item
WP Bullet nginx cache supports all of these methods, this is how to test if they are working using cURL.
Empty Entire nginx Reverse Proxy Cache
If you want to empty the entire cache you can simply delete the proxy-cache folder contents manually
You can also delete specific items if you want by creating an md5 hash of the full URL you want to purge and deleting the specific folder and subfolder recursively in the proxy_cache_path folder. The WP Bullet nginx cache plugin does this for you.
If you want to empty the entire cache using regular expressions (also known as wildcards) your only option is to use nginx Plus which costs money. The nginx plus crew know that having a high performance WordPress site means keeping your entire site cached all the time so large companies will pay for flexible cache control.
Refresh Items in nginx Reverse Proxy with BYPASS Method
Bypass is definitely the best way to invalidate and refresh your nginx reverse proxy cache. with proxy_cache_bypass you force the nginx reverse proxy to fetch a new version of the URL from the web server running WordPress and replace the old outdated version with the new fresh version. Your users will never get old content this way and will never get slow PHP compiled on-the-fly versions from your web server (unless they aren’t cacheable).
In the block above we implemented proxy_cache_bypass
only for requests that come from our web server or the reverse proxy itself
We enabled the secret header for incoming requests from the web server and reverse proxy so we can test using the secret header with cURL from those servers.
You will see this output showing BYPASS
in the X-Cache header
HTTP/1.1 200 OK
Server: nginx/1.8.1
Date: Wed, 30 Mar 2016 17:30:44 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Cache: BYPASS
If you try the same cURL command from another server you will just see a HIT
response
HTTP/1.1 200 OK
Server: nginx/1.8.1
Date: Wed, 30 Mar 2016 17:33:23 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Cache: HIT
The WP Bullet nginx cache plugin will run all of these commands automatically for you when you update your posts, pages and categories.
Refresh Items in nginx Reverse Proxy with PURGE Method
This PURGE method is courtesy of the ngx_cache_purge module found in the nginx-extras package
For this method to work I found the proxy_cache_key
had to be set to $scheme$host$request_uri
but your experience may vary
To submit a PURGE request use this syntax, the proxy_cache_purge module will translate the request into the md5 hash of the URL and delete the item from the proxy_cache_path
folder specified in the nginx reverse proxy virtual host.
If the reverse proxy has the file you will get a 200 response meaning it was successful
HTTP/1.1 200 OK
Server: nginx/1.8.1
Date: Tue, 29 Mar 2016 23:55:07 GMT
Content-Type: text/html
Content-Length: 277
Connection: keep-alive
If the nginx reverse proxy does not have that specific URL cached then you will get a 404
HTTP/1.1 404 Not Found
Server: nginx/1.8.1
Date: Tue, 29 Mar 2016 23:56:11 GMT
Content-Type: text/html
Content-Length: 168
Connection: keep-alive
If the nginx reverse proxy detects that your IP address is not allowed to execute PURGE requests you will get a 403 forbidden response
HTTP/1.1 403 Forbidden
Server: nginx/1.8.1
Date: Wed, 30 Mar 2016 17:13:45 GMT
Content-Type: text/html
Content-Length: 168
Connection: keep-alive
This type of nginx reverse proxy security is important because it limits PURGE requests by whitelisting your trusted servers
Purge Items in nginx Reverse Proxy with /purge URL Method
The /purge URL method uses a specific URL to call the nginx proxy_cache_purge method which we implemented above.
To purge via URL use this cURL comand to purge the homepage represented by the trailing slash
You will see this response if the home page was cached in the nginx reverse proxy and you successfully emptied it
HTTP/1.1 200 OK
Server: nginx/1.8.1
Date: Wed, 30 Mar 2016 13:55:47 GMT
Content-Type: text/html
Content-Length: 277
Connection: keep-alive
If your nginx reverse proxy doesn’t have your WordPress home page cached you will see a 404 error
HTTP/1.1 404 Not Found
Server: nginx/1.8.1
Date: Wed, 30 Mar 2016 13:58:50 GMT
Content-Type: text/html
Content-Length: 168
Connection: keep-alive
If your nginx reverse proxy does not allow you to access the /purge location you will get a 403 forbidden error
HTTP/1.1 403 Forbidden
Server: nginx/1.8.1
Date: Wed, 30 Mar 2016 17:16:39 GMT
Content-Type: text/html
Content-Length: 168
Connection: keep-alive
Similar to the PURGE method we are limiting access to the /purge location by whitelisting IP addresses so attackers cannot overwhelm your web server running WordPress
Get the Real IP in Apache Logs from nginx
You will need to open your Apache virtualhost to adjust the logging format
Find this line containing LogFormat %h
Replace the %h
with %{X-Forwarded-For}i
to use the header we set in nginx.
If you do not have a LogFormat line then add the whole line as you see it above within your block
Test your Apache virtual host syntax is OK
If it’s all good then reload Apache
Now the logs will show the correct IP.
Sources
Where does /var/lib/nginx/proxy come from?
Getting Real IP for Apache from nginx