Различия
Показаны различия между двумя версиями страницы.
| Предыдущая версия справа и слеваПредыдущая версияСледующая версия | Предыдущая версия | ||
| linux:nginx:nginx_tnt [2021/11/01 17:11] – dx | linux:nginx:nginx_tnt [2022/08/04 14:12] (текущий) – dx | ||
|---|---|---|---|
| Строка 1: | Строка 1: | ||
| + | ====== nginx: tips & howto ====== | ||
| + | ===== Генератор конфига ===== | ||
| + | |||
| + | * https:// | ||
| + | * https:// | ||
| + | * https:// | ||
| + | * https:// | ||
| + | |||
| + | Отдельно хочу отметить утилиту [[https:// | ||
| + | |||
| + | ===== Конфиги сниппеты ===== | ||
| + | |||
| + | * https:// | ||
| + | * https:// | ||
| + | * https:// | ||
| + | * https:// | ||
| + | |||
| + | ===== Редиректы ===== | ||
| + | |||
| + | ==== Редирект всех запросов на определенный файл ==== | ||
| + | |||
| + | < | ||
| + | root / | ||
| + | index index.php; | ||
| + | |||
| + | location / { | ||
| + | try_files $uri $uri/ @redirect; | ||
| + | } | ||
| + | location ~ \.php$ { | ||
| + | try_files $uri @redirect; | ||
| + | ... | ||
| + | } | ||
| + | location @redirect { | ||
| + | return 301 /index.php; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Works like a charm, как говорится. | ||
| + | |||
| + | ==== Перенаправление на SSL-адрес (HTTPS) с нестандартным портом ==== | ||
| + | |||
| + | via http:// | ||
| + | |||
| + | < | ||
| + | |||
| + | ==== Редирект на https:// | ||
| + | |||
| + | < | ||
| + | server { | ||
| + | listen 80; | ||
| + | server_name foobar.com www.foobar.com | ||
| + | return 301 https:// | ||
| + | } | ||
| + | server { | ||
| + | listen 443 ssl; | ||
| + | server_name foobar.com; | ||
| + | |||
| + | ssl_certificate | ||
| + | ssl_certificate_key / | ||
| + | |||
| + | return 301 https:// | ||
| + | } | ||
| + | |||
| + | server { | ||
| + | listen 443 ssl; | ||
| + | server_name www.foobar.com; | ||
| + | root / | ||
| + | |||
| + | ssl_certificate | ||
| + | ssl_certificate_key / | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Еще примеры ==== | ||
| + | |||
| + | * https:// | ||
| + | * | ||
| + | |||
| + | ===== Банхаммер3000 ===== | ||
| + | |||
| + | ==== Блокируем через geoip ==== | ||
| + | |||
| + | http:// | ||
| + | |||
| + | Начиная с версии [[https:// | ||
| + | |||
| + | Примеры использования модуля - http:// | ||
| + | |||
| + | < | ||
| + | yum install nginx-module-geoip | ||
| + | apt-get install nginx-module-geoip | ||
| + | </ | ||
| + | |||
| + | Добавляем в самое начало файла ''/ | ||
| + | |||
| + | < | ||
| + | load_module " | ||
| + | </ | ||
| + | |||
| + | Коды названий стран | ||
| + | |||
| + | [[https:// | ||
| + | |||
| + | В блок **http {}** перед **include** добавить | ||
| + | |||
| + | < | ||
| + | geoip_country / | ||
| + | map $geoip_country_code $allowed_country { | ||
| + | default yes; | ||
| + | RU no; | ||
| + | UA no; | ||
| + | BY no; | ||
| + | CN no; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Для блокировки нужно добавить в **server {}** | ||
| + | |||
| + | < | ||
| + | if ($allowed_country = no) { | ||
| + | return 444; | ||
| + | </ | ||
| + | |||
| + | 444 - закрыть соединение без отправки ответа клиенту. | ||
| + | |||
| + | FIXME почитать про GeoIP2 | ||
| + | * https:// | ||
| + | * 1 | ||
| + | |||
| + | ==== Блокируем поисковых ботов ==== | ||
| + | |||
| + | * https:// | ||
| + | * https:// | ||
| + | |||
| + | < | ||
| + | map $http_user_agent $bad_bot { | ||
| + | default 0; | ||
| + | ~(? | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | В **server {}** добавить в нужное место | ||
| + | |||
| + | < | ||
| + | |||
| + | Для проверки представимся ahrefsom | ||
| + | |||
| + | < | ||
| + | |||
| + | ==== Блокируем реферальный спам ==== | ||
| + | 1 | ||
| + | Добавляес в '' | ||
| + | |||
| + | < | ||
| + | map $http_referer $bad_referer { | ||
| + | hostnames; | ||
| + | default | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Добавляес в '' | ||
| + | |||
| + | < | ||
| + | server { | ||
| + | if ($bad_referer) { | ||
| + | return 444; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Можно использовать [[https:// | ||
| + | |||
| + | < | ||
| + | http { | ||
| + | include referral-spam.conf; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | В этом нам поможет [[http:// | ||
| + | |||
| + | ===== PHP-FPM ===== | ||
| + | |||
| + | ==== ondemand или dynamic ==== | ||
| + | |||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | |||
| + | // | ||
| + | При политике ondemand воркеры создаётся только тогда когда приходит запрос. Через несколько секунд (задаётся в настройках) после завершения обработки запроса (если не поступит нового запроса который можно передать воркеру) воркер убивается.\\ | ||
| + | При dynamic демон всегда поддерживает некоторое заданное количество воркеров в пуле, и распределяет запросы между ними. Если для обработки запросов не хватает воркеров то демон создаёт дополнительных (вплоть до некоторого конфигурируемого значения). Когда потребность в дополнительных воркерах отпадает демон убивает лишние, | ||
| + | Профит от повторного использования воркеров в том что не тратится время на повторное создание процесса. Но если у тебя тормозной код то на его фоне ты этого времени всё-равно не заметишь.\\ | ||
| + | На сколько я понимаю это происходит как-то так. | ||
| + | |||
| + | Попаболь в том что воркеры не особо спешат освобождать память использованную для обработки запроса (кстати я не в курсе баг это или какая-то непонятная фича). По этому если твоё приложение на обработку каждого запроса тратит (например) 100 мб памяти и у тебя есть 3 воркера, | ||
| + | |||
| + | У меня используется dynamic для пулов которые без запросов не остаются, | ||
| + | |||
| + | ==== Калькулятор max_children ==== | ||
| + | |||
| + | cli | ||
| + | * [[https:// | ||
| + | * https:// | ||
| + | |||
| + | ui calc | ||
| + | * https:// | ||
| + | * [[https:// | ||
| + | |||
| + | ==== Разное FPM ==== | ||
| + | |||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * https:// | ||
| + | * [[https:// | ||
| + | |||
| + | |||
| + | ==== Дебаг PHP-FPM с помощью strace ==== | ||
| + | |||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | |||
| + | ===== Разное ===== | ||
| + | |||
| + | ==== Ограничение доступа для групп адресов ==== | ||
| + | |||
| + | ''/ | ||
| + | |||
| + | < | ||
| + | allow 1.2.3.4/32; | ||
| + | allow 1.2.3.8/32; | ||
| + | </ | ||
| + | |||
| + | ''/ | ||
| + | |||
| + | < | ||
| + | allow 10.0.0.0/8; | ||
| + | allow 172.16.0.0/ | ||
| + | allow 192.168.0.0/ | ||
| + | </ | ||
| + | |||
| + | ''/ | ||
| + | |||
| + | < | ||
| + | allow 4.5.6.7; | ||
| + | allow 8.9.10.11; | ||
| + | </ | ||
| + | |||
| + | ''/ | ||
| + | |||
| + | < | ||
| + | location ^~ /admin/ { | ||
| + | include includes/ | ||
| + | deny all; | ||
| + | } | ||
| + | |||
| + | location ^~ /beer/ { | ||
| + | include includes/ | ||
| + | include includes/ | ||
| + | include includes/ | ||
| + | deny all; | ||
| + | } | ||
| + | |||
| + | location ^~ /vodka/ { | ||
| + | include includes/ | ||
| + | include includes/ | ||
| + | deny all; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Как работает SNI ==== | ||
| + | |||
| + | * https:// | ||
| + | |||
| + | ==== Что такое CORS ==== | ||
| + | |||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | |||
| + | ==== Отключить кэширование для директории ==== | ||
| + | |||
| + | Например есть такое | ||
| + | |||
| + | < | ||
| + | location /static { | ||
| + | alias / | ||
| + | add_header Pragma " | ||
| + | add_header Cache-Control " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | И есть апишечка где кэш очень вреден | ||
| + | |||
| + | |||
| + | < | ||
| + | location / | ||
| + | add_header Pragma " | ||
| + | add_header Cache-Control " | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== X509_check_private_key: | ||
| + | |||
| + | Нарушен порядок в crt/pem файле. | ||
| + | |||
| + | < | ||
| + | -----BEGIN CERTIFICATE----- | ||
| + | Сертификат_сервера | ||
| + | -----END CERTIFICATE----- | ||
| + | -----BEGIN CERTIFICATE----- | ||
| + | Сертификат корневого центра сертификации (CA) | ||
| + | -----END CERTIFICATE----- | ||
| + | -----BEGIN CERTIFICATE----- | ||
| + | СЕРТИФИКАТ ПРОМЕЖУТОЧНОГО ЦЕНТРА СЕРТИФИКАЦИИ | ||
| + | Сертификат промежуточного центра сертификации (Intermediate) | ||
| + | -----END CERTIFICATE----- | ||
| + | </ | ||
| + | |||
| + | ==== HTTPOnly и Secure Cookie ==== | ||
| + | |||
| + | * https:// | ||
| + | * https:// | ||
| + | |||
| + | ==== favicon.ico ==== | ||
| + | |||
| + | По стандарту, | ||
| + | Можно для nginx создать секцию | ||
| + | < | ||
| + | location / | ||
| + | root ... | ||
| + | log_not_found off; | ||
| + | access_log off; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Есть опция **empty_gif** | ||
| + | < | ||
| + | location / | ||
| + | empty_gif; | ||
| + | access_log off; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Таким образом будет отдаваться прозрачный гиф 1х1px на все запросы иконки. | ||
| + | |||
| + | А теперь объединим. | ||
| + | |||
| + | < | ||
| + | | ||
| + | access_log off; | ||
| + | try_files $uri @emptygif; | ||
| + | } | ||
| + | location @emptygif { | ||
| + | internal; | ||
| + | empty_gif; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | via | ||
| + | * http:// | ||
| + | * http:// | ||
| + | |||
| + | ==== Закрываем сайт на обслуживание ==== | ||
| + | |||
| + | **Варианты** | ||
| + | |||
| + | **1) в location /** | ||
| + | |||
| + | < | ||
| + | ## System Maintenance (Service Unavailable) | ||
| + | if (-f $document_root/ | ||
| + | error_page 503 / | ||
| + | return 503; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | (if нежелателен - там куча ограничений, | ||
| + | |||
| + | **2) try_files closed.html @apache =503;**\\ | ||
| + | (проблема в том, что в таком варианте код ответа при обслуживании будет 200). Хотя можно сделать отдельный location closed.html и в нем выставить код ответа 503, по желанию оттуда же отдать и саму страницу. | ||
| + | Можно написать как | ||
| + | < | ||
| + | но если индекса нет и апач перекидывает на какую-то внутреннюю страницу с рядом опций - могут быть проблемы, | ||
| + | |||
| + | С другой стороны, | ||
| + | |||
| + | **3) через переменную и if** | ||
| + | < | ||
| + | set $Maintenance = off; | ||
| + | if ($Maintenance = ' | ||
| + | но см выше про if. | ||
| + | </ | ||
| + | |||
| + | **4) выделить блок, закрывающий сайт на обслуживание в отдельный файл maint.conf**, | ||
| + | |||
| + | via http:// | ||
| + | |||
| + | ==== Как убедиться, | ||
| + | |||
| + | Нашёл здесь - https:// | ||
| + | |||
| + | Находим PID | ||
| + | |||
| + | < | ||
| + | # ps ax | grep nginx | ||
| + | 1071 ? Ss 0:01 nginx: master process / | ||
| + | 17947 pts/0 S+ 0:00 grep --color=auto nginx | ||
| + | 18315 ? S 0:25 nginx: worker process | ||
| + | </ | ||
| + | |||
| + | Запускаем trace | ||
| + | |||
| + | < | ||
| + | # strace -p 18315 2>&1 | grep gz | ||
| + | open("/ | ||
| + | open("/ | ||
| + | open("/ | ||
| + | </ | ||
| + | |||
| + | ==== monit ==== | ||
| + | |||
| + | https:// | ||
| + | |||
| + | < | ||
| + | server { | ||
| + | listen 80; | ||
| + | server_name monit.domain.com; | ||
| + | location / { | ||
| + | proxy_pass 127.0.0.1: | ||
| + | proxy_set_header Host $host; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Много соединений в TIME_WAIT ==== | ||
| + | |||
| + | Apache (backend) nginx (frontend). В netstat сотни/ | ||
| + | |||
| + | Скорее всего это нормально если включён keepalive. Если устанавливается много новых подключений и быстро разрываются, | ||
| + | |||
| + | Решением было установить для параметров ядра **TCP_TW_RECYCLE** и **TCP_TW_REUSE** значение **1**, по-умолчанию **0** | ||
| + | |||
| + | Применять с осторожностью | ||
| + | |||
| + | < | ||
| + | echo 1 > / | ||
| + | echo 1 > / | ||
| + | </ | ||
| + | |||
| + | Или добавить в ''/ | ||
| + | |||
| + | < | ||
| + | net.ipv4.tcp_tw_reuse=1 | ||
| + | net.ipv4.tcp_tw_recycle=1 | ||
| + | net.ipv4.tcp_fin_timeout=15 | ||
| + | net.ipv4.ip_local_port_range = 10240 65000 | ||
| + | </ | ||
| + | |||
| + | * TCP_TW_RECYCLE Description: | ||
| + | * TCP_TW_REUSE Description: | ||
| + | |||
| + | **Обновлено** | ||
| + | |||
| + | Ошибка **sysctl: cannot stat / | ||
| + | |||
| + | net.ipv4.tcp_tw_recycle [[https:// | ||
| + | |||
| + | < | ||
| + | The tcp_tw_recycle was already broken for connections | ||
| + | behind NAT, since the per-destination timestamp is not | ||
| + | monotonically increasing for multiple machines behind | ||
| + | a single destination address. | ||
| + | |||
| + | After the randomization of TCP timestamp offsets | ||
| + | in commit 8a5bd45f6616 (tcp: randomize tcp timestamp offsets | ||
| + | for each connection), | ||
| + | types of connections for the same reason: the timestamps | ||
| + | received from a single machine is not monotonically increasing, | ||
| + | anymore. | ||
| + | |||
| + | Remove tcp_tw_recycle, | ||
| + | the PAWSPassive SNMP counter since it is only used for | ||
| + | tcp_tw_recycle, | ||
| + | since the strict argument is only set when tcp_tw_recycle is | ||
| + | enabled. | ||
| + | </ | ||
| + | |||
| + | Почитать | ||
| + | * https:// | ||
| + | * http:// | ||
| + | |||
| + | ==== TCP_CORK/ | ||
| + | |||
| + | Игорь Сысоев / http:// | ||
| + | |||
| + | Да, в Линкусе TCP_CORK (tcp_nopush) и TCP_NODELAY взаимоисключающие, | ||
| + | nginx проявляет недюженный интеллект, | ||
| + | обеих опций. | ||
| + | |||
| + | " | ||
| + | полными пакетами. После того, как весь запрос обработан, | ||
| + | выключается, | ||
| + | |||
| + | " | ||
| + | по окончании запроса, | ||
| + | keep-alive. До этого nginx выводит данные вызовами writev() достаточно | ||
| + | большими порциями для заполнения пакета (" | ||
| + | данные должны уходить без задержек и TCP_NODELAY не нужен. А вот с последним | ||
| + | неполным пакетом может случится небольшая задержка, | ||
| + | закрывается. Для этого и нужно включить TCP_NODELAY. | ||
| + | |||
| + | В Линуксе обработка этих двух опций | ||
| + | |||
| + | < | ||
| + | | ||
| + | | ||
| + | </ | ||
| + | |||
| + | такова: | ||
| + | |||
| + | 1) если данные будут выводить комбинацией writev(заголовок)/ | ||
| + | то проверяется, | ||
| + | TCP_NODELAY выключается и включается TCP_CORK. По окончании передачи TCP_CORK | ||
| + | выключается. Включать TCP_NODELAY не нужно, так как выключание TCP_CORK | ||
| + | сбрасывает данные. | ||
| + | |||
| + | 2) если при переходе в keep-alive TCP_CORK не была включена, | ||
| + | TCP_NODELAY, | ||
| + | |||
| + | Кстати, | ||
| + | до отдачи ответа. | ||
| + | |||
| + | ==== Как определить количество рабочих процессов, | ||
| + | |||
| + | via http:// | ||
| + | |||
| + | Ответ автора nginx Игоря Сысоева: | ||
| + | |||
| + | //Если весь сайт помещается в память сервера, | ||
| + | // | ||
| + | |||
| + | Кроме этого необходимо понаблюдать за состоянием процессов nginx в работе в часы пик. Командой ps посмотреть состояние рабочих процессов (worker process): | ||
| + | |||
| + | < | ||
| + | # ps ax -o %cpu, | ||
| + | |||
| + | %CPU VSZ WCHAN COMMAND | ||
| + | 0,0 1428 pause nginx: master process / | ||
| + | 0,0 2284 - nginx: worker process (nginx) | ||
| + | 0,0 2128 kqread nginx: worker process (nginx) | ||
| + | </ | ||
| + | |||
| + | Если один из рабочих процессов находится в состоянии ожидания " | ||
| + | |||
| + | И не забывайте контролировать логи ошибок nginx, если количество соединений превысит значение, | ||
| + | |||
| + | ==== Правильная отдача заголовков при технических работах на сайте ==== | ||
| + | |||
| + | (via http:// | ||
| + | |||
| + | Есть ситуация: | ||
| + | |||
| + | < | ||
| + | server { | ||
| + | listen 80 default; | ||
| + | server_name _; | ||
| + | root / | ||
| + | charset utf-8; | ||
| + | error_page 404 403 =503 /503.html; | ||
| + | location = /503.html { | ||
| + | add_header Retry-After "Sun, 27 Feb 2011 23: | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Строка error_page **404 403 =503 /503.html** означает, | ||
| + | |||
| + | ==== Схема frontend-backend ==== | ||
| + | |||
| + | * http:// | ||
| + | |||
| + | ===== Кэширование ===== | ||
| + | |||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | |||
| + | ===== Разное ===== | ||
| + | |||
| + | * http:// | ||
| + | * http:// | ||
| + | * http:// | ||
| + | * http:// | ||
| + | * [[http:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * https:// | ||
| + | * https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||
| + | * [[https:// | ||