Table of Contents
Some weeks ago we published a tutorial instructing how to use Nginx as a Reverse Proxy with buffering & cache functions using the standard edge-origin pattern. The configuration settings shown within that guide were ok to use for generic web sites, but we can definitely optimize them better for specific caching scenarios. In this follow-up article we'll learn how to fine-tune the nginx.conf configuration file to perform well as a Reverse Proxy with caching and request buffering features for a WordPress-enabled web site.
It goes without saying that the origin server - the one serving the WP web site - can be any Linux or Windows machine with either Apache, Nginx, IIS or other web servers, while the edge server - the one hosting Nginx and actually accepting the user requests - is meant to be a Linux-based environment. The two services could even be installed within the same machine, providing that the one acting as the origin will be configured to answer to a different port (such as 8080): however, configuring everything within a single machine should be avoided for high traffic web sites for obvious performance reasons.
Http
Here's the configuration settings that can be put within the http block of the nginx.conf file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# --------------------------------------------------------------------- # REVERSE PROXY CONFIGURATION for Wordpress, v1.0/2018 # https://www.ryadel.com # --------------------------------------------------------------------- #Enables or disables buffering of responses from the proxied server. proxy_buffering on; #prevent header too large errors proxy_buffers 256 16k; proxy_buffer_size 32k; #set the location of the cached files, zone, name, size (1000 MB) and how long to cache for (600 minutes) proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=edge-cache:10m inactive=600m max_size=1g; proxy_temp_path /var/cache/nginx/tmp; proxy_cache_key $scheme$host$request_uri; # When enabled, only one request at a time will be allowed to populate # a new cache element identified according to the proxy_cache_key directive # by passing a request to a proxied server. # Other requests of the same cache element will either wait for a response to appear in the cache # or the cache lock for this element to be released, up to the time set by the proxy_cache_lock_timeout directive. proxy_cache_lock on; # proxy_cache_revalidate instructs NGINX to use conditional GET requests when refreshing content from the origin servers. # If a client requests an item that is cached but expired as defined by the cache control headers, NGINX includes the # If-Modified-Since field in the header of the GET request it sends to the origin server. # This saves on bandwidth, because the server sends the full item only if it has been modified since the time recorded # in the Last-Modified header attached to the file when NGINX originally cached it. proxy_cache_revalidate on; #proxy_cache_min_uses sets the number of times an item must be requested by clients before NGINX caches it. # This is useful if the cache is constantly filling up, as it ensures that only the most frequently accessed items # are added to the cache. By default proxy_cache_min_uses is set to 1. proxy_cache_min_uses 3; #The updating parameter to the proxy_cache_use_stale directive, combined with enabling the # proxy_cache_background_update directive, instructs NGINX to deliver stale content when clients request an item # that is expired or is in the process of being updated from the origin server. All updates will be done in the background. # The stale file is returned for all requests until the updated file is fully downloaded. proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; proxy_cache_background_update on; #fix 504 gateway timeouts, can go in nginx.conf proxy_connect_timeout 600; proxy_send_timeout 600; proxy_read_timeout 600; send_timeout 600; # Sets caching time for different response codes proxy_cache_valid 200 302 10m; proxy_cache_valid 301 1h; proxy_cache_valid any 1m; # Sets the HTTP protocol version for proxying (default is 1.0). # Version 1.1 is recommended for use with keepalive connections and NTLM authentication. proxy_http_version 1.1; # Determines whether SSL sessions can be reused when working with the proxied server (default is on). # If the errors “SSL3_GET_FINISHED:digest check failed” appear in the logs, try turning it off. # proxy_ssl_session_reuse on; # --------------------------------------------------------------------- # REVERSE PROXY CONFIGURATION - END # --------------------------------------------------------------------- |
All the settings are well-explained in the various comments: if you need additional info, you can also look for them within the official Nginx documentation by clicking here.
It's worth noting that, if you don't want to stack up everything in your main configuration file, you can also put this whole part to a new http.reverseproxy.conf file - which you can add in the /etc/nginx/ folder - and then link it by adding the following line within the http block of the nginx.conf file itself:
1 |
include http.reverseproxy.conf; |
Server
Here's the configuration settings that can be put within the server block of the nginx.conf file, right below the listen and server_name settings:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# --------------------------------------------------------------------- # CACHE CONFIGURATION for Wordpress, v1.0/2018 # https://www.ryadel.com # --------------------------------------------------------------------- # define nginx variables set $do_not_cache 0; set $skip_reason ""; set $bypass 0; # security for bypass so localhost can empty cache if ($remote_addr ~ "^(127.0.0.1)$") { set $bypass $http_secret_header; } # skip caching WordPress cookies if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) { set $do_not_cache 1; set $skip_reason Cookie; } # Don't cache URIs containing the following segments if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|sitemap(_index)?.xml") { set $skip_cache 1; set $skip_reason URI; } # --------------------------------------------------------------------- # CACHE CONFIGURATION for Wordpress - END # --------------------------------------------------------------------- |
Location
Last but not least, here's how to configure the location block:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
location / { # comment out proxy_redirect if get login redirect loop proxy_redirect off; proxy_cache edge-cache; proxy_cache_revalidate on; proxy_ignore_headers Expires Cache-Control; # CACHE CONFIGURATION result proxy_cache_bypass $bypass $do_not_cache; proxy_no_cache $do_not_cache; # httpoxy exploit protection proxy_set_header Proxy ""; # add forwarded for header proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # add the Wordpress hostname to avoid Wordpress canonical redirect proxy_set_header Host $host; # proxy_set_header Host www.edge-hostname.com; proxy_set_header Connection ""; # pass requests to the origin backend proxy_pass https://origin; } |
As we can see, we made sure that Nginx cache will be bypassed whenever it needs to (WP auth cookies, wp-admin requests and so on), so that the basic WordPress functions won't be crippled.
Results
Here's how we can put everything together into a typical Nginx configuration file (nginx.conf), assuming that we stacked everything up there:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# --------------------------------------------------------------------- # NGINX - Proxy-Cache configuration - v1.0/2018 # https://www.ryadel.com/ # --------------------------------------------------------------------- user nginx; worker_processes 2; working_directory /var/www; error_log /var/log/nginx/error.log; pid /run/nginx.pid; # Load dynamic modules. See /usr/share/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include mime.types; default_type application/octet-stream; include http.reverseproxy.conf; # Custom settings for http add_header X-Cache-Status $upstream_cache_status; upstream origin { # gusrv (via INTERNAL firewalld zone) server www.origin-hostname.com; } server { listen 80 default_server; listen [::]:80 default_server; server_name www.edge-hostname.com; # --------------------------------------------------------------------- # CACHE CONFIGURATION for Wordpress, v1.0/2018 # https://www.ryadel.com # --------------------------------------------------------------------- # define nginx variables set $do_not_cache 0; set $skip_reason ""; set $bypass 0; # security for bypass so localhost can empty cache if ($remote_addr ~ "^(127.0.0.1)$") { set $bypass $http_secret_header; } # skip caching WordPress cookies if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) { set $do_not_cache 1; set $skip_reason Cookie; } # Don't cache URIs containing the following segments if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|sitemap(_index)?.xml") { set $skip_cache 1; set $skip_reason URI; } # --------------------------------------------------------------------- # CACHE CONFIGURATION for Wordpress - END # --------------------------------------------------------------------- location / { # comment out proxy_redirect if get login redirect loop proxy_redirect off; proxy_cache edge-cache; proxy_cache_revalidate on; proxy_ignore_headers Expires Cache-Control; # CACHE CONFIGURATION result proxy_cache_bypass $bypass $do_not_cache; proxy_no_cache $do_not_cache; # httpoxy exploit protection proxy_set_header Proxy ""; # add forwarded for header proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # add the Wordpress hostname to avoid Wordpress canonical redirect proxy_set_header Host $host; # proxy_set_header Host www.giudiziouniversale.com; proxy_set_header Connection ""; # pass requests to the origin backend proxy_pass https://origin; } } } |
Troubleshooting
The most common issues we can run into while configuring Nginx as a reverse proxy are related to file permissions: ensure that the nginx user - or any other user set by the user configuration setting within the nginx.conf file - has the right permissions to access the working_directory , proxy_cache_path and proxy_temp_path folders in read/write mode. If this is not enough, remember to check out the /var/log/nginx/access.log and /var/log/nginx/error.log files for useful insights regarding your specific issue(s).
Conclusions
And that's it! I sincerely hope that these settings will help those who need to optimize their Nginx configuration for WordPress.