Edit: actually, it looks like this doesn't work the way I think it does ... looks like nginx has changed enough between 0.7 and 1.0 that my original config doesn't work as correctly as it used to.
Edit 2: Actually I think WP Supercache is the one that changed.
I particularly liked how they used the try_file directive to cut down on the if statements.
----
Like most people I've cobbled together what I found through Google searching. My case is further complicated because I run a multisite configuration and use the WP Domain Mapping plugin.
It works in a few stages.
WP Supercache is configured to gzip pages to disk. It used to be that you needed to add extra code by hand to support domain mapping, but WP Supercache now cooperates and puts on-disk cached files for each blog in its own directory.
Then I put specific directives in a sites-available/ config file, not the main Nginx file (I serve a static site off the same server).
First,
server {
listen <ipaddress> default_server;
The default_server directive means that if another listen directive doesn't pick up an incoming request, it will be handled by this config. Otherwise multisite goes kerflooie.
Getting end-to-end UTF8 on a stack is a hassle because you have to do it in the database (multiple times, MySQL has about two hojillion charset configuration dials), in PHP and then in Nginx:
The rewrite is just a little tweak. If you go to /wp-admin, Wordpress will often redirect to the home page. If you go to /wp-admin/, it does what you expect. So this rewrite just adds a trailing slash.
index index.php;
For multisite, the Wordpress coders change the URLs files are served from, for reasons that are simply beyond my mortal comprehension. Anyhow, you need a rewrite rule for /files/ URLs:
Then what follows is based on the common config file you'll see on a dozen blog and forum posts if you google around.
The next thing to do is try and serve a file straight off disk. Nginx does things in an unintuitive order, so even though this rule is further down, it will often fire first:
# Rewrite URLs for WP-Super-Cache files
# if the requested file exists, return it immediately
# this covers the static files case
if (-f $request_filename) {
expires 15d;
break;
}
The "break" directive basically says, "Oh you found whatever.css|jpg|js? Just serve that up kthxbai".
Now we proceed to determine whether or not we'll try to serve a cached file off disk:
set $supercache_file '';
set $supercache_uri $request_uri;
# don't interfere with POST events (ie form submissions)
if ($request_method = POST) {
set $supercache_uri '';
}
# Using pretty permalinks, so bypass the cache for any query string
if ($query_string) {
set $supercache_uri '';
}
# Don't show cached version to logged-in users
if ($http_cookie ~* "comment_author_|wordpress|wp-postpass_" ) {
set $supercache_uri '';
}
If there's still a supercache URL, we try to serve it straight off disk:
# if we haven't bypassed the cache, specify our supercache file
if ($supercache_uri ~ ^(.+)$) {
set $supercache_file /wp-content/cache/supercache/$http_host/$1index.html;
}
# only rewrite to the supercache file if it actually exists
if (-f $document_root$supercache_file) {
rewrite ^(.*)$ $supercache_file break;
}
Otherwise, give up and let Wordpress grind out the file:
# all other requests go to Wordpress
if (!-e $request_filename) {
rewrite ^.+?(/wp-.*) $1 last;
rewrite ^.+?(/.*\.php)$ $1 last;
rewrite ^ /index.php last;
}
}
location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/wordpress$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
From the Wordpress wiki I picked up a few nifty directives to make log files a little less cluttered; I've thrown those in a common file which I include here:
include /etc/nginx/clean.conf;
}
clean.conf looks like this:
# Global restrictions configuration file.
# Designed to be included in any server {} block.</p>
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
deny all;
}
# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
The final step is to add this magic directive to your master nginx.conf:
gzip_static on;
This tells Nginx to look for a file with a .gz extension. So when it gets redirected to look at whatever-blog.com/index.html, it will also check for index.html.gz. If it finds that file, it will serve it instead.
Googling is about the worst way to set up an nginx server configuration! The only tutorials and helpful snippets out there are riddled with bad practices.
I notice that you're using a lot of "if" statements. I hope you've read this http://wiki.nginx.org/IfIsEvil. I understand that in this case it might be harder to find alternatives for the if-statement, haven't looked into what you need really deeply.
It's been a few years since I cobbled this one together and I recall reading the IfIsEvil web page. I vaguely recall that at the time there was some limitation on how try_files worked that made it necessary to use ifs, but for the life of me I don't remember what.
The rtCamp configuration I linked to earlier makes use of try_files and says he has support for both supercache and domain mapping, so I think I'll migrate to that.
Thanks Jacques. Author of that updated config post on rtCamp.com here.
I really think Nginx in still underestimated by large. Most article handles rewrite in nginx based on their Apache knowledge.
Nginx's try_files is magical. So does maps{..} section.
Using Nginx map, you can server static files in WordPress-multisite without PHP (much better than X-SendFile or X-Accelredirection). On large wordpress-multisite network, this can really increase Nginx's capacity by multifold.