WordPress with Nginx and PostgreSQL

It took a while, but it has finally become obvious to me that I need to spend less time making my blog work and more time doing interesting things to blog about. In other words, I need a blog that “just works”. WordPress.

The two complicating factors are that it needs play nice with nginx and postgres. The solution is to use FastCGI and the PostgreSQL for Wordpress (pg4wp) plugin.

We’ll need PHP, with CGI support and spawn-fcgi. On Gentoo:

echo "dev-lang/php cgi" >> /etc/portage/package.use
emerge php spawn-fcgi
# Go have a beer, PHP takes a long time to compile

First we need WordPress

# Create a directory for this installation
cd /var/www
mkdir new.russellhaering.com
cd new.russellhaering.com
# Download WordPress
wget http://wordpress.com/latest.tar.gz
# And extract it
tar -xf latest.tar.gz
rm latest.tar.gz

Then the pg4wp plugin

# Download
wget http://downloads.wordpress.org/plugin/postgresql-for-wordpress.1.1.0.zip
# Extract
unzip postgresql-for-wordpress.1.1.0.zip
# Install
mv postgresql-for-wordpress/pg4wp wordpress/wp-content/plugins/
cd wordpress/wp-content
cp plugins/pg4wp/db.php ./

Now we need to configure spawn-fcgi. Create /etc/conf.d/spawn-fcgi.wp which should look something like this

# The path to the socket
FCGI_SOCKET=/var/run/spawn-fcgi/russellhaering_com

# WordPress uses PHP
FCGI_PROGRAM=/usr/bin/php-cgi

# I believe that with the configuration below 1 child is fine
FCGI_CHILDREN=1

# It is convenient to run as nginx, but you could use a different user
FCGI_USER=nginx
FCGI_GROUP=nginx

# PHP will spawn off this many children
PHP_FCGI_CHILDREN=2

# Evidently PHP processes should be restarted every so often
PHP_FCGI_MAX_REQUESTS=500
ALLOWED_ENV="PATH PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS"

Then create an nginx vhost

server {
	listen 80;
	server_name new.russellhaering.com;

	index  index.php index.html index.htm;

	location / {
		root   /var/www/new.russellhaering.com/wordpress;  # absolute path to your WordPress installation

		# this serves static files that exist without running other rewrite tests
		if (-f $request_filename){
			expires 30d;
			break;
		}

		# this sends all non-existing file or directory requests to index.php
		if (!-e $request_filename) {
			rewrite ^(.+)$ /index.php?q=$1 last;
		}
	}

	location ~ \.php$ {
		fastcgi_pass   unix:/var/run/spawn-fcgi/russellhaering_com-1;  # port where FastCGI processes were spawned
		fastcgi_index  index.php;

		fastcgi_param  SCRIPT_FILENAME    /var/www/new.russellhaering.com/wordpress/$fastcgi_script_name;  # same path as above

		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_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/$nginx_version;

		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;

		# required if PHP was built with --enable-force-cgi-redirect
		fastcgi_param  REDIRECT_STATUS    200;

	}
}

Go ahead and start things up..

/etc/init.d/spawn-fcgi.wp start
/etc/init.d/nginx restart

Now you should be able to perform a fairly standard WordPress installation. Just use your Postgres database and password when it asks for DB info (or when modifying the config file).