LAMP through fcgid with suexec
Взглянем на Apache+mod_php. Плюсы:
- настраивается максимально просто
- интерпретатор стартует вместе с каждым форком апача
Минусы:
- mpm_prefork далеко не самый быстрый
- все работает под одним пользователем (да-да, можно накрутить mod_itk)
В попытках сделать секьюрно и по возможности быстро я решил скрутить apache (mpm_worker) + mod_fcgid + suexec. Сам по себе CGI очень небыстр за счет того, что при каждом запросе подымается интерпретатор. FastCGI быстрее, так как интерпретатор держится отдельным процессом. А mod_fcgid – модуль, бинарно совместимый с mod_fastcgi, с новой стратегией управления процессами.
Suexec в свою очередь позволяет выполнять CGI/FastCGI/SSI с указанными uid/gid. Да-да, в системе будут заводиться реальные пользователи.
Расстановкой прав можно добиться того, что даже взломав один сайт злоумышленник не сможет увидеть другие сайты.
Приступим.
apt-get install apache2-mpm-worker apache2-suexec ache2-threaded-dev libapache2-mod-fcgid php5-cgi
Теперь когда у нас все есть, создадим скелет для будущих площадок.
mkdir -p /root/web/skel cd /root/web/skel mkdir {cgi-bin,etc,logs,tmp,www} chmod 770 tmp chmod 751 {etc,logs,www} cp /etc/php5/cgi/php.ini ./etc
Правим php.ini на предмет вывода ошибок и прочих мелких твиков.
Теперь сделаем враппер для самого обработчика (cgi-bin/php-cgi):
#!/bin/bash cd $CGI_BIN_DIR PHP_INI=../etc/php.ini if [ ! -f $PHP_INI ]; then PHP_INI=/etc/php5/cgi/php.ini fi exec /usr/bin/php5-cgi -c $PHP_INI
И делаем
chown -R 755 cgi-bin
cd /root/web
touch {adduser,awstats,vhost}.skel
touch add_site.sh && chmod +x add_site.shadduser.skel:
DSHELL=/bin/false DHOME=/var/www GROUPHOMES=no LETTERHOMES=no SKEL=/root/web/skel FIRST_SYSTEM_UID=2000 LAST_SYSTEM_UID=2999 FIRST_SYSTEM_GID=2000 LAST_SYSTEM_GID=2999 FIRST_UID=2000 LAST_UID=29999 FIRST_GID=2000 LAST_GID=2999 USERGROUPS=yes USERS_GID=100 DIR_MODE=0751 SETGID_HOME=no QUOTAUSER="" SKEL_IGNORE_REGEX="dpkg-(old|new|dist)"
awstats.skel:
LogFile="/var/www/#USER/logs/#SITE-access.log" SiteDomain="#SITE" HostAliases="localhost 127.0.0.1 REGEX[#SITE$]" Include "/etc/awstats/awstats.conf.local"
vhost.skel:
<virtualhost *>
ServerName #SITE
ServerAlias www.#SITE
DocumentRoot /var/www/#USER/www/#SITE/public_html
SuexecUserGroup #USER #USER
ScriptAlias /cgi-bin/ /var/www/#USER/cgi-bin/
<directory /var/www/#USER/www/#SITE/public_html>
Options -Indexes +ExecCGI
AllowOverride All
AddHandler fcgid-script .php
FCGIWrapper /var/www/#USER/cgi-bin/php-cgi .php
Order allow,deny
Allow from all
</directory>
ErrorLog /var/www/#USER/logs/#SITE-error.log
CustomLog /var/www/#USER/logs/#SITE-access.log combined
SetEnv AWSTATS_FORCE_CONFIG #SITE
<location /cgi-bin/awstats.pl >
AuthUserFile /var/www/#USER/etc/awstats.passwd
AuthName "Website stats for #SITE"
AuthType Basic
require valid-user
</location>
</virtualhost>add_site.sh:
#!/bin/bash if [ -z $1 ] || [ -z $2 ]; then echo "Oops. Some param not given." exit 1 fi # If no such user exists - add one right now if [ ! -d /var/www/$2 ]; then adduser --conf ./adduser.skel --disabled-login --gecos '' $2 || exit 1 fi # Buld generic folders mkdir -p /var/www/$2/www/$1/public_html chown -R $2:$2 /var/www/$2/www/$1 # Build generic vhost for apache cat vhost.skel | sed "s/#USER/${2}/g;s/#SITE/${1}/g" > ${2}_${1} # Activate vhost a2ensite ${2}_${1} # Build generic awstats config cat awstats.skel | sed "s/#USER/${2}/g;s/#SITE/${1}/g" >> /etc/awstats/awstats.${1}.conf echo "Restart apache..." apache2ctl configtest && apache2ctl restart
Вот таким нехитрым образом можно добавить сайт:
cd /root/web ./add_site example.org web_example
В результате будет создан пользователь web_example и у него сайт – example.org.
Tip
Иногда надо позволить скрипту выполяться боее 30 секунд. Думаете для этого достаточно подправить php.ini?
Нет, в таком случае fcgid отстрелит скрипт по достижении 40 секунд. Для этих случаев в конфиге vhost’а
требуется задать значение IPCCommTimeout в секундах (например, 300). Есть баг – глобальное значение
отчего-то не хочет применяться к vhost’у, потому надо указать его непосредственно в vhost’е.
В общем и целом – конфиги показал, идею донес (надеюсь). Enjoy.