Это старая версия документа.
Содержание
Существуют различные схемы построения веб-серверов для передачи данных по протоколу HTTP. Среди них достойное место по производительности занимают схемы с использованием «Nginx» в качестве внешнего (кэширующего, front-end) сервера. «Nginx» разработан для отдачи статических данных, при этом, он показывает высокое быстродействие и нагрузочную способность (см. Nginx vs Cherokee vs Apache vs Lighttpd), генерировать же динамическое содержимое он не способен. Поэтому, он часто применяется в связке с внутренним (back-end) сервером для обработки динамических данных которые потом отдаются «Nginx» как статические без участия внутреннего сервера. В качестве внутреннего сервера может применяться «Apache2» или, что и рассматривается в данной статье, «PHP-FPM».
Установка
Сервер «Nginx» поставляется в одноименном пакете «nginx» и его установка производится, например, командой в терминале
sudo apt-get install nginx nginx-extras
Установку же «PHP-FPM» можно произвести, например, командой
sudo apt-get install php5-cli php5-common php5-mysql php5-gd php5-fpm php5-cgi php5-fpm php-pear php5-mcrypt
Безопасность
Наряду с уязвимостями присущими ПО сервера, присутствуют также те, что обусловлены неосторожностью администратора сервера. Для их устранения следует соблюдать меры предосторожности:
- Должно быть запрещено выполнение PHP-кода из открытых для записи директорий. Например, директории для загрузки аватаров, файлов или директории доступные также FTP-серверу, который позволяет произвести запись в них.
- Следует следить за логами работы сервера, это позволяет выявить попытку взлома как можно раньше и минимизировать угрозу дальнейшего ущерба.
- Необходимо обновлять ПО (в том числе «CMS» — системы управления содержимым сайтов), но не обязательно тогда когда выходят новые версии (они тоже могут содержать новые уязвимости), а, прежде всего, тогда, когда обновление связано с устранением серьезной уязвимости.
- Обязательное наличие файлов для отката состояния сервера (в том числе, конфигурационных файлов).
- Осторожное и осмотрительное следование подобным инструкциям (см. Don’t trust the tutorials: check your configuration!)
Настройка
Настройка состоит из двух этапов — настройки «Nginx» и «PHP-FPM». Для начала необходимо остановить процессы (демоны) «Nginx» и «PHP-FPM», например, командами
sudo service nginx stop sudo service php5-fpm stop
Настройка PHP-FPM
Прежде всего, следует открыть файл «/etc/php5/fpm/php.ini» для редактирования, например, командой
sudo nano /etc/php5/fpm/php.ini
после чего, найти строчку содержащую «cgi.fix_pathinfo», которая по-умолчанию выглядит так (закомментирована)
;cgi.fix_pathinfo = 1
и привести её к виду
cgi.fix_pathinfo = 0
Это призвано устранить опасность неправильно трактования (и возникающей уязвимости) запросов вида «/image.gif/foo.php» (см. Don’t trust the tutorials: check your configuration!, Nginx 0day exploit for nginx + fastcgi PHP).
Если планируется загрузка больших файлов (важно для ownCloud версий < 8, в новой версии 8 и выше имеется отдельный файл для этих настроек), то можно увеличить максимальный объем загружаемых данных, например, до 200 МБ
post_max_size = 200M
и ниже
upload_max_filesize = 200M
Затем сохранить изменения в файле.
Далее, необходимо отрыть для редактирования файл «/etc/php5/fpm/pool.d/www.conf», например, командой
sudo nano /etc/php5/fpm/pool.d/www.conf
найти строчку с параметров «security.limit_extensions» и привести её к виду
security.limit_extensions = .php .php3 .php4 .php5
Эта настройка ограничит выполнение файлов по расширению имени. В этом же файле найти строчку с параметром «listen» и привести её к виду
listen = /var/run/php5-fpm.sock
Это определит файл для связи «Nginx» с «PHP-FPM» (сокет). В целях безопасности запрещаем какой-попало программе писать в сокет (см. Обновление PHP 5.5.12 с устранением уязвимости в PHP-FPM ) путём указания прав доступа к сокету. Находим строчки с описанием параметров «listen.owner», «listen.group» и «listen.mode» (по-умолчанию они закомментированы) и приводим их к виду
listen.owner = www-data listen.group = www-data listen.mode = 0660
Следует сохранить изменения в файле и перезапустить «PHP-FPM», например, командой
sudo service php5-fpm restart
Можно убедится в том, что права доступа к сокету установлены верно:
ls -la /var/run/php5-fpm.sock
Права доступа должны быть «srw-rw—-», владелец «www-data» (группа «www-data»), например,
srw-rw---- 1 www-data www-data 0 May 2 16:36 /var/run/php5-fpm.sock
Настройка Nginx
Основные настройки «Nginx» хранятся в файле «/etc/nginx/nginx.conf». Настройки базового сайта хранятся в файле «/etc/nginx/sites-available/default». Базовый конфигурационный файл сайта принято помещать в папку «/etc/nginx/sites-available/» и затем включить его путём добавления символической ссылки на этот файл в папке «/etc/nginx/sites-enabled/». Например, создадим конфигурационный файл для сайта с доменным именем (для примера выбрано «example.com») в названии для удобства
sudo touch /etc/nginx/sites-available/example.com sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
и откроем его для редактирования
sudo nano /etc/nginx/sites-available/example.com
Описывать конфигурацию сайта в одном файле не очень удобно, для увеличения читабельности конфигурационного файла и гибкости настройки можно воспользоваться директивой «include» позволяющей указать «Nginx», что следует загрузить другой конфигурационный файл и затем продолжить чтение текущего. Создадим в папке «/etc/nginx/» каталог «common», где будут хранится общие настройки для сайта, которые затем будут подгружаться из основного конфигурационного файла «/etc/nginx/sites-available/example.com» с помощью директивы «include»
sudo mkdir /etc/nginx/common
Некоторые запросы «Nginx» будет перенаправлять к «PHP-FPM», который в данном случае называется сервером выгрузки данных (upstream). Укажем как следует это делать. Создадим файл конфигурации с описанием серверов выгрузки данных
sudo touch /etc/nginx/common/upstream
и откроем его для редактирования
sudo nano /etc/nginx/common/upstream
и добавим в него строчки
upstream php-fpm { # PHP5-FPM сервер server unix:/var/run/php5-fpm.sock; }
где «php-fpm» – название для сервера выгрузки данных, для удобства.
Редактируем файл «/etc/nginx/sites-available/example.com». Добавляем строчку
include common/upstream;
для загрузки созданого выше конфигурационного файла. Как можно видеть – допускается указание относительного пути к файлу.
Далее описываем перенаправление от HTTP к HTTPS, если, конечно, это планируется. В таком случае необходимо наличие сертификатов для HTTPS (см. Сертификаты)
server { listen 80; server_name example.com www.example.com; return 301 https://$server_name$request_uri; }
иначе, можно опустить эти строчки.
Начинаем описывать конфигурацию сайта
server {
Сетевой порт для приема соединений: 80 — обычный HTTP; 443 — HTTPS (см. выше)
# Порты listen 80; listen 443 ssl; # использовать шифрование для этого порта
Корневая директория сайта работающего на данном сервере
root /var/www;
Возможные имена индексных файлов (их «Nginx» пытается открыть если он получил запрос вида «example.com/», вместо явного «example.com/index.html»)
index index.php index.html index.htm;
Имя сервера – обычно доменное имя Вашего сервера
server_name example.com www.example.com;
Настройка шифрования SSL
Необходимо наличие сертификата «*.crt» или «*.pem» и приватного секретного ключа «*.key» (см. Сертификаты). Самоподписанный сертификат можно сгенерировать командой в терминале (см. man openssl, man req)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout example.com_nginx.key -out example.com_nginx.crt
При этом программа запросит данные, среди них «commmon name» — следует указать доменное имя сервера. Можно использовать шаблон, если необходимо учесть домены нижнего уровня, например, «*example.com». Иначе могут возникнуть проблемы с некоторыми программами, например, «davfs2» (см man davfs2.conf).
Но можно пойти дальше и воспользоваться сервисом «StartSSL» где выдают бесплатные сертификаты для личного пользования (см. startssl.com и Получение и установка бесплатного SSL-сертификата), но сам приватный ключ (который нельзя никому показывать) лучше сгенерировать самому, например, так
openssl genrsa -out example_nginx.com.key 4096
затем сформировать файл запроса на подпись (при этом прийдётся вводить те же данные что и для генерации самоподписанного сертификата, но это не важно, т.к. сервис «StartSSL» проигнорирует все кроме публичного ключа)
openssl req -new -sha256 -key example.com_nginx.key -out example.com.csr
открыть полученный файл текстовым редактором
nano example.com.csr
и скопировать его содержимое в текстовое поле на сайте «StartSSL» для запроса сертификата (см. ссылки на подробные инструкции выше). Файл *.csr больше не нужен. Затем загружаем подписанный сертификат (например, файл называется signed.crt) и объединяем его с сертификатом того кто этот сертификат подписал
wget https://www.startssl.com/certs/sub.class1.server.ca.pem cat signed.crt sub.class1.server.ca.pem > example.com_nginx.crt
Файл «signed.crt» можно удалить.
Копируем секретный ключ в системную папку и выставляем права доступа
sudo cp example.com_nginx.key /etc/ssl/private/ sudo chown www-data:www-data /etc/ssl/private/example.com_nginx.key sudo chmod 400 /etc/ssl/private/example.com_nginx.key
И в соседнюю папку сам сертификат
sudo cp example.com_nginx.crt /etc/ssl/certs/
Для пущей надежности можно сгенерировать ключ Диффи-Хеллмана (тоже секретный файл который очень долго генерируется)
openssl dhparam -out example.com.dh.key 4096 sudo cp example.com_nginx.dh.key /etc/ssl/private/ chown www-data:www-data example.com_nginx.dh.key chmod 400 example.com_nginx.dh.key
Продолжаем редактировать конфигурационные файлы.
Для удобства описываем настройки шифрования во внешнем файле «/etc/nginx/common/ssl»
sudo touch /etc/nginx/common/ssl
Редактируем файл «/etc/nginx/common/ssl»
sudo nano /etc/nginx/common/ssl
Файлы сертификатов для «HTTPS»
ssl_certificate /etc/ssl/certs/example.com_nginx.crt; # сертификат (можно свободно распространять) ssl_certificate_key /etc/ssl/private/example.com_nginx.key; # приватный ключ (секретный файл - НИКОМУ НЕ ПОКАЗЫВАТЬ)
Дополнительные параметры требуемые для «HTTPS»
ssl_dhparam /etc/ssl/private/example.com_nginx.dh.key; # писать эту строчку только если файл есть ssl_session_timeout 20m; # время 20 минут ssl_session_cache shared:SSL:20m; # размер кеша 20МБ ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK;
На этом настройки «SSL» в «Nginx» завершены, сохраняем и закрываем файл. После завершения описания конфигурации (см. ниже) можно будет проверить надежность сервисом «SSLLabs»
Продолжаем редактировать файл «/etc/nginx/sites-available/example.com». Подгружаем созданный выше конфигурационный файл с описанием настроек SSL
# Настройка шифрования SSL include common/ssl;
Различные настройки
Указание максимального размера запроса – необходимо если сервер будет использоваться для загрузки больших файлов (например, для построения небольшого облачного хранилища на основе «ownCloud», эта строчка по сути делает то же что и указанные выше при настройке «PHP-FPM», только теперь для «Nginx»)
client_max_body_size 200m; # увеличение максимального объема файла для загрузки до 200МБ
Ещё одна опция
# Buffers fastcgi_buffers 64 4K;
Настройки безопасности
Опишем настройки безопасности в отдельном файле
sudo touch /etc/nginx/common/security sudo nano /etc/nginx/common/security
И укажем в нём
add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff";
Сохраним и закроем файл, а затем подключим его строкой
include common/security;
Сжатие
Для экономии трафика лучше включить сжатие (иногда со влючённым сжатием могут возникать проблемы, например, у «ownCloud», см. ниже). Опишем настройки сжатия в отдельном файле
sudo touch /etc/nginx/common/gzip sudo nano /etc/nginx/common/gzip
и введём
gzip on; gzip_disable "msie6"; gzip_comp_level 6; gzip_min_length 1100; gzip_buffers 16 8k; gzip_proxied any; gzip_types text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/javascript application/json application/xml+rss;
Следует сохранить, закрыть и затем подключить этот файл срочкой
include common/gzip;
Описание директорий сайта
Далее указание директорий сайта и правил работы с ними с использованием директив «location». Данная директива может обрабатывать регулярные выражения «Perl» (см. Регулярные выражения (шаблоны))
Корневая директория
location "/" { index index.php index.html index.htm; # варианты индексных файлов если имя файла в запросе не задано try_files $uri $uri/ =404; # проверить есть ли файл из запроса на диске, иначе - вернуть ошибку 404 }
К примеру, если хочется построить сайт на основе «WordPress», то можно описать корневую директорию так
location "/" { index index.php index.html index.htm; try_files $uri $uri/ /wordpress/; # проверяем существования файла или папки, иначе перенаправляем к example.com/wordpress rewrite "^/$" "/wordpress/" redirect; # перенаправляем запрос example.com/ к example.com/wordpress }
Соответственно сам сайт должен размещаться в каталоге «/var/www/wordpress/»
Директории можно описывать по одной в этом же файле, но это не удобно и не наглядно. А можно указать строчку
include common/locations/*.inc;
которая укажет «Nginx», что нужно подключить все файлы в директории «/etc/common/locations/» которые соответствуют шаблону «*.inc», таким образом, если один из файлов нужно будет временно отключить, то его можно просто переименовать убрав расширение в имени. Создадим директорию где будут хранится эти файлы
sudo mkdir /etc/nginx/common/locations
Некая директория «/var/www/restricted» доступная только авторизованным пользователям сервера. Создадим для неё файл конфигурации «/etc/nginx/common/locations/restricted.inc»
sudo touch /etc/nginx/common/locations/restricted.inc sudo nano /etc/nginx/common/locations/restricted.inc
со строчками
location ^~ "/restricted/" { auth_basic "Access to this folder is restricted"; auth_basic_user_file htpasswd; autoindex on; allow all; try_files $uri $uri/ =404; }
Синтаксис «^~» указывает, что при совпадении здесь директивы «location» ниже проверяться не будут.
Этот конфигурационный файл подключится автоматически, за счёт шаблона (см. выше).
Для сайта на основе Wordpress
Для более полной информации по настройке «Nginx» для «WordPress» следует обратиться к официальной документации (см. codex.wordpress.org/Nginx и wiki.nginx.org/WordPress)
Натройки «Wordpress», который, в данном примере, находится в папке «/var/www/wordpress» будут описаны в файле «/etc/nginx/common/locations/wordpress.inc»
sudo touch /etc/nginx/common/locations/wordpress.inc sudo nano /etc/nginx/common/locations/wordpress.inc
Указываем виртуальную директорию (используется для удобства и читабельности) в которую будут перенаправляться запросы при необходимости
location @wordpress { rewrite "^/wordpress/(.*)$" "/wordpress/index.php?q=$1" last; }
Аналогично примеру выше предотвращаем обработку остальных директив «location»
location ^~ "/wordpress/" { root "/var/www"; index index.php; try_files $uri $uri/ @wordpress; # проверить существует ли файл, иначе направить в виртуальную директорию # Ограничение доступа к секретному файлу location ~* "^/wordpress/wp-config.php(/.*)?$" { deny all; return 404; } # Ни в коем случае не выполнять файлы php в папках куда их может кто-то загрузить # Проще всего просто заблокировать любые операции с такими файлами регулярным выражением location ~* "/(uploads|files)/.*\.php.?(/.*)?$" { deny all; return 404; } # Перенаправление php-файлов к серверу «PHP-FPM» см. ниже по статье location ~ "^(/wordpress/.+?\.php)(/.*)?$" { # Проверяем существование файлов, пробуем исправить если нет, иначе выдаём ошибку # $1 указывает на первую скобку в регулярном выражении выше - собственно адрес запрошенного php файла try_files $1 $uri $uri/ $uri/index.php =404; include common/php-fpm; } # Другие настройки, см. ниже по статье include common/deny; include common/cache; }
Сохраняем и закрываем этот файл. Опять же, он будет подключён автоматически.
Для облачного хранилища на основе ownCloud
Для наиболее полной информации следует обратится к официальному руководству «OwnCloud» (см. Nginx Configuration). К примеру, «ownCloud» находится в папке «/var/www/owncloud».
Создадим файл настроек для «ownCloud» и отредактируем его
sudo touch /etc/nginx/common/locations/owncloud.inc sudo nano /etc/nginx/common/locations/owncloud.inc
Многое аналогично примеру для «Wordpress»
location ^~ "/owncloud/" { root "/var/www"; index index.php index.html index.htm; try_files $uri $uri/ =404; # ownCloud предоставляет свои красивые страницы для ошибок 404 и 403 - используем их error_page 403 /owncloud/core/templates/403.php; error_page 404 /owncloud/core/templates/404.php; # Отключаем сжатие - оно создаёт проблемы для клиента синхронизации ownCloud gzip off; # Переопределяем глобальную настройку описанную в главном файле # увеличиваем максимальный размер загружаемых файлов client_max_body_size 16G; # Запрещаем читать секретные файлы location ~* "^/owncloud/(\.user\.ini|data|config|db_structure\.xml|README)(/.*)?$" { deny all; return 404; } location ~ "^(/owncloud/.+?\.php)(/.*)?$" { try_files $1 $uri $uri/ $uri/index.php =404; include common/php-fpm; } include common/deny; include common/cache; }
Начиная с версии «ownCloud» 8 появился отдельный файл для переопределения некоторых настроек «PHP-FPM» взамен указанных в «/etc/php5/fpm/php.ini». Открыть его можно командой
sudo nano /var/www/owncloud/.user.ini
и в нем найти строчки
upload_max_filesize=513M post_max_size=513M
и поменять значения на требуемые.
Базовые ограничения доступа
Выше было написана строчка для подключение файла «/etc/common/deny»
include common/deny;
рассмотрим его содержание. В нём идет запрет доступа к некоторым стандартным файлам. Создадим этот файл
sudo touch /etc/nginx/common/deny sudo nano /etc/nginx/common/deny
с содержанием
# Запрет доступа к .htaccess и .htpasswd файлам location ~* "/\.(htaccess|htpasswd)$" { deny all; # запретить все для всех return 404; # вернуть код ошибки }
Следует переписать все файлы «.htaccess» в директивы «Nginx». Найти эти файлы среди файлов сайта можно, например, командой
sudo find /var/www/ -name .htaccess
Перенаправление обработки php-скриптов внутреннему серверу «PHP-FPM»
В примерах выше использовался файл «/etc/common/php-fpm» — в нём идет перенаправление обработки php-скриптов внутреннему серверу «PHP-FPM»
Создаём этот файл
sudo touch /etc/nginx/common/php-fpm sudo nano /etc/nginx/common/php-fpm
с содержанием
# Настройки порта или сокета PHP-FPM производятся в файле "/etc/php5/fpm/pool.d/www.conf" fastcgi_pass php-fpm; # Порядок важен - строчка "include fastcgi_params" должна быть первой include fastcgi_params; fastcgi_split_path_info ^(.+?\.php)(/.*)?$; # Вместо переменной "$document_root" можно указать адрес к корневому каталогу сервера и это желательно (см. http://wiki.nginx.org/Pitfalls) fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name; # См. http://trac.nginx.org/nginx/ticket/321 set $path_info $fastcgi_path_info; fastcgi_param PATH_INFO $path_info; # Additional variables fastcgi_param SERVER_ADMIN avi9526@avi9526.pp.ua; fastcgi_param SERVER_SIGNATURE nginx/$nginx_version; fastcgi_index index.php;
Сохраняем и закрываем файл, подключаем его строчкой
include common/php-fpm;
в файле «/etc/nginx/sites-available/example.com». Закрываем фигурные скобки директивы «location»
}
Кеширование
Сайт работает значительно лучше когда часть контента сохранена на стороне клиента с прошлого посещения сайта. Не все файлы можно кешировать. Поэтому описание кеширования производится в самом конце (т.е. эти настройки будут иметь наименьший приоритет и есть шанс что это не повлияет на правильную работу сайта). Создаём файл с параметрами для кеширования
sudo touch /etc/nginx/common/cache sudo nano /etc/nginx/common/cache
где укажем
location ~* ".+\.(?:ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|css|swf|js|atom|jpe?g|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$" { access_log off; log_not_found off; expires max; }
и указываем считывать этот файл строчкой в «/etc/nginx/sites-available/example.com»
include common/cache;
Завершение редактирования конфигурации
Закрываем фигурные скобки директивы «server» в «/etc/nginx/sites-available/example.com»
}
На этом правка файла «/etc/nginx/sites-available/example.com» завершена. Убедитесь в том, что все фигурные скобки «{ }» закрыты корректно и части файла верно вложены друг в друга («location» внутри «server» и т.п.).
Сохраняем все изменённые файлы.
Теперь можно перезапустить демоны
sudo service nginx restart sudo service php5-fpm restart
Ссылки
- Обсуждение статьи на форуме forum.ubuntu.ru
- Сравнение быстродействия и нагрузочной способности веб-серверов Nginx vs Cherokee vs Apache vs Lighttpd
- Рекомендации по безопасности при развертывании веб-сервера на основе «Nginx» и «PHP-FPM» Don’t trust the tutorials: check your configuration!
- Синтаксис конфигурации «Nginx» HttpCoreModule
- Пример настройки связки «Nginx + PHP-FastCGI» PHPFcgiExample
- Рекомендации по написанию удачной конфигурации для «Nginx» Pitfalls
- Работа с сертификатами в «Ubuntu» Сертификаты
- Рекомендации по обеспечению безопасности при работе с сайтом на основе «Dokuwiki» Web Access Security
- Рекомендации по обеспечению безопасности при настройке облачного хранилища на основе «ownCloud» Webserver Notes