PHP APC on Debian Squeeze with Munin monitoring

Installing APC on Debian Squeeze is as simple as installing the package:

$ aptitude install php5-apc

In my case this package come from the PHP bundle distributed by the Dotdeb repository.

If installing APC is easy, monitoring it with Munin requires some extra manipulations. There is currently no good APC plugin available on Munin Exhange. So we’ll use the external munin-php-apc project instead.

The latter can’t get APC statistics by itself: it need an extra PHP file to be served locally. As you can read in my previous article, my Munin is powered by Nginx. So now we’ll setup Nginx to serve this extra PHP file:

$ mkdir -p /var/www/apc
$ cd /var/www/apc
$ wget http://munin-php-apc.googlecode.com/svn/trunk/php_apc/apc_info.php
$ chown -R www-data:www-data /var/www/apc

Then I need to update my /etc/nginx/sites-available/munin file (see details about this file on my previous article) to have the second server section look like this:

server {
  server_name localhost;
  include /etc/nginx/php.conf;
  root /var/www/apc;
  allow 127.0.0.1;
  deny all;
  location / {
    access_log off;
  }
  location /nginx_status {
    stub_status on;
    access_log off;
  }
}

Here the included /etc/nginx/php.conf file is the one in which I’ve concentrate all the Nginx directives required to activate PHP file parsing. The content and the mechanism behind this file is describe in my article on setting up Nginx with PHP-FPM.

Let’s get back to our Munin monitoring setup. I can restart now Nginx and check that I can access locally to my raw statistics:

$ /etc/init.d/nginx reload
$ wget http://localhost/apc_info.php
$ wget http://localhost/nginx_status

The last step is to install and configure the Munin plugin:

$ aptitude install libwww-perl
$ wget http://munin-php-apc.googlecode.com/svn/trunk/php_apc/php_apc_ --output-document=/usr/share/munin/plugins/php_apc_
$ chmod -R 755 /usr/share/munin/plugins/
$ ln -s /usr/share/munin/plugins/php_apc_ /etc/munin/plugins/php_apc_usage
$ ln -s /usr/share/munin/plugins/php_apc_ /etc/munin/plugins/php_apc_hit_miss
$ ln -s /usr/share/munin/plugins/php_apc_ /etc/munin/plugins/php_apc_purge
$ ln -s /usr/share/munin/plugins/php_apc_ /etc/munin/plugins/php_apc_fragmentation
$ ln -s /usr/share/munin/plugins/php_apc_ /etc/munin/plugins/php_apc_files
$ ln -s /usr/share/munin/plugins/php_apc_ /etc/munin/plugins/php_apc_rates
$ echo "[php_apc_*]
user root
env.url http://localhost/apc_info.php?auto
" > /etc/munin/plugin-conf.d/php_apc
$ /etc/init.d/munin-node restart

And finally, after a while, you’ll get those beautiful graphs:

e107 Importer plugin for WordPress v1.4 released !

I just released the version 1.4 of my e107 Importer plugin for WordPress.

This is a special release as it ends the active development cycle. I officially declare this plugin unmaintained. I don’t plan to work on it again.

The 1.4 will be the last version. Unless you send me code contribution, you’ll not see a 1.5 version.

The reason behind this decision is simple and straightforward: I’ve recently migrated my last e107 website to WordPress. Now that e107 is no longer part of my life, I have no interest in spending time and energy working on this plugin.

So if you plan to get rid of your e107 sites in favor of WordPress, do the migration now, as the plugin will self-deteriorate as WordPress API gets updated.

Nginx + PHP-FPM + MySQL on a Debian Squeeze server

This post is not about optimization: it only describe a sure and fast way to get all those 3 components talk to each other. This article will help you bootstrap a minimal setup, something that I wouldn’t recommend for a production server without serious tweaking (to get both high performances and security).

First, we’ll get all our packages from an up-to-date DotDeb repository. If this is not already done, add those repositories to aptitude:

$ echo "deb http://packages.dotdeb.org squeeze all" > /etc/apt/sources.list.d/squeeze-dotdeb.list
$ gpg --keyserver keys.gnupg.net --recv-key 89DF5277
$ gpg -a --export 89DF5277 | apt-key add -
$ aptitude update

Now we can install the whole stack:

$ aptitude install nginx
$ aptitude install php5-fpm php5-mysql php5-gd php5-curl
$ aptitude install mysql-server

FYI, here is the list of versions I installed:

  • Nginx 1.0.2
  • PHP 5.3.6
  • MySQL 5.1.57

As a way to test that our setup is working, we’ll serve a simple PHP file:

$ mkdir -p /var/www/example.com/
$ cd /var/www/example.com/
$ echo "
<?php phpinfo(); ?>
" > ./index.php
$ chown -R www-data:www-data /var/www

Now let’s create a minimal Nginx configuration file for this site:

$ touch /etc/nginx/sites-available/example.com

In this brand new file, put the following directives:

server {
  server_name example.com;
  include /etc/nginx/php.conf;
  location / {
    root /var/www/example.com/;
    access_log on;
  }
}

This will only work if you’ve updated your DNS with an A record having example.com redirecting to the IP address of your Nginx server.

Now it’s time to create the /etc/nginx/php.conf file referenced in the Nginx configuration above. This file is where I put the generic setup making the bridge between Nginx and PHP-FPM. Here is what it should contain:

index index.php index.html index.htm;

location ~ \.php$ {
  # Zero-day exploit defense.
  # http://forum.nginx.org/read.php?2,88845,page=3
  # Won't work properly (404 error) if the file is not stored on this server, which is entirely possible with php-fpm/php-fcgi.
  # Comment the 'try_files' line out if you set up php-fpm/php-fcgi on another machine.  And then cross your fingers that you won't get hacked.
  try_files $uri =404;

  fastcgi_split_path_info ^(.+\.php)(/.+)$;
  include /etc/nginx/fastcgi_params;

  # As explained in http://kbeezie.com/view/php-self-path-nginx/ some fastcgi_param are missing from fastcgi_params.
  # Keep these parameters for compatibility with old PHP scripts using them.
  fastcgi_param PATH_INFO       $fastcgi_path_info;
  fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

  # Some default config
  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_ignore_client_abort off;

  fastcgi_pass 127.0.0.1:9000;
}

Finally you can activate the site configuration and restart the whole stack:

$ ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
$ /etc/init.d/mysql restart
$ /etc/init.d/php5-fpm restart
$ /etc/init.d/nginx restart

If everything’s OK on your DNS, pointing your browser to http://example.com will show you the famous page produced by phpinfo():

Note that MySQL doesn’t need any special attention to make it work out of the box. But again, if you plan to use it in production, its configuration needs special care, as for Nginx and PHP.

Configuring Fail2Ban on Debian Squeeze

This always start with a package installation:

$ aptitude install fail2ban

Then I simply create a local configuration file where I’ll put all my custom config:

$ touch /etc/fail2ban/jail.local

Here is the content of that file:

[DEFAULT]
# Do not filter connexion from my apartment and from the server itself
ignoreip  = 127.0.0.1 88.123.123.123 91.123.123.123
# Ban for a week
bantime   = 604800
maxretry  = 3
destemail = kevin@deldycke.com
banaction = iptables-allports
action    = %(action_mwl)s

[ssh]
enabled  = true
port     = 22
maxretry = 2

[ssh-ddos]
enabled = true
port     = 22

[apache]
# Apache basic auth
enabled   = true
maxretry  = 3
# Ban for 1 hour
bantime   = 3600

[apache-noscript]
enabled = true

[apache-overflows]
enabled = true

[apache-badbots]
enabled  = true
filter   = apache-badbots
port     = http,https
action   = iptables-allports
logpath  = /var/log/apache*/*access.log
maxretry = 1

[apache-nohome]
enabled  = true
filter   = apache-nohome
port     = http,https
action   = iptables-allports
logpath  = /var/log/apache*/*access.log
maxretry = 1

[exim]
enabled  = true
filter   = exim
port     = smtp,ssmtp
action   = iptables-allports
logpath  = /var/log/exim*/rejectlog
maxretry = 1

[exim-relay]
enabled  = true
filter   = exim-relay
port     = smtp,ssmtp
action   = iptables-allports
logpath  = /var/log/exim*/rejectlog
maxretry = 1

While adjusting Fail2Ban, I was surprised by how sensitive this software is. It can just refuse to start without any notice in the log or on the command line. Even if its log_level variable is set to 4 (= DEBUG) in /etc/fail2ban/fail2ban.conf.

In such a case, a sure way to find the culprit is to use a brute force debugging method: first set all the enabled variable of your jail.local‘s sections to false. Then activate one section after another until Fail2Ban refuse to restart.

For me, the problem was that I forgot to add my custom exim-relay filter to Fail2Ban. So I fixed my issue by creating an empty file at /etc/fail2ban/filter.d/exim-relay.conf in which I pasted the following content:

# Based on default exim.conf filter by Cyril Jaquier
# Real life exemaple:
# 2009-07-02 08:16:42 H=118-167-129-21.dynamic.hinet.net (91.121.198.84) [118.167.129.21] F=<titieueue@hotmail.com> rejected RCPT <s2288@mail2000.com.tw>: relay not permitted

[Definition]

# Option:  failregex
# Notes.:  regex to match use of my exim mail server as a relay it does not
#          allow.
# Values:  TEXT
#
failregex = \[<HOST>\] .*(?:relay not permitted)

# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
#
ignoreregex =

Speaking of custom filters, here is one to filter DFind scans (file located at /etc/fail2ban/filter.d/apache-w00tw00t.conf):

# Based on http://howflow.com/tricks/block_w00tw00t_scan_hosts_with_fail2ban
# Real life exemaple:
# [Sat Jun 27 16:43:08 2009] [error] [client 94.23.57.77] client sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): /w00tw00t.at.ISC.SANS.DFind:)

[Definition]

# Option:  failregex
# Notes.:  regex to match the w00tw00t scan messages in the logfile.
# Values:  TEXT
failregex = ^.*\[client <HOST>\].*w00tw00t\.at\.ISC\.SANS\.DFind.*

# Option:  ignoreregex
# Notes.:  regex to ignore. If this regex matches, the line is ignored.
# Values:  TEXT
ignoreregex =

And here is the corresponding section from my jail.local file:

[apache-w00tw00t]
enabled  = true
filter   = apache-w00tw00t
action   = iptables-allports
logpath  = /var/log/apache*/*error.log
maxretry = 1

Cool Cavemen WebDesign Retrospective

Here is a collection of all themes I created for the Cool Cavemen website over the years.

Before settling on its current name, the Cool Cavemen project was referred to by its members as The Ultimate Band (talk about rock-star egos…). Here is a screenshot of the theme I did for e107:

In fact the original HTML mockup this theme is based on still exists. It is dated back to November 1st, 2004, which is now the official Cool Cavemen anniversary. The theme above was created two weeks later.

When I created the Cool Cavemen’s site, I choose e107. Back then I perceived it to be the only Open Source PHP-based CMS having the best balance between a clean and a powerful theme engine. That was my opinion before decided to switch to WordPress.

At the end of November ’04, our theme was updated to this:

The header above is based on a photo of a green laser, that was taken by Cool Cavemen’s guitarist.

2005 started with an updated version of the theme, featuring a photo of Cool Cavemen’s first gig. They were only three on stage, our bass player was still drumming at the time:

In February we finally had our official photo featuring all members of the band ! But it was cold outside so we added some fur to keep our website warm:

I spent the next months trying to build my own version of the Holy Grail: a perfect CSS-based 3-columns fluid layout (with a middle column placed in the top of the HTML). This explain Eric Mayer‘s quote in these mockups and the references to the Skidoo Too template:

I never found the Holy Grail, and the tests above remained unseen by the public. Tired by this journey, I never touched the theme again.

Until September 2005 when I updated it to this:

Notice the box in the top of the right column, which was designed to publish a new track every week. The code behind this box is available in another article.

So that was the last major version of the theme. Basically our e107 site looked that way for most of its life.

In November 2005 I attempted to reboot the theme. I made these 3 propositions to the band:

The last one had an interactive header, with tiny sketches showing up on mouse over:

Unfortunately we didn’t found any of these themes matching the Cool Cavemen spirit (whatever that is). If these alternatives were publicly discussed, we decided that no one was going to replace our previous theme.

The final update we made was when our Raw EP was released. We basically applied filters on the header to match Raw’s cover. We also updated our logo to use the one designed for us by QPX:

e107 Importer v1.3 released

A month after the last one, here is a brand new version of my e107 Importer, numbered 1.3.

This version add loads of polishing and is not far from being feature-complete. I think I’m reaching the end of the active development of this plugin. I don’t see the need to add new features.

I also feel this way because last week, I succeeded in moving to WordPress all news and pages from the old e107′s Cool Cavemen website. I now only need to import all forums to definitively get rid of e107 from my life. At that point, I will declare the plugin no longer active. This mean I will no longer update it, but will still integrate code other developers are willing to contribute.

Before that happen, I will of course release one or two revisions of this plugin in the next few months. But expect bug fixes and tiny enhancements, not big new features.

That being said, here is the changelog of the brand new e107 Importer 1.3:

  • Upgrade embedded e107 code with latest 0.7.25.
  • Redirect imported images to attachments.
  • Purge invalid mapping entries on import.
  • Replace old e107 URLs in content by new WordPress permalinks.
  • Allow both imported and already-existing content to by updated with new permalinks.
  • Let user specify the list of e107 forums to import.
  • Phased imports should work without major problems.