FreeBSD — Настройка Nginx + PHP-FPM в chroot

Давно у меня в голове засела идея избавиться от apache2 на своих серверах. Зачем нужен этот древний тяжеленный мамонт? Ради модуля php? Ну так все хостинги давно уже обкатали режим php-fpm -это когда специфически собранный PHP работает сам по себе как сервис для компиляции php файликов. Стабильность и функциональность данного варианта работы PHP отличная! Остается статика, всякие картинки, стили, java-скрипты …. тут среди попсовых решений Nginx впереди планеты всей! Таким образом получаем простенькую систему из PHP-FPM + Nginx способную заменить Apache2 + mod_php + PHP. К тому же для большей безопасности и гибкости в настройке PHP-FPM поддерживает pools — это значит что PHP под каждый отдельный web-ресурс можно сконфигурить отдельно, к примеру сайту #1 дать 64MB RAM, а сайту #5 — 2048MB и тд, а любые превышения лимитов одним пулом не будут влиять на работу других. Для большей безопасности каждый пул можно разместить в его личном chroot-окружении, что на уровне FS изолирует все пулы друг от друга. Сладко??? Тогда в бой!
Установка PHP с флагом FPM:
Устанавливаем порт /usr/ports/lang/php5 с опцией PHP-FPM. При необходимости устанавливаем /usr/ports/lang/php5-extensions
Установка nginx:
Также из портов устанавливаем nginx, у меня он собран с такими опциями:

HTTP=on: Enable HTTP module
HTTP_ADDITION=on: Enable http_addition module
HTTP_CACHE=on: Enable http_cache module
HTTP_GZIP_STATIC=on: Enable http_gzip_static module
HTTP_GUNZIP_FILTER=on: Enable http_gunzip_filter module
HTTP_IMAGE_FILTER=on: Enable http_image_filter module
HTTP_PERL=on: Enable http_perl module
HTTP_REALIP=on: Enable http_realip module
HTTP_REWRITE=on: Enable http_rewrite module
HTTP_STATUS=on: Enable http_stub_status module
WWW=on: Enable html sample files

Не забываем про автозагрузку сервисов:
В /etc/rc.conf добавляем такие строчки для автостарта сервисов nginx и php-fpm

# <= Nginx => #
nginx_enable="YES"
# <= PHP-FPM => #
php_fpm_enable="YES"

Создание пользователя и окружения для chroot:
Создаем юзера, который у нас будет использоваться для виртуального web-хостинга. У меня это wwwuser. В его домешнем каталоге создаем необходимые директории для chroot php-fpm:

root@srv1:~# cd /home/wwwuser
root@srv1:/home/wwwuser# mkdir wwwchroot
root@srv1:/home/wwwuser# mkdir wwwchroot/{etc,htdocs,logs,tmp,usr}
root@srv1:/home/wwwuser# mkdir wwwchroot/usr/local
root@srv1:/home/wwwuser#

Создаем симлинки на некоторые конфиги и сокет mysql-сервера:

root@srv1:/home/wwwuser# cd wwwchroot/
root@srv1:/home/wwwuser/wwwchroot# ln -s /etc/hosts etc/hosts
root@srv1:/home/wwwuser/wwwchroot# ln -s /etc/host.conf etc/host.conf
root@srv1:/home/wwwuser/wwwchroot# ln -s /etc/resolv.conf etc/resolv.conf
root@srv1:/home/wwwuser/wwwchroot# ln -s /etc/nsswitch.conf etc/nsswitch.conf
root@srv1:/home/wwwuser/wwwchroot# ln -s /etc/localtime etc/localtime
root@srv1:/home/wwwuser/wwwchroot# ln -s /tmp/mysql.sock tmp/mysql.sock

Создаем симлинки на библиотеки:

root@srv1:/home/wwwuser/wwwchroot# ln -s /lib lib
root@srv1:/home/wwwuser/wwwchroot# ln -s /usr/local/lib usr/local/lib
root@srv1:/home/wwwuser/wwwchroot#

Настройка php-fpm:
Для удобства я «розбил» конфигурацию на основную часть [global] в конфиге /usr/local/etc/php-fpm.conf и настройки каждого веб-ресурса [pool] отдельно в директории /usr/local/etc/fpm.d/
Содержимое основного конфига:

include=etc/fpm.d/*.conf
[global]
pid = run/php-fpm.pid
events.mechanism = kqueue

Конфиги веб ресурсов нужно создавать в директории /usr/local/etc/fpm.d/. Их может быть много, поэтому удобно каждому юзеру создавать отдельный файлик. Вот пример содержимого одного из таких конфигов — /usr/local/etc/fpm.d/wwwuser_pool.conf:

[wwwuser]
prefix = /usr/home/$pool
user = wwwuser
group = wwwuser
listen = wwwchroot/tmp/php5-fpm.sock
listen.owner = www
listen.group = www
listen.mode = 0600

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 50
 
slowlog = logs/$pool.log.slow
request_slowlog_timeout = 5
request_terminate_timeout = 25
 
chroot = $prefix/wwwchroot
chdir = /htdocs
 
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f wwwuser@srv1.mydomain.ua
php_flag[display_errors] = off
php_admin_value[error_log] = /var/log/fpm-php.www.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 32M

После этого у вас должен нормально запуститься сервис php-fpm. Пробуем:

root@srv1:~# service php-fpm start
Starting php_fpm.
root@srv1:~#

Отлично! Поехали дальше!
Настройка nginx:
Тут я не очень разобрался, но скажем так, добился реально рабочего результата. Поэтому с удовольствием прочитаю замечания по настройке nginx в комментах. В стандартный конфиг /usr/local/etc/nginx/nginx.conf добавил секцию server для CMS Drupal версии 7:

    server {
        listen       80;
        server_name  mydomain.kiev.ua www.mydomain.kiev.ua;

        gzip on;
        gzip_static on;
        gzip_vary on;
        gzip_http_version 1.1;
        gzip_min_length 700;
        gzip_comp_level 6;
        gzip_disable "msie6";

        access_log  /usr/home/wwwuser/logs/drupal-access.log;
        error_log   /usr/home/wwwuser/logs/drupal-error.log;

        root /usr/home/wwwuser/wwwchroot/htdocs/drupal7;

        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }
 
        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }

        # Very rarely should these ever be accessed outside of your lan
        location ~* \.(txt|log)$ {
                allow 127.0.0.0/8;
                deny all;
        }
 
        location ~ \..*/.*\.php$ {
                return 403;
        }
 
        # No no for private
        location ~ ^/sites/.*/private/ {
                return 403;
        }
 
        # Block access to "hidden" files and directories whose names begin with a
        # period. This includes directories used by version control systems such
        # as Subversion or Git to store control files.
        location ~ (^|/)\. {
                return 403;
        }

        location / {
                # This is cool because no php is touched for static content
                try_files $uri @rewrite;
        }
 
        location @rewrite {
                # You have 2 options here
                # For D7 and above:
                # Clean URLs are handled in drupal_environment_initialize().
                rewrite ^ /index.php;
                # For Drupal 6 and bwlow:
                # Some modules enforce no slash (/) at the end of the URL
                # Else this rewrite block wouldn't be needed (GlobalRedirect)
                #rewrite ^/(.*)$ /index.php?q=$1;
        }

        location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_intercept_errors on;
        fastcgi_param SCRIPT_FILENAME /htdocs/drupal7$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT /htdocs/drupal7;
        fastcgi_pass   unix:/usr/home/wwwuser/wwwchroot/tmp/php5-fpm.sock;
        include        fastcgi_params;
                 }

        # This is for D7 and D8
        location ~ ^/sites/.*/files/styles/ {
                try_files $uri @rewrite;
        }
 
        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }
       
        location ~ /\. {
        deny  all;
        }
    }

Как видно из конфига, drupal у меня установлен в отдельной директории в htdocs, вот полный путь — /usr/home/wwwuser/wwwchroot/htdocs/drupal
После сохранения конфига можно запустить nginx:

root@srv1:~# service nginx start
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.
root@srv1:~#

Ну и после этого пробуем в браузере открыть наш сайт: http://mydomain.kiev.ua Я розпаковал в директорию drupal сам CMS — поэтому увидел приглашение к установке … все заработало с «пол-пинка». Пробовал аналогичный образом настраивать wordpress и phpBB — отлично работает, правда настройки в nginx.conf под разные движки разные, но найти их не составляет труда, зачастую на официальных сайтах разработчиков web-приложений есть готовые примеры конфига nginx.

Хай щастить!

  1. Комментов пока нет

  1. Трэкбэков пока нет.

Why ask?