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>
# FcgidIdleTimeout n (300 seconds)
# An idle fastcgi application will be terminated after IdleTimeout seconds.
FcgidIdleTimeout 600
# FcgidIdleScanInterval n (120 seconds)
# The scan interval for idle fastcgi applications.
FcgidIdleScanInterval 240
# FcgidBusyTimeout n (300 seconds)
# A fastcgi application will be terminated if handing a single request
# longer than busy timeout.
FcgidBusyTimeout 300
# FcgidBusyScanInterval n (120 seconds)
# The scan interval for busy timeout fastcgi applications.
FcgidBusyScanInterval 120
# FcgidErrorScanInterval n (3 seconds)
# The scan interval for exit pending fastcgi applications. fastcgi
# applications will be terminated within this scanning.
FcgidErrorScanInterval 6
# FcgidZombieScanInterval n (3 seconds)
# The scan interval for zombie process.
FcgidZombieScanInterval 6
# FcgidProcessLifeTime n (3600 seconds)
# A fastcgi application will be terminated if lifetime expired,
# even no error is detected.
FcgidProcessLifeTime 3600
# FcgidIPCDir path (logs/fcgidsock)
# The directory to put the UNIX domain socket. (UNIX only)
# This directory should be writable only by apache user
FcgidIPCDir /var/lib/apache2/fcgid/sock
# FcgidProcessTableFile path (logs/fcgid_shm)
# The share memory file path. (UNIX only) (version >= 2.1 only)
FcgidProcessTableFile /var/lib/apache2/fcgid/shm
# FcgidSpawnScoreUpLimit 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.
FcgidSpawnScoreUpLimit 150
# FcgidSpawnScore 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.
FcgidSpawnScore 1
# FcgidTerminationScore 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.
FcgidTerminationScore 1
# FcgidMaxProcesses n (1000)
# The max count of total fastcgi process count.
FcgidMaxProcesses 300
# FcgidMaxProcessesPerClass n (100)
# The maximum number of fastcgi application instances allowed to run for
# particular one fastcgi application.
FcgidMaxProcessesPerClass 10
# FcgidMinProcessesPerClass 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
FcgidMinProcessesPerClass 0
# DefaultInitEnv env_name env_value
# The default environment variables before a fastcgi application
# is spawned. You can set this configuration more than once.
# FcgidConnectTimeout n (3 seconds)
# The connect timeout to a fastcgi application.
FcgidConnectTimeout 600
# FcgidIOTimeout n (20 seconds)
# The communication timeout to a fastcgi application. Please increase this
# value if your CGI have a slow initialization or slow respond.
FcgidIOTimeout 120
# OutputBufferSize n (64k bytes)
# CGI output cache buffer size.
FcgidOutputBufferSize 65536
# 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
FcgidFixPathinfo 1
# FcgidMaxRequestsPerProcess n (0)
# FastCGI application processes will be terminated after handling the specified number of requests.
# A value of 0 disables the check.
FcgidMaxRequestsPerProcess 10000
# FcgidMaxRequestLen n (131072 bytes)
# If the size of the request body exceeds this amount, the request will fail with
# 500 Server Error. Administrators should change this to an appropriate value
# for their site based on application requirements.
FcgidMaxRequestLen 1024000000
# FcgidMaxRequestInMem n (64k bytes)
# This module reads the entire request body from the client before sending it to the application.
# Normally the request body will be stored in memory. Once the amount of request body read
# from the client exceeds FcgidMaxRequestInMem bytes, the remainder of the request body
# will be stored in a temporary file.
FcgidMaxRequestInMem 1024000000
# Pass the Authorization to the script
FcgidPassHeader Authorization
<IfModule mod_mime.c>
AddHandler fcgid-script .php
AddHandler fcgid-script .fcgi
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
</IfModule>
<Files ".user.ini">
Require all denied
</Files>
</IfModule>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
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
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>
Nun aktivieren wir die VirtualHost Dateien mit a2ensite <FILE>
und starten den Apache Webserver neu.
root:~# a2ensite user1
root:~# a2ensite user2
root:~# systemctl restart apache2