WordPress Multisite with nginx (subdomain/wildcard domain ver.)

WordPress Multisite, previously known as WordPress MU (Multi User), is an application which allows hosting multiple WordPress blogs with just one installation. Instead of creating copies of WordPress for each users’ blogs, one can use one installation of Multisite to be used by multiple users, each with their own blogs. Personal/custom domain is also possible as used for this blog (this blog’s master site is genshiken-itb.org). Too bad, the official documentation only provided guide for installing on Apache. If you haven’t known, I usually avoid Apache – I simply more proficient with nginx. Of course, this blog is also running on nginx therefore it’s perfectly possible to run WordPress Multisite on nginx.

At any rate, reading the official documentation is still a must and this post will only cover the nginx version of Apache-specific parts (namely Apache Virtual Hosts and Mod Rewrite and .htaccess and Mod Rewrite) and only for subdomain install. Subdirectory one will or will not follow some time later.

Assuming you have working nginx and php-cgi (with process manager like php-fpm or supervisord), for starter you’ll want to create a specific file for this WP install. Let’s say this file named app-wordpress.conf. Obviously you have put WordPress installation somewhere in your server. In this example I put the files in /srv/http/genshiken-itb.org/.php/wordpress. Its content:

client_max_body_size 100m;
root /srv/http/genshiken-itb.org;
location /. { return 404; }
location / {
  root /srv/http/genshiken-itb.org/.php/wordpress;
  index index.php;
  try_files $uri $uri/ /index.php?$args;
  rewrite ^/files/(.*) /wp-includes/ms-files.php?file=$1;
  location ~ .php$ {
    try_files $uri =404;
    fastcgi_pass unix:/tmp/php-genshiken.sock;
    fastcgi_read_timeout 600;
    fastcgi_send_timeout 600;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    include fastcgi_params;
  }
}

Simple enough. Actually, it’s exact same with normal WordPress install except one extra line:

rewrite ^/files/(.*) /wp-includes/ms-files.php?file=$1;

And you’re set. Note that I set fastcgi timeouts higher than default to work around the slow performance of Amazon EC2 Micro Instance. Should only needed on network upgrade and massive blog import.

Anyway, in your main nginx.conf file, put:

server {
  listen 80;
  server_name *.genshiken-itb.org;
  include app-wordpress.conf;
 }

In proper place. The usefulness of separate file for WordPress configuration will become apparent once you want to tweak performance for some blogs. I’ll explain that later if I feel like to.

no-www for nginx

If you happen to be in no-www camp and want to redirect people accessing www.whateverdomain.com to the no-www version but have lots of domain, instead of writing one by one and you’re not keen in using config generator (I’m not), you can use this:

server {
  listen 80;
  listen [::]:80 ipv6only=on;
  server_name ~^www.(?<domain>.+)$;
  rewrite ^ $scheme://$domain$request_uri? permanent;
  access_log /var/log/nginx/access-no_www.log;
}

Remove listen [::]:80 ipv6only=on; if you’re not using IPv6 and adjust the log file path to wherever you want (or just turn off or remove it altogether).

Note that this trick doesn’t work well with HTTPS/SSL domains since you’ll get big fat warning about incorrect domain name in certificate or about self-signed certificate if you’re using wildcard one.

Forcing SSL with nginx and Apache

Not really difficult but I guess it would be useful for some people.

First one is for nginx: create a file called `force-ssl.conf` and put in nginx’s config directory (check by `nginx -V`). And its content is:

if ($scheme = http) {
rewrite ^ https://$host$request_uri? permanent;
}

Include this file (by `include force-ssl.conf;`) in any `location … { }` block you want to force SSL on.

As for Apache, we can do it by using the usual `.htaccess` (and put in corresponding directories):

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}

The nginx rule is written by me, Apache rule is written by [someone on internet](http://joseph.randomnetworks.com/2004/07/22/redirect-to-ssl-using-apaches-htaccess/) with minor fix on skipping regex capture (`(.*)` replaced by `^`).