Server Fault is a question and answer site for system and network administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am trying to setup Wordpress Multisite, using subdirectories, with Nginx, php5-fpm, APC, and Batcache. As many other people, I am getting stuck in the rewrite rules for permalinks.

I have followed these two guides, which seem to be as official as you can get:

It is partially working:

But other permalinks, like these two to a post or to a static page, don't work:

They either take you to a 404 error, or to some other blog!

Here is my configuration:

server {
    listen       80 default_server;
    root         /var/www;

    access_log   /var/log/nginx/blog-access.log;
    error_log    /var/log/nginx/blog-error.log;

    location / {
        index index.php;
        try_files $uri $uri/ /index.php?$args;


    # Add trailing slash to */wp-admin requests.
    rewrite /wp-admin$ $scheme://$host$uri/ permanent;

    # Add trailing slash to */username requests
    rewrite ^/[_0-9a-zA-Z-]+$ $scheme://$host$uri/ permanent;

    # Directives to send expires headers and turn off 404 error logging.
    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires 24h;
        log_not_found off;

    # this prevents hidden files (beginning with a period) from being served
      location ~ /\.          { access_log off; log_not_found off; deny all; }

    # Pass uploaded files to wp-includes/ms-files.php.
    rewrite /files/$ /index.php last;

    if ($uri !~ wp-content/plugins) {
        rewrite /files/(.+)$ /wp-includes/ms-files.php?file=$1 last;

    # Rewrite multisite '.../wp-.*' and '.../*.php'.
    if (!-e $request_filename) {

        rewrite ^/[_0-9a-zA-Z-]+(/wp-.*) $1 last;
        rewrite ^/[_0-9a-zA-Z-]+.*(/wp-admin/.*\.php)$ $1 last;
        rewrite ^/[_0-9a-zA-Z-]+(/.*\.php)$ $1 last;


    location ~ \.php$ {
    # Forbid PHP on upload dirs
        if ($uri ~ "uploads") {
            return 403;

        client_max_body_size 25M;
        try_files      $uri =404;
        fastcgi_pass   unix:/var/run/php5-fpm.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        /etc/nginx/fastcgi_params;

Any ideas are welcome! Have I done something wrong? I have disabled Batcache to see if it makes any difference, but still no go.

share|improve this question

Wow, you've got a real mess on your hands.

Overall the nginx configuration looks good. The only thing that struck me on first reading as being possibly "wrong" was the try_files statement. In my production WordPress multisite, I have:

try_files $uri $uri/ index.php;

It's not necessary to append the args, as WordPress picks them up from REQUEST_URI when it is available, (almost always) and PATH_INFO when they aren't present in the query string.

Yes, I'm aware that the statement you are using is what's "recommended" on the WordPress site. Of course it's also a wiki that anybody can edit, so it has to be taken with a grain of salt, just like Wikipedia.

share|improve this answer
It seems my fastcgi_params file is incomplete, because there is no reference to PATH_INFO. Can you share your fastcgi_params? – UrkoM Sep 26 '12 at 0:45
Sorry, old Apache-isms surfacing in my brain when I wrote that. PATH_INFO isn't defined by default in nginx; you would have to explicitly define it. This isn't necessary for WordPress since it will receive the original REQUEST_URI anyway and use that. I've updated the answer. – Michael Hampton Sep 26 '12 at 0:52
Well, it seems to have made some difference: I removed Batcache and the APC object cache from the equation. I also added fastcgi_split_path_info and additional fastcgi_params (including PATH_INFO) from here: And now things are working! Now I need to look into getting back some of that speed boost that I was getting from Batcache and APC... – UrkoM Sep 26 '12 at 1:29
Ok, I just readded the APC object cache, and it's clear that this is what is causing the problems. There is definitely a key clash happening, with individual blogs overwriting each other's objects. – UrkoM Sep 26 '12 at 1:37
I found the ultimate solution, and it was, of course, a PEBKAC... See my own answer. Thanks in any case for your help! It did eventually send me in the correct path. – UrkoM Sep 27 '12 at 4:10
up vote 0 down vote accepted

Found the problem. It wasn't the rewrite rules, though Michael Hampton definitely set me in the right direction.

For some reason, the wp-config.php file had two very important lines for Multisite configuration commented out: PATH_CURRENT_SITE and BLOG_ID_CURRENT_SITE.

As soon as I fixed that, everything started working perfectly, and our site is now blazing fast. I guess the real question is: how the h*** did this work all this time?

That's it here. Thanks for watching!

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.