PLD + apache2 + suexec + fcgi + php = działa
kwiecień 2nd, 2008Oj poświęciłem nieco czasu i nerwów aby zmusić cały komplet software wymieniony w tytule posta do działania.
- maksymalne bezpieczeństwo i elastyczność
- jak najwięcej elementów konfiguracyjnych przeniesionych do katalogu użytkownika
Na początek niezbędne paczki (poza ‘podstawowymi’ apache)
apache-suexec
apache-mod_fastcgi
apache-mod_env
apache-mod_alias
apache-mod_actions
apache-mod_negotiation
php-fcgi
php-posix
php-common
Wymyśliłem sobie, że cała struktura vhostów będzie przechowywana w ścieżce podobnej do:
/home/services/hosting/user1
a w nim min. katalogi
php tmp websites
zawartość php to php.ini a websites jak nazwa wskazuje ![]()
[root@v300301 env]#ls websites/www1.dev.eqax.pl/
cgi-bin env error-pages htdocs icons logs tmp
Na pierwszy ogień fcgi. W PLD jest to plik /etc/httpd/conf.d/90_mod_fastcgi.conf
<IfModule mod_fastcgi.c>
FastCgiWrapper /usr/sbin/suexec
FastCgiIpcDir pipes
FastCgiConfig -singleThreshold 100 -killInterval 300 \
-pass-header HTTP_AUTHORIZATION -autoUpdate \
-idle-timeout 240 -maxProcesses 30 -maxClassProcesses 10
AddType application/x-httpd-php .php
AddType application/x-httpd-php .php3
AddType application/x-httpd-php .php4
AddType application/x-httpd-php .php5
AddType application/x-httpd-php .inc
AddType application/x-httpd-php .phtml
AddHandler fastcgi-script .fcgi .fcg .fpl
AddHandler php-fastcgi .php .php3 .php4 .php5 .inc .phtml
Action php-fastcgi /fcgi-bin/php.fcgi
<Location /fcgi-bin/php.fcgi>
Options +ExecCGI
SetHandler fastcgi-script
</Location>
</IfModule>
Tutaj pierwsze uwagi. Aktualnie nie 'rozdrabniamy' się na obsługę php4 i php4 poprzez oddzielne wrappery. Zdefiniowaliśmy typy rozszerzeń plików które mają być interpretowane przez php-fcgi. Wrapper FCGI otrzymuje pewne parametry
oraz globalnie definiujemy parametry dla wrappera /fcgi-bin/php.fcgi
Poniżej pełna konfiguracja vhosta
<VirtualHost *:80>
ServerName www.dev.eqax.pl
ServerAlias www1.dev.eqax.pl
ServerAdmin daniel@sardzent.org
SuexecUserGroup "#1000" "#1000"
#SuexecUserGroup "user1" "users"
# do wyboru albo username i groupname
# lub jako uid oraz gid
ServerSignature Off
LogLevel info
ErrorLog "|/usr/sbin/rotatelogs /home/services/hosting/user1/websites/www1.dev.eqax.pl/logs/error.%Y-%m.log 10M"
CustomLog "|/usr/sbin/rotatelogs /home/services/hosting/user1/websites/www1.dev.eqax.pl/logs/access.%Y-%m.log 25M" combined
DocumentRoot "/home/services/hosting/user1/websites/www1.dev.eqax.pl/htdocs/"
#
<Directory />
Options Indexes MultiViews SymLinksIfOwnerMatch
AllowOverride FileInfo Indexes Limit
<IfModule mod_authz_host.c>
Order allow,deny
Allow from all
</IfModule>
</Directory>
#
Alias /error/ "/home/services/hosting/user1/websites/www1.dev.eqax.pl/error-pages/"
<Directory "/home/services/hosting/user1/websites/www1.dev.eqax.pl/error-pages">
Options IncludesNoExec
AllowOverride None
AddOutputFilter Includes html
AddHandler type-map var
<IfModule mod_authz_host.c>
Order allow,deny
Allow from all
</IfModule>
LanguagePriority pl en cs de es fr it ja ko nl pt-br ro sv tr
ForceLanguagePriority Prefer Fallback
</Directory>
#
ScriptAlias /cgi/ "/home/services/hosting/user1/websites/www1.dev.eqax.pl/cgi-bin/"
ScriptAlias /cgi-bin/ "/home/services/hosting/user1/websites/www1.dev.eqax.pl/cgi-bin/"
<Directory "/home/services/hosting/user1/websites/www1.dev.eqax.pl/cgi-bin">
Options Indexes MultiViews SymLinksIfOwnerMatch ExecCGI
AllowOverride None
SetHandler cgi-script
<IfModule mod_authz_host.c>
Order allow,deny
Allow from all
</IfModule>
</Directory>
#
# wlasciwa obsluga fcgi
Alias /fcgi-bin/ /home/services/httpd/fcgi/user1/
<Directory "/home/services/httpd/fcgi/user1">
AllowOverride FileInfo
Options -Indexes -MultiViews SymLinksIfOwnerMatch +ExecCGI -Includes
<IfModule mod_authz_host.c>
Order allow,deny
Allow from all
</IfModule>
</Directory>
</VirtualHost>
Pierwsze pytanie dlaczego tak dużo … bo TAK. Dlaczego wrapper jest wskazany w /home/services/httpd/fcgi/user1? Ponieważ tylko w ten sposób w PLD da sie wykorzystać suexec (zmienne zaszyte w czasie kompilacji, oraz nie można zapominać o
chown -R user1:users /home/services/httpd/fcgi/user1) . Gdy fcgi wrapper nie będzie znajdował się w scieżce z prefixem /home/services/httpd zobaczymy w logach (/var/log/httpd/suexec_log oraz /var/log/httpd/error_log)
suexec policy violation: see suexec log for more details
Jeśli nie interesuje nas suexec to można wskazać dowolna ścieżkę, w tym także w katalogu roboczym user1.
Jak wygląda wrapper?
[root@v300301 env]#cat /home/services/httpd/fcgi/user1/php.fcgi
#!/bin/sh
PHP_FCGI_CHILDREN=3
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=2000
export PHP_FCGI_MAX_REQUESTS
exec /usr/bin/php.fcgi -c /home/services/hosting/user1/websites/www1.dev.eqax.pl/env/php.ini
Jak więc wygląda php.ini?
[root@v300301 env]# pwd
/home/services/hosting/user1/websites/www1.dev.eqax.pl/env
[root@v300301 env]# ls -lah php.ini
lrwxrwxrwx 1 root root 20 2008-04-02 09:48 php.ini -> ../../../php/php.ini
[root@v300301 env]# cat ../../../php/php.ini
; STARTPARSER
main_domain = "www1.dev.eqax.pl"
main_user = "user1"
main_admin = "owner@users.eqax.pl"
main_prefix = "/home/services/hosting"
main_work_dir = ${main_prefix}"/"${main_user}"/websites/"${main_domain}
main_root_dir = ${main_work_dir}"/htdocs"
main_date = "2008-04"
; ENDPARSER
open_basedir = ${main_root_dir}"/:/usr/lib/php/"
disable_functions = proc_open, popen, disk_free_space, diskfreespace, leak, exec, system, shell_exec, passthru, dl, show_source
expose_php = Off
log_errors = On
error_reporting = E_ALL
display_errors = Off
error_log = ${main_work_dir}"/logs/php."${main_date}".log"
log_errors_max_len = 104857600
date.timezone = "Europe/Warsaw"
enable_dl = Off
allow_url_fopen = Off
allow_url_include = Off
register_globals = Off
session.cookie_domain = ${main_domain}
sendmail_from = ${main_admin}
upload_tmp_dir = ${main_work_dir}"/tmp"
session.save_path = ${main_work_dir}"/tmp"
soap.wsdl_cache_dir = ${main_work_dir}"/tmp"
safe_mode = On
magic_quotes_gpc = on
max_execution_time = 60
max_input_time = 60
memory_limit = 32M
post_max_size = 4M
upload_max_filesize = 8M
Mamy więc link symboliczny php.ini, który wskazuje na plik php.ini w katalogu użytkownika.
Ostatnim etapem jest dopisanie odpowiednich linijek dla user1 w pliku /etc/security/limits.conf. Polecam rss, nproc, nofile, data.
Powinno działać … przynajmniej u mnie działa
Chciałbym podziękować Michałowi Abramowiczowi (evilabram) za pomoc ponieważ gdyby nie jego wskazówki nie dokopałbym się do tego że suexec ma prekompilowane ścieżki a enigmatyczny /var/log/httpd/suexec_log nie pomagał.
kwiecień 2nd, 2008 at 9:55 am
Cześć!
?
A co w przypadku gdy user może pisać se w php.ini
Niestety kompilacja suexec jest taka że plik php5.fcgi
ma być wł. usera, więc albo zmienić atrybut (taki zeby
nie mógł edytować) i zmienić se php.ini na inne
Albo połatać suexec tak żeby było dobrze
BLE!
kwiecień 2nd, 2008 at 10:05 am
Hmm ale liczy sie kolejność parsowania php.ini.
Jeśli najpierw jest php.ini usera a potem globlane to gdy user nakreci to i tak globalnie można zakazać pewnych operacji, ekstremalnie także php.ini przenieść do katalogu z wrapperem fcgi, czyli poza zasięg dostępu poprzez FTP
kwiecień 3rd, 2008 at 9:20 pm
mpm-peruser moze byc ciekawym rozwiazaniem:
http://blog.stuartherbert.com/php/2008/03/20/using-mpm-peruser-to-secure-a-shared-server/
kwiecień 3rd, 2008 at 10:10 pm
dziekować adamg ale czy uzywales juz tego ?