====== Nginx ======
===== Сведения =====
:!: Общее
Эффективное использование ресурсов, отзывчив под нагрузкой.\\
Используется как веб так и прокси сервер.\\
Спроектирован на базе асинхронных неблокирующих event-driver алгоритмов, сервер однопоточный и не создает процессы под каждое соединение, использование ресурсов относительно равномерно.
**Динамический контент**\\
Nginx не имеет возможности самостоятельно обрабатывать запросы к динамическому контенту (например php), для этого он передает запрос внешнему процессу (например [[:linux:php|php-fpm]]) и ожидает результата. \\
На каждый запрос создается отдельное соединение с процессом. (плюс в экономии на статических запросах).\\
Взаимодействие может быть по одному из следующих протоколов: http, FastCGI, SCGI, uWSGI, memcache.\\
**Интерпретация запросов**\\
В отличии от сервера [[:linux:apache|Apache]], Nginx интерпретирует запросы в первую очередь как URL а не как пути в файловой системе.\\
Во многом из-за своего Альтер Эго в роли прокси сервера, из-за чего и не реализует поддержку файлов .thaccess.
**Модули**\\
В отличии от [[:linux:apache|Apache]], в Nginx модули не являются динамическими, а должны компилироваться с ядром сервера.
**Совместное использование с Apache**\\
Очень частая практика использования обоих серверов вместе, Nginx ставится в качестве реверс-прокси, т.е. фронтенд а [[:linux:apache|Apache]] бэкенд.\\
Nginx самостоятельно обслуживает статический контент а динамический передает [[:linux:apache|Apache]].\\
в такой конфигурации можно ставить несколько бэкендов, таким образом хорошо масштабировать систему.
===== Установка =====
Подключаем репозиторий:\\
# echo "deb http://nginx.org/packages/debian `lsb_release -cs` nginx" | tee /etc/apt/sources.list.d/nginx.list
Импортируем ключ для него:
# curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
Устанавливаем:
# apt update && apt install nginx
Проверяем/включаем запуск/автозапуск
# systemctl start/enable nginx
===== Конфигурация =====
Проверка конфигурации:
# nginx -t
Вывести полный конфиг на экран:
# nginx -T
Применение новой конфигурации без перезагрузки сервера:
# nginx -s reload
Информация о версии и модулях:
# nginx -v
==== Виртуальные хосты ====
Виртуальный хост - это конфиг, который описывает настройку одного домена, для удобства каждый виртуальный хост в отдельном конфиге, но можно это делать и в общем.\\
Конфиги с виртуальными хостами расположены в **/etc/nginx/conf.d/**\\
Виртуальные хосты наследуют параметры из основного файла конфигурации - **/etc/nginx/nginx.conf**, эти параметры могут быть переопределены в каждом виртуальном хосте. Наследуются все явно не указанные параметры.\\
==== Location ====
**В виртуальных хостах** управляем настройками в зависимости от домена, **а тут** в зависимости от пути запроса.\\
Location можно задавать **префиксной строкой** или **регулярным выражением** (используются модификаторы:
* **~** - учитывается регистр
* **~*** - не учитывается)\\
Сначала проверяются **префиксные строки**, совпадения запоминаются, затем **регулярные выражения**, в порядке перечисления, если совпадает, то исполняется, если нет, то исполняется запомненный ранее префикс.\\
Так же, можно использовать префикс **=**, он означает точное совпадение запроса и заданного location. После совпадения, остальные проверки прекращаются.\\
** Пример: ** Укажем максимальный срок хранения картинок в кэше и отключим логирование:
location ~* ^.+.(js|css|png|jpg|jpeg|gif|ico|swf|ttf|svg)$
{
access_log off;
expires 1y;
}
** Пример: ** Запретим исполнение скриптов в перечисленных директориях:
location ~* /(images|cache|media|logs|tmp)/.*.(php|pl|py|jsp|asp|sh|cgi)$
{
return 404;
}
==== Работа с php-fpm ====
Устанавливаем и настраиваем [[:linux:php|php-fpm]].\\
Далее, достаточно только указать в виртуальном хосте **Location** для php:
location ~* \.php$
{
fastcgi_pass unix:/run/php/php7.1-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
** Расширенный пример: **
location ~ \.php$
{
try_files $uri =404;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
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_param HTTPS on; # включать, если сайт по https работает
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;
}
==== Прокси ====
Проксирование происходит с помощью блока Location, и директивы **proxy_pass**.\\
**Пример: ** Все запросы содержащие **/forum/** будут направлены на отдельный сервер
location /forum/
{
proxy_pass http://192.168.13.31;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect default;
}
:!: Пример с заббиксом
По умолчанию apache заббикса слушает 80, переводим его на другой, например 8080, так же задаем локальный адрес для прослушивания\\
Nginx может по дефолту занять 8080, чекаем этот момент\\
Далее в nginx редирект с 80 на 8080\\
server {
listen 80;
server_name zabbix.mydomain.ru;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header Proxy-IP $remote_addr;
}
}
Обработка https, прием и редирект 443, редиректим на 8080\\
server {
listen 443 ssl http2;
server_name zabbix.mydomain.ru;
root /usr/share/nginx/html;
index index.html index.htm;
ssl on;
ssl_certificate /etc/zabbix/zabbix_ssl/Zabbix.crt;
ssl_certificate_key /etc/zabbix/zabbix_ssl/Zabbix.key;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header Proxy-IP $remote_addr;
}
}
Далее меняем редирект с 80го, теперь не на 8080 а на 443, 8080 закрыт извне, т.к. заббикс слушает только локалхост\\
Перевод можно такой, перенаправляет вообще все запросы на защищенный порт\\
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
==== Связка с Apache ====
Сначала настраиваем [[:linux:apache|Apache]] как обычно, только указываем ему нестандартный порт, например 8080.\\
Далее в настройках виртуального хоста настраиваем Location.\\
** Пример: ** Перенаправление всего динамического контента, тут **2 блока Location**:
*Статика, которую возвращает сам nginx
*Все остальные запросы, передаются Apache
server
{
listen 80;
server_name example.com www.example.com;
location ~* ^.+.(js|css|png|jpg|jpeg|gif|ico|woff|woff2|swf|ttf|svg|html|txt)$
{
root /var/www/example.com/public;
expires 1y;
}
location /
{
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 120;
proxy_send_timeout 120;
proxy_read_timeout 180;
}
}
** Пример: ** Два бекенда
upstream backend
{
server 192.168.0.10:8080;
server 192.168.0.11:8080;
}
server
{
listen 80;
server_name example.com www.example.com;
location ~* ^.+.(js|css|png|jpg|jpeg|gif|ico|woff|woff2|swf|ttf|svg|html|txt)$
{
root /var/www/example.com/public;
expires 1y;
}
location /
{
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 120;
proxy_send_timeout 120;
proxy_read_timeout 180;
}
}
Тут стоит уделить внимание расположению в сети общих ресурсов этих серверов, таких как DB, FTP и пр.\\
==== Context (блоки) ====
Конфиг содержит древовидную структуру, определен наборами фигурных скобок, эти области называются контекстами. Контексты вкладываются друг в друга, заданные директивы наследуют вложенными контекстами, могут переопределяться\\
:!: Основные директивы
**Main**\\
Контекст **Main** базовый, глобальный, по умолчанию присутствует всегда, директива вне контекстов, содержится в контексте main\\
**Events**\\
Находится в main, определяет глобальные параметры, влияющие на то как Nginx обрабатывает соединения. В конфете может быть только один контекст Events\\
Как правило метод для обработки соединения выбирается автоматически, платформа выбирает наиболее эффективный из доступных\\
**Http**\\
Содержит все директивы и другие контексты, необходимые для обработки соединений HTTP или HTTPS\\
Так же является дочерним от main, одноранговые с events, не вкладываются друг в друга\\
Содержит значения по умолчанию для каждого виртуального сервера, определенного внутри\\
**Server**\\
Обычно объявляется внутри http, может быть объявлен несколько раз. Виртуальный хост, набор параметров для обработки запросов, разные хосты для разных запросов например\\
Главные директивы для выбора вирт хоста:
* "listen" - комбинация ip и порта, которую прослушивает данный блок
* "server_name" - так же используется для выбора, если есть несколько блоков в одинаковыми "listen" то будет проверяться заголовок запроса "Host" и на основании этого делаться выбор
**Location**\\
Выбирается исходя из клиентского запроса, алгоритмом сопоставления\\
Так же, их может быть несколько, могут быть вложены друг в друга (что тоже может быть полезно). Определение находится в строке заголовка\\
Блоки "location" дополнительно делят обработку запросов внутри блока "server", на основании "url" запроса\\
**upstream**\\
Используется для определения пула серверов для проксирования. Находится в блоке "http" (только ли ?)\\
Затем контекст "Upstream" может ссылаться на имя в пределах блоков "server" или "location" для передачи запросов определенного типа в пул серверов. Внутри пула используется выбор хоста (round-robin), таким образом происходит балансировка нагрузки\\
**Другие**\\
**if** \\
Позволяет настроить условное ветвление\\
**limit_exept** \\
Позволяет задать ограничения на использование HTTP-методов, можно разрешать определенным адресам например\\
===== Управление =====
==== Мониторинг ====
Для настройки мониторинга необходимо внести изменения в конфиг **nginx.conf**.\\
После этого сервер сам предоставляет кое какие данные с помощью **ngx_http_stub_status_module**.\\
Добавляем в секцию **http**:
server
{
listen 127.0.0.1:80;
server_name status.localhost;
keepalive_timeout 0;
allow 127.0.0.1;
deny all;
location /server-status
{
stub_status on;
}
access_log off;
}
После перезапуска, данные доступны (только с локального сервера, как указанно выше), командой:
# curl http://localhost/server-status
* **Active connections** - количество активных клиентских соединений.
* **accepts** - число принятых клиентских соединений.
* **handled** - число обработанных соединений.
* **requests** - число клиентских запросов.
* **Reading** - число соединений, в которых nginx в настоящий момент читает заголовок запроса.
* **Writing** - число соединений, в которых nginx в настоящий момент отвечает клиенту.
* **Waiting** - число бездействующих клиентских соединений в ожидании запроса.
==== Журналы ====
Настройка журналов указана в основном конфиге **/etc/nginx/nginx.conf**, так же может быть переопределена в виртуальных хостах.\\
Основной синтаксис: **`type_log` `path_log_file` `format_log`;**\\
Может быть включен в любой блок конфига, либо во все (**http**, **server** или **location**).\\
Даже рекомендуется делать отдельные файлы для каждого блока.\\
По умолчанию располагаются в **/var/log/nginx/**
=== Журнал доступа ===
В журнал доступа (**access_log**) регистрирует каждый запрос клиента.\\
:!:
http
{
access_log /var/log/nginx/access.log;
server
{
server_name domain.ru
access_log /var/log/nginx/domain.access.log;
}
}
Перенаправление логов в stdout\\
"AccessLog" обычно в хосте, errors в общем блоке\\
Даже при такой конфигурации, error почему то все равно создает файл в "/var/log/nginx", потому что при запуске используется дефолтный, иначе как сообщить если ошибка в конфигурации\\
(...)
error_log /dev/stdout error;
http {
server {
access_log /dev/stdout;
(...)
}
}
Если формат не указан явно, используется формат по умолчанию:
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
Журнал можно отключить:
access_log off;
=== Журнал ошибок ===
error_log log_file log_level
Третий параметр указывает уровень протоколирования (каждый уровень включает в себя все нижестоящие):\\
* **debug** – отладка сообщений.
* **info** – информационные сообщения.
* **notice** – Уведомления.
* **warn** – Предупреждения.
* **error** – Ошибки при обработке запроса (**по умолчанию**).
* **crit** – Критические вопросы. Требует быстрых действий.
* **alert** – Оповещения. Действие должно быть принято немедленно.
* **emerg** – Чрезвычайная ситуация. Система находится в нерабочем состоянии.
==== Параметры ====
:!: Перечень
**worker_processes** -
**worker_connections** -
**worker_cpu_affinity** -
**** -
===== Примеры =====
:!: Docker minimal
Dockerfile
FROM nginx
COPY index.html /usr/share/nginx/html/
COPY default.conf /etc/nginx/conf.d/
Штатный конфиг nginx (из контейнера, основной)
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
Штатный конфиг в подключаемой папке (conf.d)
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$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;
#}
}
SSL конфиг
server{
listen 443 ssl;
server_name my-super-host;
ssl_certificate /etc/nginx/certs/test.pem;
ssl_certificate_key /etc/nginx/certs/test.key;
location / {
root /usr/share/nginx/html;
index index.html;
}
location = /50x.html {
root /usr/share/nginx/html;
}
}
Генерация самоподписанного серта
openssl req -x509 -newkey rsa:4096 -nodes -sha256 -keyout /etc/ssl/private/ssl-cert-snakeoil.key -out /etc/ssl/certs/ssl-cert-snakeoil.pem -days 3650 -subj "/CN=<$PUBLIC_IP_ADDRESS>"
:!: Расположение tmp
http {
server {
(...)
client_body_temp_path /deployments/nginx/tmp;
proxy_temp_path /deployments/nginx/tmp;
fastcgi_temp_path /deployments/nginx/tmp;
uwsgi_temp_path /deployments/nginx/tmp;
scgi_temp_path /deployments/nginx/tmp;
}
}
:!: