Switching to nginx and php-fpm, so LAMP becomes LEMP

About two and a half years ago i ordered a virtual server for private purposes at Server4you. That was quite a long time ago and in the meantime you can get the same server for less money or a better server for the same price 😉
As migrating from an old productline to a new one isn’t possible at Server4you I decided to order a new server and migrate all my services to it so that i can quit the old machine afterwards.

And here we go:
LAMP (Linux, Apache, MySQL and PHP) is quite common and i also used this setup (Apache with mod_php) for hosting some small websites on my old server. The planned migration made me think about alternatives and I crawled through many blogposts about NGINX – a webserver which gains more and more popularity in our days (see this survey for more details).
Therefor i decided to give it a try and that’s where LEMP comes from (NGINX is pronounced as Engine-X)

Another new thing i wanted to try out is the integration of PHP in a different way. A project called PHP-FPM (FastCGI Process Manager) adds some new features to the ’normal‘ FastCGI implementation. It’s more or less a patch for the PHP sourcecode and it seems like it will go directly to the PHP core with PHP version 5.3.3.

After a bit of compilation and writing some scripts to automate this for future use all the websites (mostly WordPress) run on my LEMP setup. To get SEO-friendly URLs with WordPress on nginx is a bit more tricky than before, because .htaccess files are not beeing parsed by nginx, but the effort is really worth it.

Here is a related snippet from my nginx configuration file for this blog (slightly modified):

server {
listen 80;
server_name www.schmalenegger.com;

access_log /logs/schmalenegger.com_access.log;
error_log /logs/schmalenegger.com_error.log;

location / {

root /var/www/schmalenegger.com/;
index index.php index.html;

# Basic version of WordPress parameters, supporting nice permalinks.
include /etc/nginx/wordpress_params.regular;
}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9999;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
include /etc/nginx/fastcgi_params.default;
fastcgi_param SCRIPT_FILENAME /var/www/schmalenegger.com/$fastcgi_script_name;
}
}

And this is the content from /etc/nginx/wordpress_params.regular:

# WordPress pretty URLs:
if (-f $request_filename) {
break;
}
if (-d $request_filename) {
break;
}
rewrite ^(.+)$ /index.php?q=$1 last;

To be honest, I didn’t measure the differences between the performances of both setups, but I can really feel, that the webpages are being loaded much faster than before and also the memory consumption of nginx is absolutly awesome. So I’m quite happy with this new setup, but sometimes there are still some pitfalls to deal with.

Migration finished

As I wrote in the last post i was thinking about migrating back to wordpress. The steps are almost done. I don’t use categories anymore and the few links i had were added manually after the db-migration. What’s still left to do is to look for a nice theme and install some nifty plugins.

Thoughts about migrating (back) from Drupal to WordPress

Here’s something I found on this webpage related to a Drupal2Wordpress database migration:

prerequisites:

  • A fresh and clean installation of WordPress
  • Drupal database name: drupal (no table-suffix)
  • WordPress database name: wordpress (table-suffix ‚wp_‘)

Fire up the mysql cli:

USE wordpress;
DELETE FROM wp_posts ;
DELETE FROM wp_comments;
INSERT INTO wp_posts( ID, post_author, post_date, post_content, post_title, post_excerpt, post_name, post_modified )
SELECT a.nid, 1, FROM_UNIXTIME(a.created), b.body, a.title, b.teaser, concat('OLD',a.nid), FROM_UNIXTIME(a.changed)
FROM drupal.node as a, drupal.node_revisions as b
WHERE a.nid = b.nid AND (a.type='blog' OR a.type='page' OR a.type='story' OR a.type='forum');
INSERT INTO wp_comments ( comment_post_ID, comment_date, comment_content, comment_parent )
SELECT nid, FROM_UNIXTIME(timestamp), concat(subject,' ', comment), thread FROM drupal.comments ;

For the last part I wrote a perl-script, because the statement needs to iterate over all posts and calculate the related amount of comments. For getting this to work the user who runs the script needs to be able to login without a password to mysql. This can e.g. be achieved by a .my.cnf file in the home directory of the user.

#!/usr/bin/perl

@postids = echo "select ID from wp_posts" | mysql wordpress;

foreach (@postids) {
if ($_ == "ID") { next }
print $_;
system "echo 'UPDATE wp_posts SET comment_count = (SELECT count(*) from wp_comments where comment_post_ID = $_) where ID = $_;' | mysql wordpress";
system "echo 'SELECT comment_count from wp_posts where ID = $_;' | mysql wordpress";
}

I wrote this in a very short amount of time and I know it’s very dirty, but it works 🙂

Things that are still missing:

  • User migration
  • Post and Comment Formating
  • Categories

WordPress with lighttpd

A few days ago I switched the webserver for schmalenegger.com from Apache2 to lighttpd. Here’s a short guide what needs to be done to get lighttpd running with WordPress:

As I use Debian Etch, I decided to give to lighty packet from the Debian repositories a shot.


apt-get install lighttpd php5-cgi

After installation the webserver needs to be configured. This is done in the file /etc/lighttpd/lighttpd.conf.


#Load the FastCGI-Modul
server.modules = (
"mod_fastcgi",
)

#Configure PHP
fastcgi.server = ( ".php" =>
(
( "bin-path" => "/usr/bin/php5-cgi",
"socket" => "/tmp/php.socket",
"min-procs" => 1,
"max-procs" => 3,
"max-load-per-proc" => 3,
"idle-timeout" => 20 )
)
)

That should be sufficient for running WordPress. Just put your WordPress files under the configured server.document-root from lighttpd.conf and point your webbrowser to your domain.

But what about permalinks?

lighttpd has something called conditions. You can also use them for separating different sites from each other on the same server (Virtual-Hosts in Apache), but also Rewrite Rules can be configured there. So first of all make sure, that the Rewrite-module gets loaded from lighty and add mod_rewrite to the list of modules:


server.modules = (
"mod_rewrite",
)

Then configure some conditions (replace the domains with your own)


# Conditions for different sites
$HTTP["host"] =~ "^(www.)?(schmalenegger.com)$" {
server.document-root = "/www/schmalenegger.com/"
accesslog.filename = "/logs/schmalenegger.com-access.log"
url.rewrite-once = (
"^/(wp-.*)$" => "$1",
".*\.(txt|php|xml|js|ico|gif|jpg|png|css|swf)?.*$" => "$0",
"^([^?]*)?(.*)$" => "/index.php$2"
)
}

Duplicated searchresults when using EventCalendar3 in WordPress

If you use the Eventcalendar Plugin in WordPress you may experience duplicated or even more searchresults if a blogpost is in more than one category. To get rid of this problem change the following in eventcalendar3.php:

function ‚ec3_filter_posts_where‘ add the following to the first if statement


|| $wp_query->is_search

It should look like this afterwards:


if($wp_query->is_page || $wp_query->is_single || $wp_query->is_search )