Apache 2.2 on Debian Wheezy w/ PHP-FPM, FastCGI, APC and a kind of suEXEC

comments 13
Apache / Debian / PHP

won’t talk about pros and cons of PHP-FPM, FastCGI, APC and all that stuff, there are tons of articels around, see also the links below.

main urge was to speed up PHP with APC, get rid of preforked Apaches, run PHP scripts as their native user and many more.

just giving an overview how I’ve easily set it up here, having different “customers” programming their own PHP scripts and also Debian packages ready to run.


main requirements have been:

  • Opcode Cache
  • every PHP script should run as the same user the virtualhost is owned
  • Debian packages should still run as www-data
  • run Apache as MPM Worker


install all the required packages.

aptitude install apache2-mpm-worker libapache2-mod-fastcgi php5-fpm php-apc

enable needed modules.

a2enmod actions alias fastcgi


create config file for PHP-FPM and FastCGI in /etc/apache2/conf.d/php5-fpm.

# Configure all that stuff needed for using PHP-FPM as FastCGI

# Set handlers for PHP files.
# application/x-httpd-php                        phtml pht php
# application/x-httpd-php3                       php3
# application/x-httpd-php4                       php4
# application/x-httpd-php5                       php
<FilesMatch ".+\.ph(p[345]?|t|tml)$">
    SetHandler application/x-httpd-php
# application/x-httpd-php-source                 phps
<FilesMatch ".+\.phps$">
    SetHandler application/x-httpd-php-source
    # Deny access to raw php sources by default
    # To re-enable it's recommended to enable access to the files
    # only in specific virtual host or directory
    Order Deny,Allow
    Deny from all

# Deny access to files without filename (e.g. '.php')
<FilesMatch "^\.ph(p[345]?|t|tml|ps)$">
    Order Deny,Allow
    Deny from all

# Define Action and Alias needed for FastCGI external server.
Action application/x-httpd-php /fcgi-bin/php5-fpm virtual
Alias /fcgi-bin/php5-fpm /fcgi-bin-php5-fpm
<Location /fcgi-bin/php5-fpm>
  # here we prevent direct access to this Location url,
  # env=REDIRECT_STATUS will let us use this fcgi-bin url
  # only after an internal redirect (by Action upper)
  Order Deny,Allow
  Deny from All
  Allow from env=REDIRECT_STATUS
FastCgiExternalServer /fcgi-bin-php5-fpm -socket /var/run/php5-fpm.sock -pass-header Authorization

for every PHP file a Handler will be set and also some access restrictions. for the Handler a virtual Action is defined. virtual here means it will not be checked if the given file exists. the Alias is needed in any case, especially later when you go for running PHP as an other user. be careful with the Alias directory-path, don’t use any slashes as described here.

at this point you should be already able to run PHP scripts with PHP-FPM as user www-data with APC enabled. but the main focus here is on running PHP scripts just as an other user. lets go forward.

let’s party

create a new user and add www-data into its group.

adduser --disabled-login tux
adduser www-data tux

create the documentroot and set permissions.

 mkdir -p /var/www/tux/htdocs
chown -R tux:tux /var/www/tux
chmod 755 /var/www/tux
chmod 750 /var/www/tuc/htdocs

looks like overkill to have only the htdocs directory, but be prepared for some directories like log, session, tmp, …

a small index.php for tux could have the following code. keep care of ownership and permissions.


splash into the pool

create an additional PHP-FPM pool for user tux by just copying www.conf.

user = tux
group = tux

listen = /var/run/php5-fpm-tux.sock

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

chdir = /

restart PHP-FPM.

service php5-fpm restart

check if new PHP-FPM instances are running.

ps -ef | grep php-fpm


root     12065     1  0 15:36 ?        00:00:00 php-fpm: master process [...]
www-data 12066 12065  0 15:36 ?        00:00:00 php-fpm: pool www
www-data 12067 12065  0 15:36 ?        00:00:00 php-fpm: pool www
tux      12068 12065  0 15:36 ?        00:00:00 php-fpm: pool tux
tux      12069 12065  0 15:36 ?        00:00:00 php-fpm: pool tux

create a virtual host config for which tux is the owner.

<VirtualHost *:80>
  ServerName tux.kmplabs.org

  ServerAdmin webmaster@kmplabs.org

  DocumentRoot /var/www/tux/htdocs
  <Directory /var/www/tux/htdocs/>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride None
    Order allow,deny
    Allow from all

  Alias /fcgi-bin/php5-fpm /fcgi-bin-php5-fpm-tux
  FastCgiExternalServer /fcgi-bin-php5-fpm-tux -socket /var/run/php5-fpm-tux.sock -pass-header Authorization

  ErrorLog ${APACHE_LOG_DIR}/error.log

  LogLevel warn

  CustomLog ${APACHE_LOG_DIR}/access.log combined


enable new virtual host and restart apache.

a2ensite tux
service apache2 restart

that’s it!


quick & dirty

use php-fpm with apache in debian (mod_fastcgi), en, 2013-02-02
Apache2 mpm worker + fastcgi + php5-fpm on debian, en, 2012-11-02
Apache Worker, FastCGI, PHP-FPM and APC, en, 2012-01-29

explaining differences, more in detail

installing apache + mod_fastcgi + php_fpm on …, en, 2011-04-08
PHP-FPM: Mit der Lizenz zum Verwalten, de, 2011-07-20
Apache2, PHP-FPM, FastCGI and APC Opcode Cache, fr, 2010-08-14

some ideas why to go for FastCGI and Opcode Cache

FastCGI with a PHP APC Opcode Cache, en, 2009-07-07


  1. Florian says


    this is a very nice howto.
    I have one question:
    Why do you add www-data into tux’s group? Is this not a security problem, because www-data now has again the same permissions like the folder has the group www-data?
    Do I need to add www-data to the users group?
    Is it possible to avoid this with suexec?

    Thank you very much!

  2. @Flo: I’m doing this in my own setup with Nginx/Lighttpd since ~2 years. It’s the best way to control permissions, because you can add whoever you wan’t to the users group for same access as the webserver. With the group permissions you can hide include-dirs or other internal stuff (like config file from web apps) from the webserver and/or others easily. You don’t need the world-role in permissions anymore. It’s just a great thing, because the user is the real owner of his web-directory – including his own group 🙂

    @Hödlmoser: “be careful with the Alias directory-path” – you saved my ass after hours of googl’ing. Stupid bug, realy 😛

  3. sarah goldfarb says

    Hi sorry to bother you first of all nice post, I have already set a working lamp with php5-fpm the only problem is to be able to highlight sources with phps extensions I try your config without deny from all on *.phps files I suppose I have to do something like

    Action application/x-httpd-php-source /fcgi-bin/php5-fpm virtual

    but what is the correct syntax ???? I found nothing on php5-fpm doc. I want to use source highlight as I want to share sources on a educationnal project do you manage to make highlitement working with php5-fpm ???? For now whenever I am using a GET on myserver.com/myscript.phps it is downloaded. Shame on me !

  4. Pingback: Vagrant: Disposable Symfony2 Dev boxes with full LAMP stack (Part 1 of 3) - If Developer

  5. Dominik says

    keep an eye on listen.owner and listen.group in fpm pool config! you need that properties since the latest security fix for php5!

  6. perry says

    BAM!!! I just ran through another setup using suexec – the object was similar to what you accomplished, but he wasn’t as specific about what went where, or why – or how to test things on your way through the setup. That guys setup might have some advantages, but I can’t see what they would be. The disadvantages was having scripts here and there to do this and that and the other thing … convoluted to say the least.

    You’rs just worked FLAWLESSLY first time through, no fixing errors like I was doing with the other one. I spent 2 hours messing with the other one, crashed my vps in the process … less than 30 min and I’m up and running THANK YOU SO MUCH!!!

  7. suberimakuri says

    Excellent thank you.

    If copying per user config from http://www.conf, remember to change the pool name as well.
    Else if you have multiple sites, they will fail trying to use the same pool name I believe.

    ; Start a new pool named ‘www’.
    ; the variable $pool can we used in any directive and will be replaced by the
    ; pool name (‘www’ here)

  8. Iskren Hadzhinedev says

    This is by far the most fine guide I’ve ever seen. Just a note for those who have Apache 2.4: Allow/Deny is deprecated and must be replaced as:

    Order Deny,Allow -> Require all denied
    Deny from All -> [delete line]
    Allow from env=REDIRECT_STATUS -> Require env REDIRECT_STATUS

  9. Perry says

    Ok, I’ve been using this setup for a while, mostly undisturbed except for adding a few sites. I just set it up on a newer machine running Debian 8 with Apache 2.4, and php 5.6 and looked a little closer at phpinfo output, and it raised a few questions.

    1. Php 5.6 has Zend Opcache built in, although it doesn’t have user caches. APC has user caches as well. APCu is only user caches, and can be used to augment Zend Opcache. So my question is – when I installed php-apc, does it override Zend Opcache and use APC instead, or is it now running Opcache with APCu? It appears that is running Opcache / APCu, and this is how I’d like it to be operating.

    2. I’ve never used suEXEC so forgive me if this is a dumb question … This method uses “a kind of suEXEC” – why not use suEXEC? Is it a security hole, or a pain to manage?

    3. Is there a relatively easy way to analyze performance of the opcache? A way to determine if the user maybe HAS a user cache, but the site is instead using the server-wide cache in error?

    • Hödlmoser says

      thanks for all your remarks concerning Debian Jessie and Apache 2.4. but I haven’t upgraded my Apache and its VM to Debian Jessie yet. so I’v no experience. when I go for upgrade I will update this post, for sure.

  10. Perry says

    Oh, and one more thing I wanted to add unrelated to the previous question:

    If you’re using Apache 2.4, DEFINITELY do what the guy above suggests, or it won’t work. The first setup I did in December was on 2.2 and went flawlessly. This time I beat my head against the wall changing this and that and the other thing – then I found the comment up there about 2.4 …

    Well by that time I had changed too much chasing the issue, so I wiped it out and started over – this time following Iskrens advice. His advice is solid, but it’s not 100% complete.

    In the php5-fpm config file, there are other places. His example uses the entry in , but above it there are two other entries in sections that have to be updated accordingly.

    In the virtualhost config file, there is an order allow/deny allow from all. Use the Apache 2.4 way here too:

    order allow/deny
    Allow from all

    becomes “Require all granted”

Leave a Reply

Your email address will not be published. Required fields are marked *