Настройка nginx от начала и до конца. Ubuntu/Debian. nginx + PHP + spawn-fcgi + XCache. Пошаговая инструкци
Apache хороший веб-сервер, распространенный, легко настраиваемый, но потребляющий немереное количество ресурсов сервера. Рано или поздно веб-мастера начинают задумываться о переходе на более легковесный веб-сервер, как правило это те, у кого высоконагруженные проекты, либо обладатели VDS/VPS серверов с ограниченными ресурсами. О настройке хорошо известного, который находится у многих на слуху, веб-сервера nginx с поддержкой PHP, я и хотел бы сегодня поговорить. Необходимо развеять миф у новичков о сложности настройки связки nginx + PHP. Не все так страшно, как многие это представляют. Сегодня я наглядно покажу начинающим администраторам, как собрать самую свежую версию nginx + spawn-fcgi.
Так как nginx не имеет своего модуля для работы с PHP, а сам PHP по умолчанию не может работать в режиме FastCGI, то для связи с nginx нужен посредник, в нашем случае посредником будет выступать spawn-fcgi.
Стоит немного пояснить, зачем это нужно. Само по себе создание процесса FastCGI прямо в веб-сервере имеет несколько недостатков: процесс FastCGI может быть запущен только локально, имеет те же права, что и веб-сервер, а так же имеет ту же base-dir, что и веб-сервер.
Как только Вы начнете использовать отдельный FastCGI сервер, чтобы снять нагрузку с веб-сервера, Вы сможете контролировать процесс FastCGI внешними программами, такими как spawn-fcgi.
spawn-fcgi используется, чтобы запустить FastCGI процесс в своём окружении, выставить ему user-id, group-id и сменить корневую директорию (chroot).
Приступим.
Если не установлен LAMP, устанавливаем пакеты без A (Apache):
sudo apt-get install php5-common php5-dev php5-mysql php5-sqlite php5-tidy php5-xmlrpc php5-xsl php5-cgi php5-mcrypt php5-curl php5-gd php5-mhash php5-pspell php5-snmp libmagick9-dev php5-cli mysql-server mysql-client libmysqlclient15-dev
Если Apache уже предустановлен, останавливаем его и убираем из загрузочных скриптов:
sudo /etc/init.d/apache2 stop sudo update-rc.d -f apache2 remove
Используем скрипт для настройки безопасности MySQL:
sudo mysql_secure_installation
Создаем пользователя, к примеру webmaster:
sudo adduser webmaster
Лично я для сборки бинарников из исходных кодов использую виртуальную машину, чтобы не захламлять продакшн сервер, Вы в праве сами выбирать как Вам поступать. Если Вы выбираете сборку на виртуальной машине, Вам необходимо будет установить следующие пакеты:
sudo apt-get install build-essential libssl-dev
Если Вы выберете сборку непосредственно на рабочем сервере, Вам все равно придется поставить эти пакеты, тем самым захламляя систему ненужными для работы библиотеками.
Скачиваем все необходимые для конечной компиляции пакеты:
http://sysoev.ru/nginx/download.html http://www.pcre.org/ http://www.zlib.net/
Можете воспользоваться для этого утилитой wget:
cd /usr/src wget http://sysoev.ru/nginx/nginx-0.8.31.tar.gz wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.00.tar.gz wget http://www.zlib.net/zlib-1.2.3.tar.gz
Распаковываем:
tar zxvf pcre-8.00.tar.gz tar zxvf zlib-1.2.3.tar.gz tar zxvf nginx-0.8.31.tar.gz
Конфигурируем nginx со всеми необходимыми нам модулями:
cd nginx-0.8.31 ./configure —user=webmaster —group=webmaster —sbin-path=/usr/local/sbin —with-http_ssl_module —with-pcre=../pcre-8.00 —with-zlib=../zlib-1.2.3
Для быстрой сборки deb-пакетов, мы воспользуемся удобной утилитой checkinstall. Если Вы предпочитаете сборку пакетов по всем правилам с включением init-скриптов в пакет, советую так и поступить, но так как все админы в какой-то степени лентяи и не любят выполнять лишние телодвижения, и я в этом случае не исключение, мы не будет собирать пакет по всем правилам, слишком маленькое приложение, чтобы тратить на это свое время. Воспользуемся checkinstall. Установим этот пакет из репозитория:
sudo apt-get install checkinstall
Конфигурацию мы уже сделали, компилируем приложение и собираем deb-пакет:
sudo make sudo checkinstall
Ответьте на вопросы, в результате в папке с исходниками появится пакет с расширением *.deb, который, в свою очередь, и будет установлен автоматически. Для обновления на новую версию, просто скачиваем свежие соурсы, собираем и переносим на продакшн сервер готовый *.deb пакет и устанавливаем:
sudo dpkg -i *.deb
Привожу пример своего конфига nginx.conf, который находится в папке ‘/usr/local/nginx’. В результате сайты будут добавляться очень просто, в стиле Debian (sites-available, sites-enabled). Конфиг снабжен подробными комментариями. На английском, уж извините, делал пометки для себя (комменты добавлю чуть позже):
user webmaster webmaster; worker_processes 4; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; #tcp_nopush on; tcp_nodelay off; keepalive_timeout 2; gzip on; gzip_comp_level 2; gzip_proxied any; gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; include /usr/local/nginx/sites-enabled/*; }
Создать папки ‘logs’, ‘sites-available’ и ‘sites-enabled’ в ‘/usr/local/nginx’. В папке ‘logs’ создать пустые файлы ‘access.log’ и ‘error.log’.
Создать и сохранить init-script с именем ‘nginx’ в ‘/etc/init.d’:
#!/bin/bash ### BEGIN INIT INFO # Provides: nginx # Required-Start: $all # Required-Stop: $all # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts the nginx web server # Description: starts nginx using start-stop-daemon ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/local/sbin/nginx NAME=nginx DESC=nginx test -x $DAEMON || exit 0 # Include nginx defaults if available if [ -f /etc/default/nginx ] ; then . /etc/default/nginx fi set -e . /lib/lsb/init-functions test_nginx_config() { if nginx -t $DAEMON_OPTS then return 0 else return $? fi } case "$1" in start) echo -n "Starting $DESC: " test_nginx_config start-stop-daemon —start —quiet —pidfile /var/run/$NAME.pid \ —exec $DAEMON — $DAEMON_OPTS || true echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon —stop —quiet —pidfile /var/run/$NAME.pid \ —exec $DAEMON || true echo "$NAME." ;; restart|force-reload) echo -n "Restarting $DESC: " start-stop-daemon —stop —quiet —pidfile \ /var/run/$NAME.pid —exec $DAEMON || true sleep 1 test_nginx_config start-stop-daemon —start —quiet —pidfile \ /var/run/$NAME.pid —exec $DAEMON — $DAEMON_OPTS || true echo "$NAME." ;; reload) echo -n "Reloading $DESC configuration: " test_nginx_config start-stop-daemon —stop —signal HUP —quiet —pidfile /var/run/$NAME.pid \ —exec $DAEMON || true echo "$NAME." ;; configtest) echo -n "Testing $DESC configuration: " if test_nginx_config then echo "$NAME." else exit $? fi ;; status) status_of_proc -p /var/run/$NAME.pid "$DAEMON" nginx && exit 0 || exit $? ;; *) echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2 exit 1 ;; esac exit 0
Выставим необходимые права:
sudo chmod +x /etc/init.d/nginx
Добавим в автозагрузку:
sudo update-rc.d -f nginx defaults
Теперь Вы можете запускать, останавливать и перезапускать nginx, используя следующие команды:
sudo /etc/init.d/nginx start sudo /etc/init.d/nginx stop sudo /etc/init.d/nginx restart
Привожу пример настройки виртуального хоста, комментарии присутствуют:
server { # 301 redirect on main domain without www # listen 80; server_name www.zerolab.net; rewrite ^/(.*) /$1 permanent; } server { listen 80; server_name zerolab.net; access_log /home/webmaster/logs/access.log; error_log /home/webmaster/logs/error.log; error_page 403 /errors/403.html; error_page 404 /errors/404.html; error_page 500 502 503 504 /errors/50x.html; location /errors/50x.html { internal; } location / { root /home/webmaster/www/zerolab.net; index index.php index.html index.htm; } # ReWrite rule for web-based frontend to Transmission-daemon # location /transmission/ { rewrite /transmission[/]?$ /transmission/web break; proxy_pass http://127.0.0.1:9091; } # Pass the PHP scripts to FastCGI server listening on 127.0.0.1:9090 # location ~ \.php$ { fastcgi_pass 127.0.0.1:9090; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /home/webmaster/www/zerolab.net$fastcgi_script_name; include fastcgi_params; } # Deny access to .htaccess files, if Apache’s document root # concurs with nginx’s one # location ~ /\.ht { deny all; } }
Включаем виртуальные хосты (создаем симлинк):
sudo ln -s /usr/local/nginx/sites-available/zerolab.net /usr/local/nginx/sites-enabled/zerolab.net
Устанавливаем PHP с поддержкой FastCGI, если еще не установлен:
sudo apt-get install php5-cgi
Скачиваем исходники spawn-fcgi:
http://redmine.lighttpd.net/projects/spawn-fcgi
Воспользуемся wget:
wget http://www.lighttpd.net/download/spawn-fcgi-1.6.3.tar.gz
Распаковываем, конфигурируем и собираем deb-пакет:
tar zxvf spawn-fcgi-1.6.3.tar.gz cd spawn-fcgi-1.6.3 ./configure sudo make sudo checkinstall
Создать и сохранить init-script с именем ‘php5-fcgi’ в ‘/etc/init.d’:
#!/bin/bash # ### BEGIN INIT INFO # # Provides: php5-fcgi # # Required-Start: $all # # Required-Stop: $all # # Default-Start: 2 3 4 5 # # Default-Stop: 0 1 6 # # Short-Description: starts the php5-cgi in fast-cgi mode # # Description: configure and starts php5-cgi processes in fast-cgi mode using spawn-fcgi # ### END INIT INFO # # PATH=/sbin:/bin:/usr/sbin:/usr/bin # SCRIPTNAME="/etc/init.d/php5-fcgi" # # FCGI_PIDFILE="/var/run/spawn-php5-fcgi.pid" # ## Абсолютный путь до spawn-fcgi # FCGI_DAEMON="/usr/local/bin/spawn-fcgi" # # ## PHP переключится на этого юзера и группу (делать такими же, как у nginx) # USER=webmaster # GROUP=webmaster # ## Абсолютный путь до php # FCGI_PROGRAM="/usr/bin/php5-cgi" # ## Количество запущенных процессов PHP-fcgi, см http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:PerformanceFastCGI#How-many-PHP-processes-do-I-need # PHP_FCGI_CHILDREN=10 # ## Максимальное количество запросов, которое обработает отдельный PHP — fcgi процесс до своего перезапуска # PHP_FCGI_MAX_REQUESTS=1000 # ## TCP порт, который будет слушать php-fcgi # FCGI_PORT="9090" # ## IP адреса, по которым будет доступен PHP-fcgi (через запятую) # FCGI_IP="127.0.0.1" # # test -x $FCGI_PROGRAM || exit 0 # test -x $FCGI_DAEMON || exit 0 # # set -e # # export PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS # # . /lib/lsb/init-functions # # case "$1" in # start) # log_daemon_msg "Starting spawn-fcgi" # if ! $FCGI_DAEMON -a $FCGI_IP -p $FCGI_PORT -f $FCGI_PROGRAM -u $USER -g $GROUP -C $PHP_FCGI_CHILDREN -P $FCGI_PIDFILE; then # log_end_msg 1 # else # log_end_msg 0 # fi # RETVAL=$? # ;; # stop) # log_daemon_msg "Killing all spawn-fcgi processes" # start-stop-daemon —stop —pidfile $FCGI_PIDFILE —signal 2 && log_end_msg 0 || log_end_msg 1 # #if killall —signal 2 php5-cgi > /dev/null 2> /dev/null; then # # log_end_msg 0 # #else # # log_end_msg 1 # #fi # RETVAL=$? # ;; # restart|force-reload) # $0 stop # $0 start # ;; # *) # echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 # exit 1 # ;; # esac # # exit $RETVAL
Выставим необходимые права:
sudo chmod +x /etc/init.d/php5-fcgi
Обновляем правила rc.d для автоматического запуска php5-fcgi при старте системы:
sudo update-rc.d php5-fcgi defaults
Теперь Вы можете запускать, останавливать и перезапускать spawn-fcgi, используя следующие команды:
sudo /etc/init.d/php5-fcgi start sudo /etc/init.d/php5-fcgi stop sudo /etc/init.d/php5-fcgi restart
Проверяем spawning:
ps xa | grep php5-cgi
Смотрим работу нашего веб-сервера:
Каждый раз, когда Вы открываете страничку динамического веб-приложения, веб-сервер обращается к PHP, который загружает запрошенный php-файл, все include() и require(), затем парсит их, компилирует в промежуточный байт-код (opcode) и исполняет. Причем в больших проектах процесс включения всех include файлов может занимать весьма продолжительное время. Поэтому были разработаны многочисленные PHP-кэшеры. Все они позволяют сохранять и повторно использовать скомпилированный байт-код PHP, что позволяет экономить время на сборку всех включений и их компиляцию, экономит процессорное время и оперативную память (причем весьма значительно). Помимо этого, они позволяют хранить в кэше переменные PHP и обращаться к ним при следующем вызове скрипта. Наиболее популярные из кэшеров – APC (Alternative PHP Cache), XCache и eAccelerator. Какой из этих кэшеров использовать — не особо принципиально, по производительности они не сильно отличаются. Я выбрал XCache.
Устанавливаем пакет php5-xcache:
sudo apt-get install php5-xcache
Создаем файл настроек ‘xcache.ini’ в ‘/etc/php5/conf.d’, на примере моего файла настроек:
[xcache-common] # configuration for php Xcache module extension = xcache.so [xcache.admin] xcache.admin.auth = On # Configure this to use admin pages xcache.admin.user = "ZeroChaos" ; xcache.admin.pass = md5($your_password) xcache.admin.pass = "7885cccb9b01ee06462b98b2e1aa366b" [xcache] ; ini only settings, all the values here is default unless explained ; select low level shm/allocator scheme implemenation xcache.shm_scheme = "mmap" ; to disable: xcache.size=0 ; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows xcache.size = 128M ; set to cpu count (cat /proc/cpuinfo |grep -c processor) xcache.count = 4 ; just a hash hints, you can always store count(items) > slots xcache.slots = 8K ; ttl of the cache item, 0=forever xcache.ttl = 0 ; interval of gc scanning expired items, 0=no scan, other values is in seconds xcache.gc_interval = 0 ; same as aboves but for variable cache xcache.var_size = 8M xcache.var_count = 4 xcache.var_slots = 8K ; default ttl xcache.var_ttl = 0 xcache.var_maxttl = 0 xcache.var_gc_interval = 300 xcache.test = Off ; N/A for /dev/zero xcache.readonly_protection = Off ; for *nix, xcache.mmap_path is a file path, not directory. ; Use something like "/tmp/xcache" if you want to turn on ReadonlyProtection ; 2 group of php won’t share the same /tmp/xcache ; for win32, xcache.mmap_path=anonymous map name, not file path xcache.mmap_path = "/dev/zero" ; leave it blank(disabled) or "/tmp/phpcore/" ; make sure it’s writable by php (without checking open_basedir) xcache.coredump_directory = "" ; per request settings xcache.cacher = On xcache.stat = On xcache.optimizer = On [xcache.coverager] ; per request settings ; enable coverage data collecting for xcache.coveragedump_directory and xcache_coverager_start/stop/get/clean() functions (will hurt executing performance) xcache.coverager = Off ; ini only settings ; make sure it’s readable (care open_basedir) by coverage viewer script ; requires xcache.coverager=On xcache.coveragedump_directory = ""
Не забудьте изменить логин и md5-хэш пароля. Вот и все, на этом настройка закончена. Заранее прошу прощения, если слишком подробно описаны банальные операции, но это лишь для того, чтобы не возникало лишних вопросов. Надеюсь Вам окажется полезной моя статья.