Apache2 mit php5 (mod_fcgid) und Suexec einrichten
Unser Ziel ist es, zwei Virtual Hosts mit unterschiedlichen Suexec-Usern zu erstellen, deren Home-Verzeichnis /home/<USERNAME>/htdocs
, auch das DocumentRoot Verzeichnis ist. Die PHP-Prozessen laufen dann mit den Rechten des jeweiligen Users. Nennen wir die User in unserem Beispiel user1 und user2.
root:~# apt-get install apache2 apache2-utils apache2-suexec-custom libapache2-mod-fcgid php5-cgi
Mit dem Befehl a2enmod
aktivieren wir die installierten Module.
root:~# a2enmod fcgid && a2enmod suexec
Nun bearbeiten wir die Konfigurationsdatei für das fcgid Module und tragen folgendes ein.
<IfModule mod_fcgid.c>
# IdleTimeout n (300 seconds)
# An idle fastcgi application will be terminated after IdleTimeout seconds.
IdleTimeout 600
# IdleScanInterval n (120 seconds)
# The scan interval for idle fastcgi applications.
IdleScanInterval 240
# BusyTimeout n (300 seconds)
# A fastcgi application will be terminated if handing a single request
# longer than busy timeout.
BusyTimeout 300
# BusyScanInterval n (120 seconds)
# The scan interval for busy timeout fastcgi applications.
BusyScanInterval 120
# ErrorScanInterval n (3 seconds)
# The scan interval for exit pending fastcgi applications. fastcgi
# applications will be terminated within this scanning.
ErrorScanInterval 6
# ZombieScanInterval n (3 seconds)
# The scan interval for zombie process.
ZombieScanInterval 6
# ProcessLifeTime n (3600 seconds)
# A fastcgi application will be terminated if lifetime expired,
# even no error is detected.
ProcessLifeTime 3600
# SocketPath path (logs/fcgidsock)
# The directory to put the UNIX domain socket. (UNIX only)
# This directory should be writable only by apache user
SocketPath /var/lib/apache2/fcgid/sock
# SharememPath path (logs/fcgid_shm)
# The share memory file path. (UNIX only) (version >= 2.1 only)
SharememPath /var/lib/apache2/fcgid/shm
# SpawnScoreUpLimit n (10)
# The spawn-speed control score up water limit. Score increases while
# a process is spawned or terminated, and decreases as time progresses;
# while the score is higher than SpawnScoreUpLimit, the spawning will be
# held for a while. The higher this number is, the higher speed of the
# spawning can be.
SpawnScoreUpLimit 10
# SpawnScore n (1)
# The weight of spawning. This weight will be plused to the spawn-control
# score on every spawn. The higher this number is, the lower speed of
# spawning can be.
SpawnScore 1
# TerminationScore n (2)
# The weight of termination. This weight will be plused to the score while
# fastcgi process terminates. The higher this number is, the lower speed
# of spawning can be.
TerminationScore 2
# MaxProcessCount n (1000)
# The max count of total fastcgi process count.
MaxProcessCount 300
# DefaultMaxClassProcessCount n (100)
# The maximum number of fastcgi application instances allowed to run for
# particular one fastcgi application.
DefaultMaxClassProcessCount 10
# DefaultMinClassProcessCount n (3)
# The minimum number of fastcgi application instances for any one fastcgi
# application.
# Idle fastcgi will not be killed if their count is less than n
# Set this to 0, and tweak IdleTimeout
DefaultMinClassProcessCount 0
# DefaultInitEnv env_name env_value
# The default environment variables before a fastcgi application
# is spawned. You can set this configuration more than once.
# IPCConnectTimeout n (3 seconds)
# The connect timeout to a fastcgi application.
IPCConnectTimeout 60
# IPCCommTimeout n (20 seconds)
# The communication timeout to a fastcgi application. Please increase this
# value if your CGI have a slow initialization or slow respond.
IPCCommTimeout 120
# OutputBufferSize n (64k bytes)
# CGI output cache buffer size.
# PHP_Fix_Pathinfo_Enable n(n=0/1, default 0)
# If you are using PHP and set cgi.fix_pathinfo=1 in php.ini, set PHP_Fix_Pathinfo_Enable 1.
# From php.ini:
# 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 it's paths to conform to the spec. A setting
# of zero causes PHP to behave as before. Default is zero. You should fix your scripts
# to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
# cgi.fix_pathinfo=1
PHP_Fix_Pathinfo_Enable 1
MaxRequestsPerProcess 500
FcgidConnectTimeout 60
MaxRequestLen 33554432
AddHandler fcgid-script .php
AddHandler fcgid-script .fcgi
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
</IfModule>
Die Konfigurationsdatei für suexec finden wir unter /etc/apache2/suexec/
und hat den Namen des Users, unter dem der Apacheprozess läuft. Auf Debian Systemen ist das der User www-data. In der Datei /etc/apache2/suexec/www-data
ändern wir den Eintrag in der ersten Zeile. Dieser lautet meist /var/www
und ist das docroot Verzeichnis für den Apache. Da die Homeverzeichnisse der Unixusers unter /home/<USERNAME>/htdocs
liegen und wir diese als DocumentRoot definieren wollen, tragen wir /home
ein, da der php5-cgi Interpreter (den wir noch anlegen werden) innerhalb vom docroot liegen muss, da sonst suexec sich beschwert.
/home
public_html/cgi-bin
# The first two lines contain the suexec document root and the suexec userdir
# suffix. Both features can be disabled separately by prepending a # character.
# This config file is only used by the apache2-suexec-custom package.
Nun erstellen wir in den Homeverzeichnissen der Unixuser die Verzeichnisse bin/fcgid, var/tmp und htdocs.
root:~# mkdir -p /home/{user1,user2}/bin/fcgid
root:~# mkdir -p /home/{user1,user2}/var/tmp
root:~# mkdir -p /home/{user1,user2}/htdocs
root:~# chown -R user1.user1 /home/user1/htdocs
root:~# chown -R user1.user1 /home/user1/var/tmp
root:~# chown -R user1.user1 /home/user1/bin/fcgid
root:~# chown -R user2.user2 /home/user2/htdocs
root:~# chown -R user2.user2 /home/user2/var/tmp
root:~# chown -R user2.user2 /home/user2/bin/fcgid
Im bin/fcgid Verzeichnis erstellen wir nun eine Datei php5-cgi.
#!/bin/sh
# Shell Script To Run PHP5 using mod_fastcgi under Apache 2.x
### Set PATH ###
PHPRC="/home/<UNIXUSER>/bin/fcgid"
PHP_FCGI_CHILDREN=4
PHP_FCGI_MAX_REQUESTS=1000
FCGI_SERVER_MAX_STDERR_LINE_LEN=2047
TMPDIR="/home/<UNIXUSER>/var/tmp"
### no editing below ###
export TMPDIR
export PHP_FCGI_CHILDREN
export PHP_FCGI_MAX_REQUESTS
export FCGI_SERVER_MAX_STDERR_LINE_LEN
exec /usr/bin/php5-cgi
Nun setzen wir auf die Datei php5-cgi das Ausführungs-Bit und setzen die Dateirechte zu gunsten des jeweiligen Users.
root:~# chmod 755 /home/user1/bin/fcgid/php5-cgi
root:~# chmod 755 /home/user2/bin/fcgid/php5-cgi
root:~# chown user1.user1 /home/user1/bin/fcgid/php5-cgi
root:~# chown user2.user2 /home/user2/bin/fcgid/php5-cgi
Dann kopieren wir uns die Original php.ini
Datei in das jeweilige fcgid Verzeichnis des jeweiligen Users.
root:~# cp /etc/php5/cgi/php.ini /home/user1/bin/fcgid/php.ini
root:~# chown user1.user1 /home/user1/bin/fcgid/php.ini
root:~# cp /etc/php5/cgi/php.ini /home/user2/bin/fcgid/php.ini
root:~# chown user2.user2 /home/user2/bin/fcgid/php.ini
Die folgenden Variablen habe ich für jeden User geändert. Der String <UNIXUSER> ist ein Platzhalter für den jeweiligen User. Dort muss dann der User user1 bzw. user2 eingetragen werden.
....
post_max_size = 32M
....
upload_max_filesize = 32M
....
upload_tmp_dir = /home/<UNIXUSER>/var/tmp
....
Zum testen, erstellen wir im DocumentRoot Verzeichnis htdocs eines jeden Users eine index.php
mit dem Inhalt der phpinfo()
Funktion.
root:~# echo -e "<?php\nphpinfo();\n?>" >/home/{user1,user2}/htdocs/index.php
root:~# chown user1.user1 /home/user1/htdocs/index.php
root:~# chown user2.user2 /home/user2/htdocs/index.php
Als letztes erstellen wir eine VirtualHosts Datei für user1 und user2. Die VirtualHost Datei könnte wie folgt aussehen. Wichtig sind die Pfade zum DocumentRoot Verzeichnis /home/<USERNAME>/htdocs
, und der Pfad zum php5-cgi Interpreter /home/<USERNAME>/bin/fcgid/php5-cgi
.
<VirtualHost *:80>
ServerAdmin postmaster@example.com
ServerName user1.example.com
ServerSignature Off
SuexecUserGroup user1 user1
DocumentRoot /home/user1/htdocs
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /home/user1/htdocs>
Options -Indexes FollowSymLinks MultiViews
DirectoryIndex index.htm index.html index.php
AllowOverride None
Order allow,deny
allow from all
</Directory>
# PHP settings - mod_fcgid.c
<IfModule mod_fcgid.c>
<Files ~ "\.php$">
FCGIWrapper /home/user1/bin/fcgid/php5-cgi .php
Options +ExecCGI
</Files>
</IfModule>
CustomLog ${APACHE_LOG_DIR}/user1.example.com_acc.log mycommon env=!DONTLOG
ErrorLog ${APACHE_LOG_DIR}/user1.example.com_err.log
LogLevel warn
</VirtualHost>
Das Logformat, was wir hierbei benutzen, ist das mycommon Logformat, welches in der Datei apache2.conf
definiert wird.
....
LogFormat "%t %{HOST}i %h \"%u\" \"%r\" \"%{Content-Type}o\" %>s %b \"%T\" \"%{User-Agent}i\" \"%{Referer}i\" \"%{cookie}i\"" mycommon
....
Die Variable DONTLOG wird in der Datei /etc/apache2/conf.d/setenv.conf
definiert, wo wir noch weitere Environment Variablen definieren können.
# File: /etc/apache2/conf.d/setenv.conf
# Get the domain from Host (e.g. foobar.example.com => example.com)
SetEnvIfNoCase Host ([^.]+)\.([^.]+)$ DOMAIN=$1.$2
# Define variable DONTLOG to define Request
# witch have to no log into the access logfile.
SetEnvIf Request_URI "^/favicon.ico$" DONTLOG
Nun aktivieren wir die VirtualHost Dateien mit a2ensite <FILE> und starten den Apache Webserver neu.
root:~# a2ensite user1
root:~# a2ensite user2
root:~# service apache2 restart