Arch Linux Apache 2.4 with PHP


Arch Linux recently updated the Apache HTTPd in it’s repositories from version 2.2.x to 2.4.x [1]. Taking into account that Arch Linux aims to be a bleeding-edge distribution, it is fairly surprising that this step first happens now. Apache 2.4 officially has been released over 2 years ago [2]. But okay, the 2.2 branch still is officially supported upstream, so whatever. I don’t want to cover this here.

Updating to Apache 2.4 brings a lot of improvements, but it will most likely break the setup for everyone who used Apache 2.2 (yes, really). Much internal stuff has been reworked, some configuration values has been removed, some new added, etc.

For a complete list of (especially backwards-incompatible) changes see [3]. That page already gives you a good impression about what you need to change to get your setup working with the 2.4 version. For most people, the replacement of the configuration entries Allow and Deny (e.g. Allow from all is now Require all granted) already creates a fair amount of manual intervention after the update.

But, all that stuff is already pretty well documented on the web. What I really want to cover here is the move from mod_php to php-fpm. mod_php was the default (or, better if I’d say: the easiest) way to make the Apache webserver handle PHP scripts in Apache 2.2. When moving to Apache 2.4, I wanted to replace mod_php with php-fpm. mod_php has some really big disadvantages (performance, security, …) compared to php-fpm. Additionally, to make mod_php work under Apache 2.4, PHP needs to be compiled with thread-safety, which is not the case in most distributions (and also not in Arch Linux currently). Or, if that is not possible, you would have to change the event-based-MPM, which became default in 2.4, back to the prefork-based-MPM (which was default in 2.2). Both was not an option for me (for various reasons), so I decided to go for php-fpm.

As it showed up, this move is not easily done. There are various ways to accomplish this, and either they are very complex to setup or they do not work completely (directory listings not working anymore, security concerns, …). There are tons of tutorials on the web of how to do this, but none of them really covered my special needs. This is why I am writing this article.

I will now give a brief explanation about how I set it up. In my opinion (after having tried several ways) this is currently the best solution (when you don’t agree, just put a comment and tell me why it’s not :P).

What I now will describe is generally applicable on every Apache 2.4 installation (regardless of the used Linux distribution and everything). Though, dependent on the exact distribution and/or your setup or requirements, you might have to adapt some paths and something. But as I am assuming that you know your system, this won’t be a problem for you.

By the way: I will not go very much in depth in this explanation. If you don’t have a basic idea about php-fpm pools or Apache virtualhosts (or other stuff that you don’t understand below), then you should inform yourself about these topics first. There are already good articles available on the web to that regard.

I also assume, that you already setup a php-fpm pool for every virtualhost you have (which is the recommended way to use php-fpm).

Additionally, you at least need the mod_fastcgi and mod_actions modules for Apache (which are not enabled by default).

So, let’s start!

First of all, create a new directory /srv/http/.php-fpm – this will be the directory Apache will use internally to route all calls to the php-fpm fastcgi handler. This is basically a way to fool Apache, but you might notice yourself later on.

Now adapt your virtualhost configurations. Put this line into every virtualhost configuration (adapt the 000-default part to something that identifies your virtualhost and/or make that unique for every virtualhost):

Alias /.php-fpm /srv/http/.php-fpm/000-default

As you a clever, you noticed, that this routes every request with is coming in to /.php-fpm into that directory we just created.

Okay, the next step is to create a new configuration file for Apache (e.g. /etc/httpd/conf/php-fpm.conf) and to include it in your httpd.conf (using Include conf/php-fpm.conf). The file should have the following content:

# Block direct access to .php-fpm and only allow it when coming through an internal rewrite chain
<LocationMatch "^\.php\-fpm|\/\.php\-fpm">
    Require all denied
    Require env REDIRECT_STATUS
</LocationMatch>

# Block direct access to the /srv/http/.php-fpm directory (this is only a security thingy, it should not be possible at all with the block above)
<Directory /srv/http/.php-fpm>
    Require all denied
    Require env REDIRECT_STATUS
</Directory>

# Tell Apache to handle all .php files with a new "php-fpm" handler
AddHandler php-fpm .php
# Tell Apache that the "php-fpm" handler should invoke a CGI script which is found under the path /.php-fpm (this is where our alias from the virtualhost configuration comes into play)
Action php-fpm /.php-fpm
# As this is not default in httpd.conf, set index.php also as an index file
DirectoryIndex index.html index.php

# fastcgi external server definition, the -socket part is coming from your php-fpm pool definition (you probably need an own line here for every virtualhost you have)
FastCGIExternalServer /srv/http/.php-fpm/000-default -socket /run/php-fpm/000-default.sock

So, as you see, basically what will happen is this:

  1. Apache notices it is going to handle a .php file
  2. It is invoking the php-fpm handler
  3. The php-fpm handler routes the request to /srv/http/.php-fpm/000-default (using a per-virtualhost alias)
  4. Apache notices that you have a fastcgi external server configured for that path
  5. The fastcgi external server is invoked and returns the result

That was all. You probably have to play a little bit around with the exact setup of the paths and thelike to fit your exact requirements. But as you know, I cannot really take that into account here.

I would really be glad to see any comments here! So when you don’t agree, when you have some questions, or when you just want to say something about this: Go ahead and write something! 🙂

Thanks, see you.

[1] = https://mailman.archlinux.org/pipermail/arch-dev-public/2014-March/025941.html
[2] = http://mail-archives.apache.org/mod_mbox/httpd-announce/201202.mbox/%3C2922160F-CBF2-4633-8B1E-C5045CC35918%40apache.org%3E
[3] = https://httpd.apache.org/docs/trunk/upgrading.html