RTFM.WIKI

Ordnung muß sein. Ordnung über alles (18+)

Инструменты пользователя

Инструменты сайта


linux:nginx:nginx_tnt

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";

Коды названий стран

ISO 3166 Country Codes

В блок 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 - закрыть соединение без отправки ответа клиенту.

FIXME почитать про GeoIP2

Блокируем поисковых ботов

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

Разное 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-----

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. Можно не симлинком а копированием. Самый быстрый способ, но требует немного кодинга.

via http://dragonflybsd.blogspot.ru/2012/10/nginx.html

Как убедиться, что работает 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.

Показать

Скрыть

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), the tcp_tw_recycle is broken for all types of connections for the same reason: the timestamps received from a single machine is not monotonically increasing, anymore.

Remove tcp_tw_recycle, since it is not functional. Also, remove the PAWSPassive SNMP counter since it is only used for tcp_tw_recycle, and simplify tcp_v4_route_req and tcp_v6_route_req since the strict argument is only set when tcp_tw_recycle is enabled.

Почитать

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 можно написать что-нибудь осмысленное для пользователей и даже встроить флэш-игру, чтобы не было скучно.

Схема frontend-backend

Кэширование

Разное

Обсуждение

Ваш комментарий. Вики-синтаксис разрешён:
 
linux/nginx/nginx_tnt.txt · Последнее изменение: 2022/08/04 14:12 — dx