How To Set Up Apache2 With mod_fcgid And PHP5 On OpenSUSE 12.3

Want to support HowtoForge? Become a subscriber!
 
Submitted by falko (Contact Author) (Forums) on Mon, 2013-06-10 17:11. :: SuSE | Web Server | Apache

How To Set Up Apache2 With mod_fcgid And PHP5 On OpenSUSE 12.3

Version 1.0
Author: Falko Timme <ft [at] falkotimme [dot] com>
Follow me on Twitter
Last edited 04/12/2013

This tutorial describes how you can install Apache2 with mod_fcgid and PHP5 on OpenSUSE 12.3. mod_fcgid is a compatible alternative to the older mod_fastcgi. It lets you execute PHP scripts with the permissions of their owners instead of the Apache user.

I do not issue any guarantee that this will work for you!

 

1 Preliminary Note

I'm using an OpenSUSE 12.3 server in this tutorial with the hostname server1.example.com and the IP address 192.168.0.100.

I will create two Apache vhosts in this tutorial, www.example1.com and www.example2.com, to demonstrate the usage of mod_fcgid.

 

2 Installing Apache2/mod_fcgi/PHP5

We can install Apache2, mod_fcgid, and PHP5 as follows:

zypper install apache2 apache2-mod_fcgid php5-fastcgi

If Apache2 was already installed with PHP5 as an Apache module, disable the PHP5 module now:

a2dismod php5

Next enable the suexec and fcgid modules:

a2enmod suexec
a2enmod fcgid

Then we create the system startup links for Apache and start it:

systemctl enable apache2.service
systemctl start apache2.service

Next we open /etc/php5/fastcgi/php.ini...

vi /etc/php5/fastcgi/php.ini

... and uncomment the line cgi.fix_pathinfo = 1:

[...]
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is.  For more information on PATH_INFO, see the cgi specs.  Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec.  A setting
; of zero causes PHP to behave as before.  Default is 1.  You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
; http://php.net/cgi.fix-pathinfo
cgi.fix_pathinfo=1
[...]

Open /etc/apache2/conf.d/mod_fcgid.conf...

vi /etc/apache2/conf.d/mod_fcgid.conf

... and add the line PHP_Fix_Pathinfo_Enable 1 (this line must not go into a <VirtualHost> section because then you would get this error: PHP_Fix_Pathinfo_Enable cannot occur within <VirtualHost> section):

[...]

PHP_Fix_Pathinfo_Enable 1
</IfModule>

Then restart Apache:

systemctl restart apache2.service

 

3 Creating Vhosts For www.example1.com And www.example2.com

I will now create two vhosts, www.example1.com (with the document root /srv/www/web1/web) and www.example2.com (with the document root /srv/www/web2/web). www.example1.com will be owned by the user and group web1, and www.example2.com by the user and group web2.

First we create the users and groups:

groupadd web1
groupadd web2
useradd -s /bin/false -d /srv/www/web1 -m -g web1 web1
useradd -s /bin/false -d /srv/www/web2 -m -g web2 web2
chmod 755 /srv/www/web1
chmod 755 /srv/www/web2

Then we create the document roots and make them owned by the users/groups web1 resp. web2:

mkdir -p /srv/www/web1/web
chown web1:web1 /srv/www/web1/web
mkdir -p /srv/www/web2/web
chown web2:web2 /srv/www/web2/web

We will run PHP using suExec; suExec's document root is /srv/www, as the following command shows:

/usr/sbin/suexec2 -V

server1:~ # /usr/sbin/suexec2 -V
 -D AP_DOC_ROOT="/srv/www"
 -D AP_GID_MIN=96
 -D AP_HTTPD_USER="wwwrun"
 -D AP_LOG_EXEC="/var/log/apache2/suexec.log"
 -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
 -D AP_UID_MIN=96
 -D AP_USERDIR_SUFFIX="public_html"
server1:~ #

Therefore we cannot call the PHP binary (/usr/bin/php-cgi) directly because it is located outside suExec's document root. As suExec does not allow symlinks, the only way to solve the problem is to create a wrapper script for each web site in a subdirectory of /srv/www; the wrapper script will then call the PHP binary /usr/bin/php-cgi. The wrapper script must be owned by the user and group of each web site, therefore we need one wrapper script for each web site. I'm going to create the wrapper scripts in subdirectories of /srv/www/php-fcgi-scripts, e.g. /srv/www/php-fcgi-scripts/web1 and /srv/www/php-fcgi-scripts/web2.

mkdir -p /srv/www/php-fcgi-scripts/web1
mkdir -p /srv/www/php-fcgi-scripts/web2

vi /srv/www/php-fcgi-scripts/web1/php-fcgi-starter

#!/bin/sh
PHPRC=/etc/php5/fastcgi/
export PHPRC
export PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN=8
exec /usr/bin/php-cgi

vi /srv/www/php-fcgi-scripts/web2/php-fcgi-starter

#!/bin/sh
PHPRC=/etc/php5/fastcgi/
export PHPRC
export PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN=8
exec /usr/bin/php-cgi

The PHPRC line contains the directory where the php.ini file is located (i.e., /etc/php5/fastcgi/ translates to /etc/php5/fastcgi/php.ini). PHP_FCGI_MAX_REQUESTS is the maximum number of requests before an fcgid process is stopped and a new one is launched. PHP_FCGI_CHILDREN defines the number of PHP children that will be launched.

The php-fcgi-starter scripts must be executable, and they (and the directories they are in) must be owned by the web site's user and group:

chmod 755 /srv/www/php-fcgi-scripts/web1/php-fcgi-starter
chmod 755 /srv/www/php-fcgi-scripts/web2/php-fcgi-starter
chown -R web1:web1 /srv/www/php-fcgi-scripts/web1
chown -R web2:web2 /srv/www/php-fcgi-scripts/web2

Now we create the Apache vhosts for www.example1.com and www.example2.com:

vi /etc/apache2/vhosts.d/www.example1.com.conf

<VirtualHost *:80>
  ServerName www.example1.com
  ServerAlias example1.com
  ServerAdmin webmaster@example1.com
  DocumentRoot /srv/www/web1/web/

  <IfModule mod_fcgid.c>
    SuexecUserGroup web1 web1
    <Directory /srv/www/web1/web/>
      Options +ExecCGI
      AllowOverride All
      AddHandler fcgid-script .php
      FCGIWrapper /srv/www/php-fcgi-scripts/web1/php-fcgi-starter .php
      Order allow,deny
      Allow from all
    </Directory>
  </IfModule>

  # ErrorLog /var/log/apache2/error.log
  # CustomLog /var/log/apache2/access.log combined
  ServerSignature Off

</VirtualHost>

vi /etc/apache2/vhosts.d/www.example2.com.conf

<VirtualHost *:80>
  ServerName www.example2.com
  ServerAlias example2.com
  ServerAdmin webmaster@example2.com
  DocumentRoot /srv/www/web2/web/

  <IfModule mod_fcgid.c>
    SuexecUserGroup web2 web2
    <Directory /srv/www/web2/web/>
      Options +ExecCGI
      AllowOverride All
      AddHandler fcgid-script .php
      FCGIWrapper /srv/www/php-fcgi-scripts/web2/php-fcgi-starter .php
      Order allow,deny
      Allow from all
    </Directory>
  </IfModule>

  # ErrorLog /var/log/apache2/error.log
  # CustomLog /var/log/apache2/access.log combined
  ServerSignature Off

</VirtualHost>

Make sure you fill in the right paths (and the correct user and group in the SuexecUserGroup lines).

Open /etc/apache2/httpd.conf and add the line NameVirtualHost * before the Include /etc/apache2/vhosts.d/*.conf line (otherwise only the first vhost will work):

vi /etc/apache2/httpd.conf

[...]
### Virtual server configuration ############################################
#
# VirtualHost: If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them. Most configurations
# use only name-based virtual hosts so the server doesn't need to worry about
# IP addresses. This is indicated by the asterisks in the directives below.
#
# Please see the documentation at
# <URL:http://httpd.apache.org/docs-2.2/vhosts/>
# for further details before you try to setup virtual hosts.
#
# You may use the command line option '-S' to verify your virtual host
# configuration.
#
NameVirtualHost *:80

Include /etc/apache2/vhosts.d/*.conf
[...]

Before we restart Apache, we change the permissions of the suExec executable (otherwise you will see the following warning when you restart Apache: Warning: SuexecUserGroup directive requires SUEXEC wrapper.):

chmod 4755 /usr/sbin/suexec2

Restart Apache afterwards:

systemctl restart apache2.service

 

4 Testing

Now we create a small PHP test file, for example in the www.example1.com web site...

vi /srv/www/web1/web/info.php

<?php
phpinfo();
?>

... and call that file in a browser (http://www.example1.com/info.php). If all goes well, the output should look similar to this, and you should see CGI/FastCGI in the Server API line:

 

5 Custom php.ini for Each Web Site

Because each web site has its own php-fcgi-starter wrapper script, it is possible to define different php.ini files for different web sites. To demonstrate this, I will copy the default php.ini (/etc/php5/fastcgi/php.ini) to the /srv/www/web2/ directory and make www.example2.com use the php.ini from the /srv/www/web2/ directory:

cp /etc/php5/fastcgi/php.ini /srv/www/web2/
chown web2:web2 /srv/www/web2/php.ini

(You can now modify /srv/www/web2/php.ini to your likings.)

Then we open /srv/www/php-fcgi-scripts/web2/php-fcgi-starter...

vi /srv/www/php-fcgi-scripts/web2/php-fcgi-starter

... and put /srv/www/web2/ in the PHPRC line:

#!/bin/sh
PHPRC=/srv/www/web2/
export PHPRC
export PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN=8
exec /usr/bin/php-cgi

Restart Apache afterwards:

systemctl restart apache2.service

Create a new phpinfo(); file for www.example2.com...

vi /srv/www/web2/web/info.php

<?php
phpinfo();
?>

... and call it in a browser (http://www.example2.com/info.php). The Loaded Configuration File line should now show /srv/www/web2/php.ini:

 

6 Changing Single PHP Configuration Settings

Instead of passing a whole new php.ini file to your web site, you can as well change single PHP configuration settings in the php-fcgi-starter wrapper script (or use a combination of both) by adding the -d switch to the PHP executable. For example, if I want to disable magic_quotes_gpc for the web site www.example2.com, I'd do it as follows:

vi /srv/www/php-fcgi-scripts/web2/php-fcgi-starter

#!/bin/sh
PHPRC=/etc/php5/fastcgi/
export PHPRC
export PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN=8
exec /usr/bin/php-cgi -d magic_quotes_gpc=off

Restart Apache afterwards:

systemctl restart apache2.service

Then call the info.php script again in a browser (http://www.example2.com/info.php) and search for the magic_quotes_gpc line - it should show Off now:

 

7 Links


Please do not use the comment function to ask for help! If you need help, please use our forum.
Comments will be published after administrator approval.