Настраиваем nginx и php-fpm

Сегодня мы научимся устанавливать веб службы на слабые сервера. Точнее, даже, не обязательно на слабые. Просто, для разнообразия, мы откажемся от использования стандартной LAMPы (Linux+Apache+MySQL+PHP). Ещё точнее, мы откажемся от использования Apache. Мы будем настраивать связку nginx + php-fpm + MySQL. В первой части статьи мы поднимем наш сервер.

Начнём с того, что у нас есть сервер с только что поставленной CentOS 6.6.  Сервер функционирует в сети с доменным суффиксом local, включённым DHCP и работающим DNS, разрешающим имена в зоне local. Для сокращения текста, все команды мы будем выполнять из контекста root-а. Для начала — обновим систему:

[admin@sandbox ~]$ su -
Password:
[root@sandbox ~]# yum update
[root@sandbox ~]#

Теперь можно устанавливать nginx. В официальных репозиториях необходимого нам пакета нет, по этому мы создадим файл для официального репозитория nginx.org:

[root@sandbox ~]# cat /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
[root@sandbox ~]#

После чего устанавливаем nginx традиционным путём. Не забываем включить выполнение nginx при старте системы командой chkconfig:

[root@sandbox ~]# yum install nginx
[root@sandbox ~]# chkconfig nginx on
[root@sandbox ~]#

Забудем пока про nginx, он, надеюсь, без ошибок установился у нас. Теперь будем устанавливать MySQL. Тут всё тоже довольно тривиально, но на всякий случай напомню. Устанавливаем через yum обе части — mysql и mysql-server, включаем запуск при загрузке и запускаем mysqld. Теперь выполняем скрипт безопасной установки, который почистит свежепоставленный MySQL от ненужного хлама, заменит пароль рутовому пользователю и ограничит для него подключения. Попутно, памятуя о будущей безопасности, засунем mysql.pid в будущее chroot окружение:

[root@sandbox ~]# yum install mysql mysql-server
[root@sandbox ~]# chkconfig mysqld on
[root@sandbox ~]# service mysqld start
Starting mysqld: [ OK ]
[root@sandbox ~]# /usr/bin/mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY!

In order to log into MySQL to secure it, we'll need the current
password for the root user. If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.

Set root password? [Y/n] y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!


By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them. This is intended only for testing, and to make the installation
go a bit smoother. You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] y
... Success!

Normally, root should only be allowed to connect from 'localhost'. This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] y
... Success!

By default, MySQL comes with a database named 'test' that anyone can
access. This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] y
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] y
... Success!

Cleaning up...

All done! If you've completed all of the above steps, your MySQL
installation should now be secure.

Thanks for using MySQL!
[root@sandbox ~]# mkdir -p /var/www/var/run/mysqld
[root@sandbox ~]# mount --bind /var/run/mysqld/ /var/www/var/run/mysqld/
[root@sandbox ~]#

На данном этапе MySQL нам тоже больше не нужен. Теперь перейдём к установке php. Для начала подключим два репозитория — EPEL и REMI. Они, кстати, вполне могут пригодиться и не только в рамках данной статьи — в них много полезнейших пакетов, которые обновляются раньше, чем в официальных репах.

[root@sandbox ~]# yum install yum-priorities
[root@sandbox ~]# rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
[root@sandbox ~]# rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

REMI нам сейчас лучше включить, так как установка всей требухи php будет происходить именно с него:

[root@sandbox ~]# cat /etc/yum.repos.d/remi.repo
[remi]
name=Les RPM de remi pour Enterprise Linux 6 - $basearch
#baseurl=http://rpms.famillecollet.com/enterprise/6/remi/$basearch/
mirrorlist=http://rpms.famillecollet.com/enterprise/6/remi/mirror
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi

[root@sandbox ~]#

Всё, можно смело ставить php-fpm и прочие пехапешные необходимости всё тем же традиционным yum. Не забываем включить старт при загрузке:

[root@sandbox ~]# yum install php php-fpm
[root@sandbox ~]# yum install php-gd php-mysql php-mbstring php-xml php-mcrypt
[root@sandbox ~]# yum install php-mysql php-gd php-imap php-ldap php-mbstring php-odbc php-pear php-xml php-xmlrpc
[root@sandbox ~]# chkconfig php-fpm on

Установка завершена!

Создадим директории для нашего будущего хоста и для логов php-fpm в chroot, назначим необходимые права на них и, для экспериментов, создадим в корневой директории нашего хоста файл index.php, который будет нам отдавать результат выполнения phpinfo:

[root@sandbox ~]# mkdir -p /var/www/sandbox
[root@sandbox ~]# mkdir -p /var/www/var/log/php-fpm
[root@sandbox ~]# chwon nginx:nginx /var/www/var/log/php-fpm
[root@sandbox ~]# echo "<?php phpinfo (); ?>" > /var/www/sandbox/index.php
[root@sandbox ~]# chown -R nginx:nginx /var/www/sandbox/
[root@sandbox ~]# chmod -R 750 /var/www/sandbox/
[root@sandbox ~]# ln /etc/hosts /var/www/etc/hosts
[root@sandbox ~]# ln /etc/resolv.conf /var/www/etc/resolv.conf
[root@sandbox ~]# ln /etc/localtime /var/www/etc/localtime
[root@sandbox ~]# cp -R /usr/share/zoneinfo/ /var/www/usr/share/

В конфигурационном файле php-fpm зададим пользователя и группу, от которых он будет выполняться

[root@sandbox ~]# cat /etc/php-fpm.d/www.conf | grep -6 'user/group'
; Default Values: user and group are set as the running user
;                 mode is set to 0660
;listen.owner = nobody
;listen.group = nobody
;listen.mode = 0660

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
; RPM: apache Choosed to be able to access some dir as httpd
user = nginx
; RPM: Keep a group allowed to write in log dir.
group = nginx
[root@sandbox ~]#

и зададим место, где будем его chroot-ить. chdir указывается здесь уже относительно chroot, будем внимательны

[root@sandbox ~]# cat /etc/php-fpm.d/www.conf | grep -10 'chdir'
; Chroot to this directory at the start. This value must be defined as an
; absolute path. When this value is not set, chroot is not used.
; Note: chrooting is a great security feature and should be used whenever
;       possible. However, all PHP paths will be relative to the chroot
;       (error_log, sessions.save_path, ...).
; Default Value: not set
chroot = /var/www

; Chdir to this directory at the start. This value must be an absolute path.
; Default Value: current directory or / when chroot
;chdir = /var/www
chdir = /

; Redirect worker stdout and stderr into main error log. If not set, stdout and
; stderr will be redirected to /dev/null according to FastCGI specs.
; Default Value: no
;catch_workers_output = yes

; Limits the extensions of the main script FPM will allow to parse. This can
; prevent configuration mistakes on the web server side. You should only limit
; FPM to .php extensions to prevent malicious users to use other extensions to
; exectute php code.
[root@sandbox ~]#

Естественно, не забываем выставить правильный часовой пояс в настройках php

[root@sandbox ~]# cat /etc/php.ini | grep -5 'date.timezone'
; Whether the CLI web server uses ANSI color coding in its terminal output.
cli_server.color = On

[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = Europe/Moscow

; http://php.net/date.default-latitude
;date.default_latitude = 31.7667

; http://php.net/date.default-longitude
[root@sandbox ~]#

 

Приступим теперь к конфигурированию нашеего хоста. Начнём с основного файла конфигурации nginx.

[root@sandbox ~]# cat /etc/nginx/nginx.conf
user nginx;                     # От этого пользователя будет работать nginx
worker_processes        1;      # Устанавливается значение по числу ядер процессора (процессоров)

timer_resolution        100ms;  # Уменьшается разрешение таймеров времени в рабочих процессах
worker_rlimit_nofile    8192;   # Изменяется ограничение на максимальное число открытых файлов для рабочих процессов.
worker_priority         -5;     # Увиличивается приоритет

error_log       /var/log/nginx/error.log;
pid             /var/run/nginx.pid;

events  {
    worker_connections 1024;    # Максимальное количество подключений на процесс
}

http {
    include     /etc/nginx/mime.types;
    access_log  /var/log/nginx/access.log;

    sendfile            on;     # Включается соответствующий системный вызов
    keepalive_timeout   65;     # Время открытого постоянного соединения
    tcp_nodelay         on;     # разрешает использование опции сокета TCP_NODELAY

    port_in_redirect    off;    # Запрет указания порта в редиректах nginx


    gzip                on;     # Включается сжатие данных сервером
    gzip_comp_level     3;      # Устанавливается степень сжатия
    gzip_disable        "msie6";# Запрещается сжатие для проблемного MS Internet Explorer 6
    gzip_min_length     1024;   # Устанавливается минимальный размер сжиаемого содержимого
    gzip_vary           on;     # Разрешается выдача в ответе поле заголовка “Vary: Accept-Encoding”
    gzip_proxied        any;    # Разрешается сжатие для всех проксированных запросов
    gzip_types          text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
                                # Разрешается сжатие для указанных MIME Types

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

И сконфигурируем наш хост.  Обращаем внимание на то, что в контексте location, отвечающем за обработку php, пути, передаваемые php-fpm, указываются относительно нашего будущего chroot

[root@sandbox ~]# cat /etc/nginx/conf.d/default.conf
server {
    listen              80;     # Устанавливается порт
    server_name         sandbox.local www.sandbox.local;
                                # Устанавливаются имена на которые отвечает сервер
    root        /var/www/sandbox;       # Устанавливается путь к каталогу с содержимым
    index       index.php;      # Устанавливается индексный файл

    location /  {
        try_files $uri $uri/ /index.php?q=$uri&$args; # Проверка существования файлов для обработки запроса
    }

    location ~* ^.+.(js|css|png|jpg|jpeg|gif|ico)$ {
        access_log        off; # Не заносить в access.log доступ к статичному содержимому
        expires           max; # Установить максимальное время кэширования
    }

    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;  # Указывает где слушает php-fpm
        fastcgi_index  index.php;       # Указывает индексный файл

        fastcgi_param  DOCUMENT_ROOT    /sandbox;
        fastcgi_param  SCRIPT_FILENAME  /sandbox$fastcgi_script_name;
        fastcgi_param  PATH_TRANSLATED  /sandbox$fastcgi_script_name;

        include fastcgi_params;
        fastcgi_param  QUERY_STRING     $query_string;
        fastcgi_param  REQUEST_METHOD   $request_method;
        fastcgi_param  CONTENT_TYPE     $content_type;
        fastcgi_param  CONTENT_LENGTH   $content_length;
        fastcgi_intercept_errors        on;
        fastcgi_ignore_client_abort     off;
        fastcgi_connect_timeout 60;
        fastcgi_send_timeout 180;
        fastcgi_read_timeout 180;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;
                                        # Устанавливаются параметры обращения к php_fpm
    }

    location = /favicon.ico {
        log_not_found   off;    # Не писать в логи попытки доступа к favicon.ico
        access_log      off;
    }

    location = /robots.txt {
        allow           all;    # Не писать в лог попытки доступа к robots.txt
        log_not_found   off;
        access_log      off;
    }

    location ~ /\.ht {
        deny            all;    # Запрет доступа к файлам .htpassword и .htaccess
    }

}
[root@sandbox ~]#

Мы уже почти закончили. Теперь нам осталось проверить конфигурацию nginx, запускаем его и php-fpm:

[root@sandbox ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@sandbox ~]# service nginx start
Starting nginx:                                            [  OK  ]
[root@sandbox ~]# service php-fpm start
Starting php-fpm:                                          [  OK  ]
[root@sandbox ~]#

и не забываем внести строку в наш файервол, которая разрешит нам подключаться на 80-й порт примерно так:

[root@sandbox sysconfig]# iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
2    ACCEPT     icmp --  anywhere             anywhere
3    ACCEPT     all  --  anywhere             anywhere
4    ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh
5    REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination
1    REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination
[root@sandbox sysconfig]# iptables -I INPUT 4 -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
[root@sandbox sysconfig]# iptables-save > /etc/sysconfig/iptables

теперь мы вполне можем обратиться к нашему хосту http://sandbox.local и насладиться выводом команды phpinfo();. Если, конечно, мы всё сделали правильно.

В следующей части я расскажу как на всё это накатить что-нибудь серьёзнее phpinfo  и как всё это оптимизировать ещё дальше…

Помогла заметка - поделись с другом:
    • tobsik
    • Сентябрь 29th, 2016

    Спасибо огромное за статью. очень помогла с настройкой.

  1. Сейчас совершенно нет времени написать вторую часть статьи, про то как заставить работать эту связку в chroot окружении с чем-то более-менее сложным, типа WordPress. Но руководствуясь этой статьёй уже можно получить вполне себе работоспособный сервер под нормальные задачи. Достаточно в /etc/php-fpm.d/www.conf закомментировать директивы chroot и chdir, а в секции location конфигурации хоста в nginx писать директивы так:
    fastcgi_param DOCUMENT_ROOT $document_root;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;

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

Оставьте эти два поля как есть:


 
Яндекс.Метрика