HOWTO: Apache1 + PHP4/mod_php + PHP5/FastCGI + DA

paix

Verified User
Joined
Oct 31, 2006
Messages
55
Location
ua
This instruction describe how to use PHP5/FastCGI alongside default DA Apache1 and PHP4/mod_php.
---------------------
Workaround

File/Directory Permissions.
When PHP runs as an Apache Module it executes as the user/group of the webserver which is usually "apche" or "nobody". Under this mode, files or directories that you require your php scripts to write to need to have 777 permissions (read/write/execute at user/group/world level). This is not very secure because besides allowing the webserver to write to the file it also allows anyone else to read or write to the file.

With PHP running as CGI with suexec enabled your php scripts now execute under your user/group level. Files or directories that you require your php scripts to write to no longer need to have 777 permissions and all files you upload or create will be owned by your user/group automatically.
Files and directories also need to be owned by your user/group.

The biggest problem of PHP/CGI and suPHP too is very bad performance compare to mod_php.

Solution

FastCGI module can be used to pre-fork cgi processed and let them running instead of starting up a new process for every request. This is by far faster than PHP/CGI.

First, I prefer to use mod_php4 for perfomance reasons. But in this case the configuration of apache and php is very important. I'm using php security restrictions such us: open_basedir, disable_functions = ... , allow_url_fopen = Off, etc.
Second, for php scripts, that require executing under your user/group I'm going use PHP/FastCGI.

This installation successfully works on my FreeBSD6 servers.

Lets begin
==================================================
Installing PHP5
----------------
#mkdir /var/src
#cd /var/src

Go to http://www.php.net/downloads.php and choose the php version (currently - 5.2.0) and the mirror for downloading. Copy link location.

#wget "http://us2.php.net/get/php-5.2.0.tar.gz/from/this/mirror"
#tar -zxvf php-5.2.0.tar.gz
#cd php-5.2.0
#vim configure5.php
edit configure5.php as follow:
Code:
#!/bin/sh
./configure \
          --prefix=/usr/local/php5 \
          --with-config-file-path=/usr/local/etc/php5/cgi \
          --with-fastcgi=/usr/local \
          --enable-fastcgi \
          --enable-force-cgi-redirect \
          --disable-cli \
          --with-iconv=/usr/local/lib \
          --with-bz2 \
          --with-curl \
        --with-curl-dir=/usr/local/lib \
        --with-gd \
        --with-gd-dir=/usr/local \
        --with-gettext \
        --with-jpeg-dir=/usr/local/lib \
        --with-kerberos \
        --with-mcrypt \
        --with-mhash \
        --with-mysql=/usr/local/mysql \
        --with-pear \
        --with-png-dir=/usr/local/lib \
        --with-xml \
        --with-zlib \
        --with-zlib-dir=/usr/local/lib \
        --with-zip \
        --with-openssl \
        --enable-bcmath \
        --enable-calendar \
        --enable-ftp \
        --enable-magic-quotes \
        --enable-sockets \
        --enable-track-vars \
        --enable-mbstring \
        --enable-memory-limit
-----------------------

#sh configure5.php

If you get error like this
"configure: error: xml2-config not found. Please check your libxml2 installation."
you should just install libxml2.
In my case: #portinstall -i libxml2

#make
#make install

Don't worry about old php. Php5 would be installed to /usr/local/php5 directory.
#mkdir -p /usr/local/etc/php5/cgi
#cp php.ini-dist /usr/local/etc/php5/cgi/php.ini

In the end, you can verify php5 installation
#/usr/local/php5/bin/php -v
PHP 5.2.0 (cgi-fcgi) (built: Dec 18 2006 21:16:37)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2006 Zend Technologies

Good!
=========================================================
Installing Apache mod_fastcgi
--------------
Reference http://www.fastcgi.com/

Downloading
#wget http://www.fastcgi.com/dist/mod_fastcgi-2.4.2.tar.gz
#tar -zxvf mod_fastcgi-2.4.2.tar.gz
#cd mod_fastcgi-2.4.2

#less INSTALL and look for "Installing mod_fastcgi as a DSO"
Then
#apxs -o mod_fastcgi.so -c *.c
#apxs -i -a -n fastcgi mod_fastcgi.so

Support of fastcgi_module will be added automatically to your httpd.conf.
-------------
Configuring mod_fastcgi

# vim /etc/httpd/conf/httpd_custom.conf
edit httpd_custom.conf as follow:
Code:
#--- mod FastCGI ---#
<IfModule mod_fastcgi.c>
  
        FastCgiConfig -singleThreshold 100  -autoUpdate -idle-timeout 90 -pass-header HTTP_AUTHORIZATION

	AddHandler php-fastcgi5 .php5
        AddType application/x-httpd-php .php5
        DirectoryIndex index.php5
	
	#This tell php to launch php-fcgi wrapper when .php5 files  are requested.
        Action php-fastcgi5 /cgi-bin/php-fcgi

        <Directory "/usr/local/php5/bin/">
           AllowOverride None
           Options ExecCGI -Includes -MultiViews -Indexes
           Order allow,deny
           Allow from all
        </Directory>

        <Files *.ini>
          Order deny,allow
          Deny from All
        </Files>
	
</IfModule>
#--------------------#
After this add next line to your httpd.conf:
Code:
Include /etc/httpd/conf/httpd_custom.conf
Now create the wrapper script.

This script lets you set a specific .ini file. In the example, PHP will read in /usr/local/etc/php5/cgi/php.ini for configuration parameters. The number of running children is controlled by the other environment variable.

# vim /usr/local/directadmin/scripts/php-fcgi
edit php-fcgi as follow:
Code:
#!/bin/sh
#PHPRC="/usr/local/etc/php5/cgi/php.ini"
#export PHPRC
PHP_FCGI_CHILDREN=4
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS
exec /usr/local/php5/bin/php
#chmod 555 /usr/local/directadmin/scripts/php-fcgi

This script should be copied to every users home into directory public_html/cgi-bin
If you want to let users use a custom php.ini file, you should use PHPRC="../". In this case wrapper will be find php.ini file in the root of public_html directory.
But I think this way is enough insecure...because users can override important server directives such us open_basedir, etc.
I prefer manually point PHPRC to wanted php.ini configuration file. For example you can use
PHPRC="/usr/local/etc/php5/cgi/php.ini" or
PHPRC="/usr/local/etc/php5/cgi/rule1/php.ini" or
PHPRC="/usr/local/etc/php5/cgi/username/php.ini" and edit each rule as you need.

By default php5 will look for php.ini file in /usr/local/etc/php5/cgi/ directory, so I've commented PHPRC directives .

Note, for every existent users you should copy this script manually in their cgi-bin directories and switch the owners of php-fcgi script.
For new domains and subdomains I've written tiny sctipts.
----------------------
Editing "domain_create_post.sh" and "subdomain_create_post.sh" for new domains and subdomains.

#vim /usr/local/directadmin/scripts/custom/domain_create_post.sh
edit domain_create_post.sh as follow:
Code:
#!/bin/sh
cp /usr/local/directadmin/scripts/php-fcgi /home/${username}/domains/${domain}/public_html/cgi-bin
chmod 555 /home/${username}/domains/${domain}/public_html/cgi-bin/php-fcgi
chown ${username}:${username}  /home/${username}/domains/${domain}/public_html/cgi-bin/php-fcgi
echo "`date`  ${domain} created  " >> /var/log/directadmin/domain_create.log
#chown diradmin:diradmin /usr/local/directadmin/scripts/custom/domain_create_post.sh
#chmod 700 /usr/local/directadmin/scripts/custom/domain_create_post.sh

#vim /usr/local/directadmin/scripts/custom/subdomain_create_post.sh
edit subdomain_create_post.sh as follow:
Code:
#!/bin/sh
cp /usr/local/directadmin/scripts/php-fcgi /home/${username}/domains/${domain}/public_html/cgi-bin
chmod 555 /home/${username}/domains/${domain}/public_html/cgi-bin/php-fcgi
chown ${username}:${username}  /home/${username}/domains/${domain}/public_html/cgi-bin/php-fcgi
echo "`date`  ${domain}/public_html/${subdomain}  created  " >> /var/log/directadmin/domain_create.log
#chown diradmin:diradmin /usr/local/directadmin/scripts/custom/subdomain_create_post.sh
#chmod 700 /usr/local/directadmin/scripts/custom/subdomain_create_post.sh

=============
Configuring php.ini for more security

You can configure your /usr/local/etc/php5/cgi/php.ini file wtih next directives

open_basedir = /home/:/var/www/html/:/tmp:/etc/virtual

disable_functions = symlink, system, shell_exec, exec, proc_get_status, proc_nice, proc_terminate, define_syslog_variables, syslog, openlog, closelog, escapeshellcmd, passthru, ocinumcols, ini_alter, leak, listen, chgrp, set_time_limit, apache_note, apache_setenv, debugger_on, debugger_off, ftp_exec, dl, dll, ftp

display_errors = Off
log_errors = On
error_log = /var/log/httpd/php5_error.log

register_globals = Off
enable_dl = Off
upload_tmp_dir = /tmp
allow_url_fopen = Off
session.save_path = /var/tmp/php5_sessions
#mkdir /var/tmp/php5_sessions
#chmod 777 /var/tmp/php5_sessions
===============
For testing your installation create file with .php5 extension and see phpinfo();

This all! Enjoy! ;)

PS. and sorry for my engl...
 
Last edited:

kke

Verified User
Joined
Apr 4, 2006
Messages
202
Location
Thailand
Nice howto but...

Then user can easily overwrite php-fcgi wrapper in their cgi-bin
eg. change PHPRC to their own php.ini
or sometime may accidently delete cgi-bin folder

IMO the wrapper should be store in some place that user can not access
and set open_basedir to that folder
eg. /usr/local/php-wraper/username/php-fcgi

YES, user still can modify this file via php script, but not so easy as just use ftp or da filemanager!

anyway, thanks for nice howto
 

paix

Verified User
Joined
Oct 31, 2006
Messages
55
Location
ua
Nice howto but...

Then user can easily overwrite php-fcgi wrapper in their cgi-bin
eg. change PHPRC to their own php.ini
or sometime may accidently delete cgi-bin folder

IMO the wrapper should be store in some place that user can not access
and set open_basedir to that folder
eg. /usr/local/php-wraper/username/php-fcgi

YES, user still can modify this file via php script, but not so easy as just use ftp or da filemanager!

anyway, thanks for nice howto
Yes, I know about this bug.

It's good idea to keep wrapper in some place that user can not access, but I think this case will not work, because
" Action php-fastcgi5 /cgi-bin/php-fcgi " call wrapper concerning virtualhost DocumentRoot, so you can't write separate(full patch) location of wrapper script.

Of course, you could testing this case. Maybe I'm not right..

Anothe reason:

If you want use php5/FastCGI by default you should simply add

Code:
     AddHandler php-fastcgi5 .php
     Action php-fastcgi5 /cgi-bin/php-fcgi
to user virtualhost directive or to the
.htaccess file.

It's very flexible!

To prevent users modify wrapper script you can change file flags (chflags for FreeBSD). So, only root will be able to modify this script.

Next, you can write some check-script. If users will use their php.ini files you can suspend them.

I have php5/FastCGI in production on my servers. If users of php5 want to change some configuration of php5 they are write to our support.
So php5 lets you make full custom configurations for every user when in the mod_php4 users can modify only some directives via .htaccess.

Thank you for reply! :)
I tnihk FastCGI is very perspective technology!
Good luck!
 

jackc

Verified User
Joined
Jan 19, 2007
Messages
347
So after chmod 555 to all users's php-fcgi in cgi-bin, there won't be this security issue as kke described since the user cannot modify it?
 

paix

Verified User
Joined
Oct 31, 2006
Messages
55
Location
ua
So after chmod 555 to all users's php-fcgi in cgi-bin, there won't be this security issue as kke described since the user cannot modify it?
Chmod 555 can't resolve this issue, just make more hardly modifying php-fcgi script for users. Users still can overwrite php-fcgi wrapper.

chflag(FreeBSD) or chattr(Linux) can resolve this security issue, but require some additional tips. (Probably this is paranoiac feature :)

Anothe way is suspend users if they will use custom php.ini (such as dreamhost). All changes must make hosting's support.
 
Last edited:

jackc

Verified User
Joined
Jan 19, 2007
Messages
347
thanks, i think i get what you meant.
they can still do something like this
AddHandler php-fastcgi5 .php
Action php-fastcgi5 /cgi-bin/php-fcgi2
to use a different file.
I'm thinking how to check the user if they use custom php.ini
 

jackc

Verified User
Joined
Jan 19, 2007
Messages
347
maybe I got it wrong, but please let us know if there is a easy solution.:D
 

jackc

Verified User
Joined
Jan 19, 2007
Messages
347
btw, if I don't let users use their own php.ini then I won't have this problem is that correct? thanks
 

erohas

Verified User
Joined
Aug 5, 2007
Messages
58
Location
Kazakhstan, Almaty
I have been install mod_fcgid for apache 2.0.59

Code:
[~] apxs -c -o mod_fcgid.so -Iarch/unix -I. fcgid_bridge.c fcgid_conf.c fcgid_pm_main.c fcgid_protocol.c fcgid_spawn_ctl.c mod_fcgid.c arch/unix/fcgid_proctbl_unix.c arch/unix/fcgid_pm_unix.c arch/unix/fcgid_proc_unix.c fcgid_bucket.c fcgid_filter.c

[~] cp .libs/mod_fcgid.so /usr/lib/apache/mod_fcgid.so

[~] vi /etc/httpd/conf/httpd.conf
>>
LoadModule fcgid_module /usr/lib/apache/mod_fcgid.so
then

Code:
[~] mkdir /fcgi
[~] mkdir -p /fcgi/user/public_html/
[~] touch /fcgi/user/public_html/fcgid.sh
[~] chown -R user:user /fcgi/user
because SuexecUserGroup does not allow exec scripts outside Suexec_docroot

Code:
[~] vi /fcgi/user/public_html/fcgid.sh
>>
#!/bin/sh
PHPRC=/fcgi/user/public_html/php.ini
export PHPRC
export PHP_FCGI_MAX_REQUESTS=0
exec /usr/local/php5/bin/php-cgi
then in virtual host file
insert the following
Code:
<IfModule mod_fcgid.c>
Options +ExecCGI
AddHandler fcgid-script .phpf
FCGIWrapper "/fcgi/user/public_html/fcgid.sh" .phpf
</IfModule>
restart apache
and enjoy )

DA changes:
Code:
cd /usr/local/directadmin/scripts/custom/
vi fcgid.sh
>>>
#!/bin/sh
export PHP_FCGI_MAX_REQUESTS=0
exec /usr/local/php5/bin/php-cgi

Code:
vi domain_create_post.sh
>>>
#!/bin/sh
 
mkdir -p /fcgi/${username}/public_html
cp /usr/local/directadmin/scripts/custom/fcgid.sh /fcgi/${username}/public_html/fcgid.sh && chmod 0700 /fcgi/${username}/public_html/fcgid.sh
chown -R ${username}:${username} /fcgi/${username}
echo "`date`  ${domain} created  " >> /var/log/directadmin/domain_create.log
Code:
vi domain_destroy_post.sh
>>>
#!/bin/sh
 
rm -dfr /fcgi/${username}
echo "`date`  ${domain} removed  " >> /var/log/directadmin/domain_remove.log
and user can't overwrite PHPRC var

sorry for my english
 
Last edited:

paix

Verified User
Joined
Oct 31, 2006
Messages
55
Location
ua
Good solution :)

However this issue with PHPRC is to much exaggerate.
You try to harden PHP by don't let users possibilities to change their own php.ini... but forgot about cgi and perl!!!

It's biggest vulnerability! A simple script on perl shows all files of your server.. (of course respectively to unix permissions)
Don't forget about this!

IMHO only right decision with security on shared virtual hosting is jail. Put all sites, apache+php+cgi+perl, proftpd to jail.

In every case your should watch for right unix permissions at first! Don't forget to keep all software up to date so.
 

Overseer

Verified User
Joined
Mar 6, 2008
Messages
13
Apache2 + PHP5/FastCGI + DA
Can't login to phpmyadmin =( HELP..

UPDATE:
problem almost solved. i have turned off E_NOTICE in php.ini
 
Last edited:

paix

Verified User
Joined
Oct 31, 2006
Messages
55
Location
ua
Since current DA comes with FastCGI, I don't need to do anything anymore.
It's good news.
Currently I'm using on my hosting box
DA + nginx + apache1+mod_fastcgi+php5

This howto still valid, but you should keep in mind that versions of software is outdated, and there is no reasons to install mod_php4.

Some addons. Most effective mod_fastcgi settings (imho):

Code:
#--- mod FastCGI ---#
<IfModule mod_fastcgi.c>

        FastCgiConfig   -singleThreshold 90 -multiThreshold 90 -minProcesses 2  -maxProcesses 40 -maxClassProcesses 5    \
                        -idle-timeout 60 -killInterval 40 -updateInterval 120 -autoUpdate  -restart  \
                        -pass-header HTTP_AUTHORIZATION

        AddHandler php-fastcgi5 .php5
        AddType application/x-httpd-php .php5
        DirectoryIndex index.php5

        #This tell php launch php-fcgi wrapper when .php5 files are requested.
        Action php-fastcgi5 /cgi-bin/php-fcgi

       FastCgiWrapper /usr/sbin/suexec
       FastCgiIpcDir /var/run/fastcgi

        <Location /cgi-bin/php-fcgi>
                Options ExecCGI FollowSymLinks
               SetHandler fastcgi-script
        </Location>

</IfModule>
#--------------------#
 

snk

Verified User
Joined
Dec 19, 2007
Messages
102
Hi
paix did you tried php-fpm ?

just asking... :)
 
Last edited:

paix

Verified User
Joined
Oct 31, 2006
Messages
55
Location
ua
Hi
paix did you tried php-fpm ?

just asking... :)
Yes, of course!
As I wrote here: http://www.directadmin.com/forum/showthread.php?t=27344
point 7
php-fpm is most advansed PHP fastcgi process manager (imho).

I'm using it on some heavy loaded projects! It's look great. Also it has very good technical support at the google groups:
highload-php-en
highload-php-ru

Also you could download a freebsd port here: http://paix.org.ua/sk/php5_fpm_526.tar.gz

In the end, on some my hosting box (under freebsd, DA) I'm using
nginx + php-fpm together with nginx + apache1-mod_fastcgi-php5. Both php-fpm and php5 are compiled from ports. Any issues!

Good luck! :)
 

huan

Verified User
Joined
Mar 7, 2005
Messages
30
Location
Poland
Hi,

I wrote a php script for people who need to copy the wrapper to existing users' directories. For servers with many accounts it can be usefull.

What it does is it copies /usr/local/directadmin/scripts/php-fcgi to /cgi-bin/ of every domain and subdomain on the server. It may report some errors as not all sudomain directories have to exist.

Code:
#!/usr/bin/php
<?php

$userdir = '/usr/local/directadmin/data/users';

if ($handle = opendir($userdir)) {
        while (false !== ($username = readdir($handle))) {
            $username = trim($username);
            if($domains = file($userdir.'/'.$username.'/domains.list')){
                for($i=0;$i<count($domains);$i++){
                    $domains[$i] = trim($domains[$i]);
                    system("mkdir -m 755 /home/$username/domains/$domains[$i]/public_html/cgi-bin");
                    system("chown $username.$username /home/$username/domains/$domains[$i]/public_html/cgi-bin");
                    system("cp -f /usr/local/directadmin/scripts/php-fcgi /home/$username/domains/$domains[$i]/public_html/cgi-bin");
                    system("chmod 555 /home/$username/domains/$domains[$i]/public_html/cgi-bin/php-fcgi");
                    system("chown $username.$username /home/$username/domains/$domains[$i]/public_html/cgi-bin/php-fcgi");
                    if($subdomains = file($userdir.'/'.$username.'/domains/'.$domains[$i].'.subdomains')){
                        for($j=0;$j<count($subdomains);$j++){
                            $subdomains[$j] = trim($subdomains[$j]);
                            system("mkdir -m 755 /home/$username/domains/$domains[$i]/public_html/$subdomains[$j]/cgi-bin");
                            system("chown $username.$username /home/$username/domains/$domains[$i]/public_html/$subdomains[$j]/cgi-bin");
                            system("cp -f /usr/local/directadmin/scripts/php-fcgi /home/$username/domains/$domains[$i]/public_html/$subdomains[$j]/cgi-bin");
                            system("chmod 555 /home/$username/domains/$domains[$i]/public_html/$subdomains[$j]/cgi-bin/php-fcgi");
                            system("chown $username.$username /home/$username/domains/$domains[$i]/public_html/$subdomains[$j]/cgi-bin/php-fcgi");
                        }
                    }
                }
            }
        }
}


?>
 

scsi

Verified User
Joined
Aug 19, 2008
Messages
4,695
Why in the heck would you want php-fcgi in every cgi-bin directory.........
 

huan

Verified User
Joined
Mar 7, 2005
Messages
30
Location
Poland
Why in the heck would you want php-fcgi in every cgi-bin directory.........
Since there is Action php-fastcgi5 /cgi-bin/php-fcgi in the httpd.conf it means every PHP request will go throught /cgi-bin/php-fcgi wrapper.

I wonder how this would work the other way around. Have mod_proxy push off the image processing to Nginx. That way people could maintain the functionality of Apache for their web apps, and off-load the images to Nginx.
Actually at this time I use the following config: Nginx frontend + (Apache with FastCGI) - works great for me. Just install Nginx according to this how-to and then install FastCGI for Apache.
 
Top