Содержание
nginx: tips & howto
Генератор конфига
Отдельно хочу отметить утилиту gixy для провеки конфига на наличие разного рода ошибок.
Конфиги сниппеты
Редиректы
Редирект всех запросов на определенный файл
root /var/www/foobar.com; 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://www.f-notes.info/nginx:ssl_non-stadard_port
error_page 497 https://$server_name:8443$request_uri;
Редирект на https://foobar.com
server { listen 80; server_name foobar.com www.foobar.com return 301 https://www.foobar.com$request_uri; } server { listen 443 ssl; server_name foobar.com; ssl_certificate /etc/nginx/ssl/www.foobar.com.crt; ssl_certificate_key /etc/nginx/ssl/www.foobar.com.key; return 301 https://www.foobar.com$request_uri; } server { listen 443 ssl; server_name www.foobar.com; root /var/www/html ssl_certificate /etc/nginx/ssl/www.foobar.com.crt; ssl_certificate_key /etc/nginx/ssl/www.foobar.com.key; }
Еще примеры
Банхаммер3000
Блокируем через geoip
http://blog.ls20.com/optimizing-nginx-config-for-your-website-or-blog/
Начиная с версии 1.9.11 введена поддержка динамических модулей
Примеры использования модуля - http://nginx.org/en/docs/http/ngx_http_geoip_module.html
yum install nginx-module-geoip apt-get install nginx-module-geoip
Добавляем в самое начало файла /etc/nginx/nginx.conf
перед блоком http {}
load_module "modules/ngx_http_geoip_module.so";
Коды названий стран
В блок http {} перед include добавить
geoip_country /usr/share/GeoIP/GeoIP.dat; map $geoip_country_code $allowed_country { default yes; RU no; UA no; BY no; CN no; }
Для блокировки нужно добавить в server {}
if ($allowed_country = no) { return 444;
444 - закрыть соединение без отправки ответа клиенту.
почитать про GeoIP2
- 1
Блокируем поисковых ботов
map $http_user_agent $bad_bot { default 0; ~(?i)(alexa.com|AltaVista|ApacheBench|Aport|Ahrefs|AhrefsBot|Baiduspider|BLEXBot|CCBot|CommentReader|Copier|Crowsnest|DISCo|discobot|ExpertSearch|ExpertSearchSpider|FairShare|FeedFetcher|FlaxCrawler|FastSeek|FlappyBot|FlashGet|GetRight|GetWeb!|Grabber|g00g1e|HTTrack|ia_archiver|LeechFTP|LeechGet|Linguee|LinkBot|MauiBot|MJ12|MJ12bot|netvampire|Offline|PycURL|Python|QuerySeekerSpider|Ruby|Seopult|Semrush|SEMrushBot|SputnikBot|spbot|SputnikFaviconBot|SputnikImageBot|Sogou|TalkTalk|Teleport|uTorrent|urllib|Vampire|vkShare|WebCopy|WebCopier|WebCollector|WebSpider|WebStripper|WebWhacker|Yeti|YottosBot) 1; }
В server {} добавить в нужное место
if ($bad_bot = 1) { return 403; }
Для проверки представимся ahrefsom
curl http://localhost -H 'User-Agent: Ahrefs' -I
Блокируем реферальный спам
1
Добавляес в http {}
спам домены
map $http_referer $bad_referer { hostnames; default 0; "~*best\-seo\-solutions\.com" 1; "~*buy\-cheap\-online\.net" 1; "~*get\-free\-traffic\-now\.biz" 1; }
Добавляес в server {}
для нужного сайта
server { if ($bad_referer) { return 444; } }
Можно использовать готовый черный список через include
http { include referral-spam.conf; }
В этом нам поможет ngx_http_map_module
PHP-FPM
ondemand или dynamic
Во-первых пул это просто набор процессов. Это не какой-то отдельный процесс.
При политике ondemand воркеры создаётся только тогда когда приходит запрос. Через несколько секунд (задаётся в настройках) после завершения обработки запроса (если не поступит нового запроса который можно передать воркеру) воркер убивается.
При dynamic демон всегда поддерживает некоторое заданное количество воркеров в пуле, и распределяет запросы между ними. Если для обработки запросов не хватает воркеров то демон создаёт дополнительных (вплоть до некоторого конфигурируемого значения). Когда потребность в дополнительных воркерах отпадает демон убивает лишние, так что-бы осталось нужное количество.
Профит от повторного использования воркеров в том что не тратится время на повторное создание процесса. Но если у тебя тормозной код то на его фоне ты этого времени всё-равно не заметишь.
На сколько я понимаю это происходит как-то так.
Попаболь в том что воркеры не особо спешат освобождать память использованную для обработки запроса (кстати я не в курсе баг это или какая-то непонятная фича). По этому если твоё приложение на обработку каждого запроса тратит (например) 100 мб памяти и у тебя есть 3 воркера, каждый из которых за свою жизнь получил хотя-бы один запрос, то у тебя в системе будет висеть три процесса каждый из которых выжирает по 100 мб памяти, даже если запросов в тот пул сейчас нет вообще. Побаболь наступает тогда когда у тебя есть куча малопосещаемых сайтов с жадным до памяти кодом.
У меня используется dynamic для пулов которые без запросов не остаются, и ondemand для малопосещаемых сайтов.
Калькулятор max_children
cli
ui calc
Разное FPM
Дебаг PHP-FPM с помощью strace
Разное
Ограничение доступа для групп адресов
/etc/nginx/includes/admin-ips
allow 1.2.3.4/32; allow 1.2.3.8/32;
/etc/nginx/includes/private-ips
allow 10.0.0.0/8; allow 172.16.0.0/12; allow 192.168.0.0/16;
/etc/nginx/includes/testing-ips
allow 4.5.6.7; allow 8.9.10.11;
/etc/nginx/conf.d/foobar.conf
location ^~ /admin/ { include includes/admin-ips; deny all; } location ^~ /beer/ { include includes/admin-ips; include includes/testing-ips; include includes/private-ips; deny all; } location ^~ /vodka/ { include includes/admin-ips; include includes/testing-ips; deny all; }
Как работает SNI
Что такое CORS
Отключить кэширование для директории
Например есть такое
location /static { alias /var/www/foobar.com/static; add_header Pragma "cache"; add_header Cache-Control "public"; }
И есть апишечка где кэш очень вреден
location /api/ping-pong { add_header Pragma "no-cache"; add_header Cache-Control "private, max-age=0, no-cache, no-store"; }
X509_check_private_key:key values mismatch
Нарушен порядок в crt/pem файле.
-----BEGIN CERTIFICATE----- Сертификат_сервера -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- Сертификат корневого центра сертификации (CA) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- СЕРТИФИКАТ ПРОМЕЖУТОЧНОГО ЦЕНТРА СЕРТИФИКАЦИИ Сертификат промежуточного центра сертификации (Intermediate) -----END CERTIFICATE-----
HTTPOnly и Secure Cookie
favicon.ico
По стандарту, "картинка (иконка) сайта" должна быть. Поэтому в еррлоги активно пишется на каждый запрос, что favicon.ico not found. Можно для nginx создать секцию
location /favicon.ico { root ... log_not_found off; access_log off; }
Есть опция empty_gif
location /favicon.ico { empty_gif; access_log off; }
Таким образом будет отдаваться прозрачный гиф 1х1px на все запросы иконки.
А теперь объединим.
location /favicon.ico { access_log off; try_files $uri @emptygif; } location @emptygif { internal; empty_gif; }
via
Закрываем сайт на обслуживание
Варианты
1) в location /
## System Maintenance (Service Unavailable) if (-f $document_root/system_maintenance.html ) { error_page 503 /system_maintenance.html; return 503; }
(if нежелателен - там куча ограничений, нюансов и оно довольно сильно грузит сервер, IfIsEvil)
2) try_files closed.html @apache =503;
(проблема в том, что в таком варианте код ответа при обслуживании будет 200). Хотя можно сделать отдельный location closed.html и в нем выставить код ответа 503, по желанию оттуда же отдать и саму страницу.
Можно написать как
try_files /maintenance.html $uri $uri/ @wordpress;
но если индекса нет и апач перекидывает на какую-то внутреннюю страницу с рядом опций - могут быть проблемы, если такой файл вдруг появится, а это не предусмотрено системой. Плюс, если была встроенная фильтрация на бэкенде - так ее можно обойти. Ну и 2 лишние проверки получаем.
С другой стороны, для простых движков этот вариант будет быстрее и если вся статика не вынесена по отдельным location, автоматом начнётся раздача статики. Но снова безопасность, надо тогда создавать location на потенциально опасные места и там запрещать, обязательно. В частности на .ht, .svn, .git, служебные области. В общем, лучше первая версия этого варианта.
3) через переменную и if
set $Maintenance = off; if ($Maintenance = 'on') ... но см выше про if.
4) выделить блок, закрывающий сайт на обслуживание в отдельный файл maint.conf, сделать 2 файла maint-on.conf и maint-off.conf, и вешать симлинк на нужную версию файла с именем maint.conf и потом делать reload. Можно не симлинком а копированием. Самый быстрый способ, но требует немного кодинга.
Как убедиться, что работает gzip_static
Нашёл здесь - https://stackoverflow.com/questions/2460821/how-can-i-check-that-the-nginx-gzip-static-module-is-working
Находим PID
# ps ax | grep nginx 1071 ? Ss 0:01 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf 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("/home/admin/web/foobar.com/public_html/uploads/posts/2017-01/1485714800-275451094.jpg.gz", O_RDONLY|O_NONBLOCK|O_LARGEFILE) = 34 open("/home/admin/web/foobar.com/public_html/uploads/posts/2017-01/1485714801-2083693483.jpg.gz", O_RDONLY|O_NONBLOCK|O_LARGEFILE) = 34 open("/home/admin/web/example.com/public_html/uploads/posts/2016-11/thumbs/1480346913_09b7vuxzf2vgwqd.jpg.gz", O_RDONLY|O_NONBLOCK|O_LARGEFILE) = -1 ENOENT (No such file or directory)
monit
https://mmonit.com/wiki/Monit/Nginx
server { listen 80; server_name monit.domain.com; location / { proxy_pass 127.0.0.1:2812; proxy_set_header Host $host; } }
Много соединений в TIME_WAIT
Apache (backend) nginx (frontend). В netstat сотни/тысячи коннектов в состоянии TIME_WAIT. В итоге система упирается в количество доступных сетевых сокетов, что приводит к невозможности устанавливать новые соединения.
Скорее всего это нормально если включён keepalive. Если устанавливается много новых подключений и быстро разрываются, то образуется очередь из TIME_WAIT.
Решением было установить для параметров ядра TCP_TW_RECYCLE и TCP_TW_REUSE значение 1, по-умолчанию 0
Применять с осторожностью
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
Или добавить в /etc/sysctl.conf
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: Enables fast recycling of TIME_WAIT sockets. Use with caution and ONLY in internal network where network connectivity speeds are “faster”.
- TCP_TW_REUSE Description: Allows for reuse of sockets in TIME_WAIT state for new connections, only when it is safe from the network stack’s perspective.
Обновлено
Ошибка sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recycle: No such file or directory
net.ipv4.tcp_tw_recycle был удалён из ядра Linux 4.12 в 2017.
Почитать
TCP_CORK/TCP_NOPUSH и TCP_NODELAY
Игорь Сысоев / http://sysoev.ru
Да, в Линкусе TCP_CORK (tcp_nopush) и TCP_NODELAY взаимоисключающие, но nginx проявляет недюженный интеллект, пытаясь совместить преимущества обеих опций.
"tcp_nopush on" полезно для sendfile(), он в этом случае выводит данные полными пакетами. После того, как весь запрос обработан, TCP_CORK/TCP_NOPUSH выключается, что приводит в сбросу последнего неполного пакета.
"tcp_nodelay on" полезно для keep-alive. nginx включает TCP_NODELAY только по окончании запроса, после которого соединение переходит в состоянии keep-alive. До этого nginx выводит данные вызовами writev() достаточно большими порциями для заполнения пакета ("postpone_output 1460"), поэтому данные должны уходить без задержек и TCP_NODELAY не нужен. А вот с последним неполным пакетом может случится небольшая задержка, если соединение не закрывается. Для этого и нужно включить TCP_NODELAY.
В Линуксе обработка этих двух опций
tcp_nopush on; tcp_nodelay on;
такова:
1) если данные будут выводить комбинацией writev(заголовок)/sendfile(), то проверяется, не было ли уже включен TCP_NODELAY. Если было, то TCP_NODELAY выключается и включается TCP_CORK. По окончании передачи TCP_CORK выключается. Включать TCP_NODELAY не нужно, так как выключание TCP_CORK сбрасывает данные.
2) если при переходе в keep-alive TCP_CORK не была включена, то включается TCP_NODELAY, чтобы сбросить неполный пакет.
Кстати, возможно, для "proxy_buffering off" имеет смысл включать TCP_NODELAY до отдачи ответа.
Как определить количество рабочих процессов, задаваемых параметром worker_processes?
via http://www.httpd.kiev.ua/tips/nginx/number-of-worker-processes/
Ответ автора nginx Игоря Сысоева:
Если весь сайт помещается в память сервера, к диску обращений нет, и это выделенный сервер для nginx, то 1. Не будет лишних переключений контекста. Если нужно ходить на диск, то 5-10 - это позволит обрабатывать соединения процессами, незаблокироваными на диске.
Кроме этого необходимо понаблюдать за состоянием процессов nginx в работе в часы пик. Командой ps посмотреть состояние рабочих процессов (worker process):
# ps ax -o %cpu,vsz,wchan,command | grep "nginx\|PID" %CPU VSZ WCHAN COMMAND 0,0 1428 pause nginx: master process /usr/local/nginx/sbin/nginx 0,0 2284 - nginx: worker process (nginx) 0,0 2128 kqread nginx: worker process (nginx)
Если один из рабочих процессов находится в состоянии ожидания "kqread" в колонке "WCHAN", то значит их количество достаточно. Ну а если уж все они постоянно находятся в этом состоянии, то их количество можно сократить до одного.
И не забывайте контролировать логи ошибок nginx, если количество соединений превысит значение, которое в может обслужить nginx текущим количеством процессов, то в логах это будет соответствующее сообщение.
Правильная отдача заголовков при технических работах на сайте
(via http://www.zagirov.name/correct-return-header-on-service)
Есть ситуация: проводятся какие-то технические работы на сайте и нужно сайт правильно закрыть. Это нужно чтобы поисковики знали, что сайт не доступен, а не добавляли страницы в индекс или помечали страницы как удалённые.
server { listen 80 default; server_name _; root /var/www/default/www; charset utf-8; error_page 404 403 =503 /503.html; location = /503.html { add_header Retry-After "Sun, 27 Feb 2011 23:59:59"; } }
Строка error_page 404 403 =503 /503.html означает, что перенаправляем все запросы с ошибками 404 и 403 на файл 503.html, попутно меняя код ответа на 503. И при запросе файла 503.html отдаём заголовок Retry-After, чтобы поисковики знали, когда можно опять запросить страницу. Вместо даты можно указать количество секунд перед следующей попыткой. В файле 503.html можно написать что-нибудь осмысленное для пользователей и даже встроить флэш-игру, чтобы не было скучно.
Обсуждение