Update: This article is updated for WordPress 3.5 multisite’s file-handling and new W3-Total-Cache page-cache directory structure.
In this article, we will setup WordPress Multisite using subdomains with Nginx with added support for W3 Total Cache Plugin.
If you haven’t created a WordPress Multisite network, please check this guide first.
Nginx Config
Below is recommended Nginx configuration.
server {
##DM - uncomment following line for domain mapping
#listen 80 default_server;
server_name example.com *.example.com ;
##DM - uncomment following line for domain mapping
#server_name_in_redirect off;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
root /var/www/example.com/htdocs;
index index.php;
set $cache_uri $request_uri;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $cache_uri 'NULL';
}
if ($query_string != "") {
set $cache_uri 'NULL';
}
# Don't cache uris containing the following segments
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
set $cache_uri 'NULL';
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
set $cache_uri 'NULL';
}
# Use cached or actual file if they exists, otherwise pass request to WordPress
location / {
try_files /wp-content/cache/page_enhanced${cache_uri}_index.html $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri /index.php;
include fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off; log_not_found off; expires max;
}
location = /robots.txt { access_log off; log_not_found off; }
location ~ /\. { deny all; access_log off; log_not_found off; }
location ^~ /wp-content/w3tc- { deny all; access_log off; log_not_found off; }
}
Above configuration is already tested for minification & browser caching. You can disable minification in W3-Total-Cache settings.
Domain Mapping
You need to uncomment few lines in above nginx-config to get domain-mapping working. Apart from above config changes, you can read this guide to setup/configure domain-mapping.
Must Read:
- Checklist For Perfect WordPress-Nginx Setup - It will help you verify if your caching will work after PHP/MySQL crash.
- Nginx Maps for Better Static File Handling in WordPress-Multisite - useful for multisite created before WordPress 3.5 released
- WordPress-Nginx tutorials

Hello,
With wordpress 3.5 comes some pretty drastic changes with media file handling. More specifically, the Upload file path has changed completely in 3.5 as can be found here: http://codex.wordpress.org/Multisite_Network_Administration#Uploaded_File_Path
Is there any chance of you updating your guides to reflect these changes? I’m extremely new to nginx and would hate to have to go back to apache or use an older version of wordpress because of not knowing nginx well enough to adapt.
Thanks for your consideration.
Hi Chris,
I have answered this here – https://rtcamp.com/support/topic/nginx-subdomain-multi-site-w3-total-cache-wordpress3-5/
In short, you can ignore changes if you are in hurry.
Which line were you referring to? Why would my nginx conf change if I’m using an A record vs. a CNAME?
Thanks, great articles!
I am referring to line:
By default it is off but in case you face any issue, you need to uncomment that line. More info about server_name_in_redirect is here.
Regarding A-records v/s CNAME…
First, there was a typo. I wanted to say that you need to make changes for domain-mapping to work. The change was a line as mentioned above. So domain-mapping may affect your config. Not sure if you need to change config while switching from A-records to CNAME.
If you are using CNAME records + domain-mapping, can you please share your nginx config?
I never used CNAME records as they involve 2 lookups but there are valid cases to use CNAME records.
Anyway, I corrected line which caused confusion. Thanks.