apache2 with fcgid

Michael Kaufmann edited this page Mar 29, 2017 · 1 revision


Why setting up PHP with suexec?

Because you can run PHP with different users according to the vHost, which means its easier to protect each vHost from attacks by another vHost. On the other site there are no more problems between permissions of the FTP- and the Webserver-user or compromised hosts.

Why FastCGI?

Running PHP as a CGI would require reloading the PHP binary for every request which would lead to a massive overhead. This is why there is FastCGI, it loads the binary only once and hands requests to PHP by redirecting stdin and stdout by pipes/sockets.

Why mod_fcgid?

The old mod_fastcgi doesn't seem to be in development anymore and wasn't released under the GPL. mod_fcgid http://fastcgi.coremail.cn/ is the implementation of the FastCGI protocol under the GPL, its actively developed and has a better process management (Supports MPM and Thread Management).


  • Fast + Secure. PHP is thread safe that way so you can use Apache mpm-worker for better performance.
  • Individual php.ini per customer
  • No permission problems between the FTP- and Webserver-users


  • Complex to set up
  • Wrong installations can cause more security holes than using the original mod_php5 module
  • A lot of RAM is used when there are a lot of vHosts (can be limited slightly)

I assume that you have Froxlor already running and the database set up.

Setting up the environment

First you should ensure that the Froxlor cronjob isn't executed while you set up mod_fcgid. This could produce unwanted results!

/etc/init.d/cron stop

In order to have suexec work, you need real usernames as suexec cannot work with virtual user IDs Froxlor uses. We must get libnss-mysql to read users from MySQL. The FTP table in the Froxlor database provides us with every information we need. To avoid any bottlenecks that might happen with big directories we install the name service caching daemon 'nscd'.

apt-get install libnss-mysql nscd

Now copy and paste the actual configuration files from the Froxlor panel and apply them to your file system. You'll need the to create or update the following files (templates in your Froxlor panel in menu: "Configuration"):

  • /etc/nss-mysql-root.conf
  • /etc/nss-mysql.conf
  • /etc/nsswitch.conf

Make sure that only root can read those configs since they include your Froxlor database password!

chmod 600 /etc/nss-mysql.conf /etc/nss-mysql-root.conf

Restard nscd now

/etc/init.d/nscd restart

Now it should already work. To find out if it really works just go to a directory that was created by Froxlor and check if the user ID got replaced by the username.

ls -al /var/customers/webs/

This should produce a result like:

drwxr-xr-x  3 web1      web1       4096 2008-06-13 17:18 web1
drwxr-xr-x  8 web2      web2       4096 2009-01-02 17:40 web2
drwxr-xr-x 10 web3      web3       4096 2009-01-25 13:33 web3

If you don't see a result like this or just the virtual user IDs, check your configs and if the users really exist. If nscd isn't working properly you cannot continue with the next steps.

Setting up suexec

On the very first beginning I want to explain some general things about suexec since this produces the most confusion. If you specify the SuexecUserGroup directive in a vHost in combination with a directory which has the ExecCGI option enabled, the suexec module will first switch its user ID in a new thread if a new client has connected. After that the starter script will be executed to set up some environment options for the CGI binary, which is PHP in our case. This starter script will then run the PHP CGI binary. In order that this works it must be possible for the PHP process to communicate with Apache to redirect its in and output (stdin/stdout). This is the normal behavior for all CGI applications. In our case this redirection is managed by FastCGI/mod_fcgid.

Independent of the options with which suexec has been compiled you can store the files of the customers wherever you want. I recommend to store all of them under the default path (/var/customers/webs/). And also Froxlor should be within this directory, so its easier for you to manage all in all.

Never store the customer files beside the php.ini and starter directory, this is a security problem! The customer could be able to modify security relevant settings. On the other site Froxlor will override this settings anyway if something has changed.

Please don't forget that the starter scripts must be always stored under the path with which suexec has been compiled. This is a security feature of suexec, so don't try to hack it. If you need to modify the original path, recompile suexec on your own.

This howto was created for the default options from Debian, Ubuntu and SuSE so you don't need to compile anything new. To find out which is the default path for your suexec binary, run

apt-get install apache2-suexec
/usr/lib/apache2/suexec -V

For Debian this could produce a result like this. Important is the path specified in AP_DOC_ROOT.

-D AP_DOC_ROOT="/var/www"
-D AP_HTTPD_USER="www-data"
-D AP_LOG_EXEC="/var/log/apache2/suexec.log"
-D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
-D AP_USERDIR_SUFFIX="public_html"</pre>

Using the default suexec binary

You can continue with this section if you use a distribution like Debian, Ubuntu or SuSE. If you use /var/www/ as the place to store your starter scripts you can use the standard suexec binary that comes with your distribution. (If you don't use /var/www/ as the place to store your starter scripts, you can see section Using-suexec-custom) I recommend that by the way! If you wonder why suexec isn't called suexec2 on Debian, don't worry - the versions are correct, just the binaries got renamed.

Enable suexec (otherwise apache won't know the directive SuexecUserGroup) by typing this in a root shell:

a2enmod suexec

Now restart Apache with

/etc/init.d/apache2 restart

If you don't see any new errors or warnings than without suexec you can continue with the next section. Otherwise check the logs, they will help you.

Using suexec-custom

(debain wheezy/jessie based instructions) Install the suexec-custom package

apt-get install apache2-suexec-custom

If you use the normal suexec binary, apt-get shall remove suexec first and than install suexec-custom. After the Installation you can (normaly) edit this file "@/etc/apache2/suexec/www-data@"

The file contains 2 important lines: /var/www/ public_html/cgi-bin

# /Path/to/store/your/fcgi-scripts/
# (please expand) I don't know, but comment it out like this ''#public_html/cgi-bin''

Enable suexec (otherwise apache won't know the directive SuexecUserGroup) by typing this in a root shell:

a2enmod suexec

Now restart Apache with

/etc/init.d/apache2 restart

Now follow the next steps and customize the fcgi path in Froxlor

Enable fastcgi in Froxlor

You'll now have to tell Froxlor to create the starter scripts and the correct directives in the vHosts. Do this by activating the option Include PHP via mod_fcgid/suexec in the control panel options (just enable FCGID in the settings page). All other options for this module should be all ok by the default values. Just check if FCGIWrapper is enabled for the inclusion of the starter scripts in the vHosts - this is the easiest solution to get it running.

Setting up mod_fcgid

Now we need to install and enable mod_fcgid

apt-get install libapache2-mod-fcgid
a2enmod fcgid

Restart apache to enable the prvious installed modules

/etc/init.d/apache2 restart

Running PHP as FastCGI

First we need the PHP CGI binary. Install it via

apt-get install php5-cgi

Make sure that everything is ok by running

php-cgi -v

The output should be similar to this:

PHP 5.6.30-0+deb8u1 (cgi-fcgi) (built: Feb  8 2017 08:50:21)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2006 Zend Technologies
   with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

It's important that you can find cgi and fcgi or fcgid in the output, otherwise something went wrong. If you don't see the output of Suhosin its ok - that is just a security patch for PHP. (My recommendation is to use this patch!)

Setting up the Froxlor vHost

Now that we have all set up, we will enable suexec for Froxlor.

Froxlor user creation

I think having an own user for Froxlor is a nice solution as we don't want FTP access for it anyway.

useradd -s /bin/false -U froxlorlocal

The Start-script and php.ini for Froxlor will automatically be generated by Froxlor itself.

To enable this setting, login as Admin, visit the Settings-Menu (Submenu FCGID) and check the "Enable FCGID for the Froxlor vhost" box.

You need to make the Froxlor-Directory readable for the fcgid-enviorment.

chown -R froxlorlocal:froxlorlocal /var/www/froxlor

Now reload the Apache configuration and open Froxlor in your browser.

/etc/init.d/apache2 restart

Log into Froxlor and check the Webserver-Interface for CGI-FCGI. Froxlor now runs under the froxlorlocal user!

Final Steps

After all is working make sure to disable the default mod_php5 modules in Apache. Otherwise this would be a security hole in your new setup!

a2dismod php5

Get into Froxlor and klick Rebuild Configuration Files.

Force the cronjob once to run to create the fcgi settings for all domains

/usr/bin/php5 /var/www/froxlor/scripts/froxlor_master_cronjob.php --force --debug

Don't forget to start Cron again.

/etc/init.d/cron start

If you have set up all correctly it should be now possible to open the customer domains in your browser. If there are PHP child processes under the Apache process all is working fine. You can also check that by running phpinfo(); from a file within a customer domain.

To check if there are child processes, run

ps faux

This should produce a result like this:

root     18486  0.0  0.5  21896 10772 ?        Ss   Jan25   0:00 /usr/sbin/apache2 -k start
www-data 18681  0.0  0.3  20824  7692 ?        S    Jan25   0:00  \_ /usr/sbin/apache2 -k start
www-data 18682  0.0  0.3  21156  7740 ?        S    Jan25   0:00  \_ /usr/sbin/apache2 -k start
web1     18969  0.0  0.4  19952  8216 ?        S    Jan25   0:21  |   \_ /usr/bin/php5-cgi -c /var/www/php-fcgi-scripts/web1/example.com/
web2     18972  0.0  0.3  19464  6376 ?        S    Jan25   0:03  |   \_ /usr/bin/php5-cgi -c /var/www/php-fcgi-scripts/web2/example.org/
web3     19002  0.0  0.3  19660  7452 ?        S    Jan25   0:01  |   \_ /usr/bin/php5-cgi -c /var/www/php-fcgi-scripts/web3/example.net/

Possible problems you might run into

There are like 1 billion problems you might have to face ;)

  • First get nss-mysql and nscd running
  • Dont forget to restart nss-mysql and nscd
  • suexec is often a problem. Make sure you configure it right at compile time. For the default distribution packages check /var/log/apache2/suexec.log for errors.
  • 500 Internal Server Error - Check the logs! Often you can find the solution by the given errors. This may help you further http://htmlfixit.com/cgi-tutes/tutorial_Common_Web_dev_error_messages_and_what_they_mean.php
  • Enabled debug logging for apache and restart it. (LogLevel debug in /etc/apache2/apache2.conf) Be sure to uncomment this line and do a restart of apache after debugging!
  • Be sure that /etc/apache2/logs/fcgidsock is owned by www-data. Otherwise you will get the typical error Premature end of script headers, which says that PHP isn't able to communicate with the apache process.
  • Look at the logs!!!
  • ps faux and look if there is a PHP process running under the apache process.
  • strace -s 2000 -ff -o /tmp/fastcgi -p Very useful if you know how to debug!
  • If you edit config files, please dont use WinSCP. This adds Windows format and Linux can't work with this.

Got problems?

If you got problems with this howto please let us/me know. But please prefer to use the Forum instead of the Bugtracker or IRC. Thanks!

Links and references

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.