---
author:
    email: mail@petermolnar.net
    image: https://petermolnar.net/favicon.jpg
    name: Peter Molnar
    url: https://petermolnar.net
copies:
- http://web.archive.org/web/20120223230828/http://petermolnar.eu:80/linux-tech-coding/nginx-config-for-wordpress-network/
lang: en
published: '2012-02-10T08:52:59+00:00'
summary: Easy and clean nginx config for a secure WordPress Network.
tags:
- WordPress
title: nginx config for a WordPress Network

---

The real bottleneck of a WordPress Network is that the static files of
the sub-blogs will be served by PHP - unless you write some tricky
rewrite rules. The drawback? This is not automatic; each sub-blog will
require a new entry, but it falls back safely to the original, PHP based
serving if blog is not mapped yet.

**Note**: PHP-FPM is required, otherwise this config will *not* work.
That's going to be in an other entry, it's not here.

nginx is still marvellous and it's config is getting incredibly easy and
nice. For example, this config is enough to run a WordPress site on port
80 and 443 with SSL enabled only on 443.

``` {.apache}
# if nginx map module is available, this can be used to serve the
# static files from sub-blogs of a network directly with nginx
# instead of PHP
# this reduces page load time and server load as well
#
# left: sub-blog domain
# right: the number of the sub-blog in WordPress Network
map $host $wordpress_network_blog_dir {
    default                         0;
    subblog1.your-domain.com        1;
    subblog2.your-domain.com        2;
}


server {
    ## Ports
    listen          80;
    listen          443  ssl;

    ## SSL certs
    ssl_certificate         /etc/ssl/yourcert.crt;
    ssl_certificate_key     /etc/ssl/yourcert.key;

    ## server name
    # . acts as wildcard
    server_name     .your-domain.com;

    ## root
    root            /path/to/your/root/;

    ## global rewrites
    # WordPress Network sites files (map is above)
    if ( $wordpress_network_blog_dir!= 0 )
    {
        rewrite ^/files/(.*)$ /wp-content/blogs.dir/$wordpress_network_blog_dir/files/$1 last;
    }
    # fallback if site is not mapped
    if ( $wordpress_network_blog_dir= 0 )
    {
        rewrite ^(.*)/files/(.*)$ /wp-includes/ms-files.php?file=$2 last;

    }

    ## locations
    location / {

        # enable browser cache for images
        # not location, because this applies for PHP served images as well in WP Network
        if ( $uri ~ .(ico|gif|jpg|jpeg|png)$  ) {
            expires 30d;
            add_header Pragma public;
            add_header Cache-Control "public, must-revalidate, proxy-revalidate";
        }

        # enable browser cache for css / js
        # not location, because this applies for PHP served files as well in WP Network
        if ( $uri ~ .(css|js)$  ) {
            expires 7d;
            add_header Pragma public;
            add_header Cache-Control "public, must-revalidate, proxy-revalidate";
        }

        # default uri
        try_files $uri $uri/ @rewrites;
    }

    # rewrite rules
    location @rewrites {
        rewrite ^(.*)$ /index.php?q=$1 last;
    }

    ## hide files starting with .
    location ~ /. {
        deny all;
        log_not_found off;
    }

    ## enable nginx status screen, optional
    location /nginx_status {
        stub_status on;
    }

    ## pass to PHP5-FPM server in the background
    location ~ .php {
        fastcgi_param   QUERY_STRING            $query_string;
        fastcgi_param   REQUEST_METHOD          $request_method;
        fastcgi_param   CONTENT_TYPE            $content_type;
        fastcgi_param   CONTENT_LENGTH          $content_length;
        fastcgi_param   SCRIPT_FILENAME         $document_root$fastcgi_script_name;
        fastcgi_param   SCRIPT_NAME             $fastcgi_script_name;
        fastcgi_param   REQUEST_URI             $request_uri;
        fastcgi_param   DOCUMENT_URI            $document_uri;
        fastcgi_param   DOCUMENT_ROOT           $document_root;
        fastcgi_param   SERVER_PROTOCOL         $server_protocol;
        fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
        fastcgi_param   SERVER_SOFTWARE         nginx;
        fastcgi_param   REMOTE_ADDR             $remote_addr;
        fastcgi_param   REMOTE_PORT             $remote_port;
        fastcgi_param   SERVER_ADDR             $server_addr;
        fastcgi_param   SERVER_PORT             $server_port;
        fastcgi_param   SERVER_NAME             $server_name;
        # PHP only, required if PHP was built with --enable-force-cgi-redirect
        fastcgi_param   REDIRECT_STATUS         200;

        fastcgi_index                           index.php;
        fastcgi_connect_timeout                 60;
        fastcgi_send_timeout                    180;
        fastcgi_read_timeout                    180;
        fastcgi_buffer_size                     128k;
        fastcgi_buffers                         4       256k;
        fastcgi_busy_buffers_size               256k;
        fastcgi_temp_file_write_size            256k;
        fastcgi_intercept_errors                on;
        fastcgi_split_path_info ^(.+.php)(/.*)$;
        fastcgi_pass    127.0.0.1:9000;
    }
}
```

When a new site is added into WordPress, a directory is created for it
inside wp-content/blogs.dir/, with the same number the site was added to
the system. This is the number I've called
\$wordpress\_network\_blog\_dir in the config above.

Feel free to ask question if there are.