====== nginx: tips & howto ======
===== Генератор конфига =====
* https://nginxconfig.io
* https://nginxbeautifier.com / https://github.com/vasilevich/nginxbeautifier
* https://github.com/1connect/nginx-config-formatter
* https://git.blindage.org/21h/nginx-formatter
Отдельно хочу отметить утилиту [[https://github.com/yandex/gixy|gixy]] для провеки конфига на наличие разного рода ошибок.\\
===== Конфиги сниппеты =====
* https://github.com/h5bp/server-configs-nginx/tree/master/h5bp
* https://github.com/gulch/Trickz-Snipz/blob/master/nginx/NGINX-GCONF/nginx.conf
* https://github.com/gulch/Trickz-Snipz/tree/master/nginx/NGINX-GCONF/templates
* https://github.com/david-rahrer/nginx-opencart/blob/master/nginx/sites-available/example.com-le.vhost
===== Редиректы =====
==== Редирект всех запросов на определенный файл ====
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;
}
==== Еще примеры ====
* https://pai-bx.com/wiki/nginx/2332-useful-redirects-in-nginx/
*
===== Банхаммер3000 =====
==== Блокируем через geoip ====
http://blog.ls20.com/optimizing-nginx-config-for-your-website-or-blog/
Начиная с версии [[https://www.nginx.com/blog/dynamic-modules-nginx-1-9-11/|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";
Коды названий стран
[[https://dev.maxmind.com/geoip/legacy/codes/iso3166/|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
* https://medium.com/@karljohnson/geoip-discontinuation-upgrade-to-geoip2-with-nginxon-centos-c2a3dbcf8fd
* 1
==== Блокируем поисковых ботов ====
* https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker
* https://github.com/mariusv/nginx-badbot-blocker
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;
}
}
Можно использовать [[https://github.com/Stevie-Ray/referrer-spam-blocker|готовый черный список]] через include
http {
include referral-spam.conf;
}
В этом нам поможет [[http://nginx.org/en/docs/http/ngx_http_map_module.html|ngx_http_map_module]]
===== PHP-FPM =====
==== ondemand или dynamic ====
* [[https://www.linux.org.ru/forum/web-development/13089187?lastmod=1482082470587#comment-13089427|Как быть с пулами в php-fpm, если сайтов больше 2-x?]]
* [[https://ma.ttias.be/a-better-way-to-run-php-fpm/|A better way to run PHP-FPM]]
* [[https://hcbogdan.com/php/2016/09/16/php-fpm-dynamic/|Настраиваем php-fpm / hcbogdan]]
//Во-первых пул это просто набор процессов. Это не какой-то отдельный процесс.\\
При политике ondemand воркеры создаётся только тогда когда приходит запрос. Через несколько секунд (задаётся в настройках) после завершения обработки запроса (если не поступит нового запроса который можно передать воркеру) воркер убивается.\\
При dynamic демон всегда поддерживает некоторое заданное количество воркеров в пуле, и распределяет запросы между ними. Если для обработки запросов не хватает воркеров то демон создаёт дополнительных (вплоть до некоторого конфигурируемого значения). Когда потребность в дополнительных воркерах отпадает демон убивает лишние, так что-бы осталось нужное количество.\\
Профит от повторного использования воркеров в том что не тратится время на повторное создание процесса. Но если у тебя тормозной код то на его фоне ты этого времени всё-равно не заметишь.\\
На сколько я понимаю это происходит как-то так.
Попаболь в том что воркеры не особо спешат освобождать память использованную для обработки запроса (кстати я не в курсе баг это или какая-то непонятная фича). По этому если твоё приложение на обработку каждого запроса тратит (например) 100 мб памяти и у тебя есть 3 воркера, каждый из которых за свою жизнь получил хотя-бы один запрос, то у тебя в системе будет висеть три процесса каждый из которых выжирает по 100 мб памяти, даже если запросов в тот пул сейчас нет вообще. Побаболь наступает тогда когда у тебя есть куча малопосещаемых сайтов с жадным до памяти кодом.
У меня используется dynamic для пулов которые без запросов не остаются, и ondemand для малопосещаемых сайтов.//
==== Калькулятор max_children ====
cli
* [[https://myshell.co.uk/blog/2012/07/adjusting-child-processes-for-php-fpm-nginx/|Adjusting child processes for PHP-FPM (Nginx)]]
* https://tresnet.ru/archives/1313
ui calc
* https://cmorrell.com/php-fpm/
* [[https://chrismoore.ca/2018/10/finding-the-correct-pm-max-children-settings-for-php-fpm/|Finding the correct pm.max_children settings for PHP-FPM]] / https://spot13.com/pmcalculator/ / https://github.com/spot13/pmcalculator
==== Разное FPM ====
* [[https://www.getpagespeed.com/server-setup/nginx/no-input-file-specified|NGINX vs PHP-FPM: No input file specified]]
* [[https://www.vennedey.net/resources/3-Secure-webspaces-with-NGINX-PHP-FPM-chroots-and-Lets-Encrypt|Secure webspaces with NGINX, PHP-FPM chroots and Let's Encrypt]] / [[https://www.vennedey.net/jailspaces|Jailspaces]]
* [[https://publications.jbfavre.org/web/php-fpm-apps-server-nginx.en|PHP-FPM, application server made by PHP]]
* [[http://docs.mirocow.com/doku.php?id=system:php:chroot|php-fpm в chroot и некоторые трудности]]
* [[http://mailman.nginx.org/pipermail/nginx-ru/2013-June/051221.html|Re: Проблема с chroot в связке Nginx + PHP-FPM]]
* https://blog.programs74.ru/how-to-installing-and-configuring-server-for-web-hosting/
* [[https://haydenjames.io/php-fpm-tuning-using-pm-static-max-performance/|PHP-FPM tuning: Using ‘pm static’ for max performance]]
==== Дебаг PHP-FPM с помощью strace ====
* [[https://shubhamjain.co/2015/09/10/debugging-stuck-php-fpm-process-with-strace/|Debugging Stuck PHP-FPM Process With Strace]]
* [[https://www.bggofurther.com/2015/04/using-strace-with-multiples-pids|Using strace with multiples PIDs]]
* [[https://blog.sleeplessbeastie.eu/2019/10/14/how-to-strace-php-fpm-processes/|How to strace PHP-FPM processes / blog.sleeplessbeastie.eu]]
* [[https://stackoverflow.com/questions/33643131/how-strace-php-fpm-process|how strace php-fpm process?]]
* [[https://medium.com/@nickpeirson/analyse-running-php-processes-with-free-open-source-tools-538ae18f5fe1|Inspecting rogue PHP processes]]
===== Разное =====
==== Ограничение доступа для групп адресов ====
''/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 ====
* https://www.itsfullofstars.de/2020/12/server-name-indication/
==== Что такое CORS ====
* [[https://ibnrubaxa.medium.com/nginx-vs-cors-7a63029d9a34|NGINX vs. CORS]]
* [[https://enable-cors.org/server_nginx.html|CORS on Nginx]]
* [[https://evilinside.ru/nastrojka-cors-v-nginx/|Настройка CORS в Nginx]]
==== Отключить кэширование для директории ====
Например есть такое
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 ====
* https://rdevelab.ru/blog/no-category/post/samesite-cross-domain-cookies
* https://itgala.xyz/nginx-httponly-and-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
* http://nginx.org/en/docs/http/ngx_http_empty_gif_module.html
* http://dragonflybsd.blogspot.ru/2012/10/nginx-faviconico.html
==== Закрываем сайт на обслуживание ====
**Варианты**
**1) в location /**
## System Maintenance (Service Unavailable)
if (-f $document_root/system_maintenance.html ) {
error_page 503 /system_maintenance.html;
return 503;
}
(if нежелателен - там куча ограничений, нюансов и оно довольно сильно грузит сервер, [[http://wiki.nginx.org/IfIsEvil|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 [[https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4396e46187ca5070219b81773c4e65088dac50cc|был удалён из ядра]] 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.
Почитать
* https://www.speedguide.net/articles/linux-tweaking-121
* http://web.archive.org/web/20140616114533/http://performancewiki.com/linux-tuning.html
==== 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 ====
* http://blog.korphome.ru/2010/12/31/centos-nginx-%D0%B2-%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B5-frontend%D0%B0-%D0%BA-apache/
===== Кэширование =====
* [[http://wiki.enchtex.info/practice/nginx/cache|Настройка кеширования в nginx]]
* [[http://debian-help.ru/web-servers/nastroika-keshirovaniya-statiki-s-pomoshyu-nginx-v-debian/|Настройка кэширования статики с помощью nginx в Debian]]
* [[http://habrahabr.ru/post/253121/|Гид по заголовкам кэширования HTTP для начинающих]]
* [[https://angristan.xyz/ghost-nginx-cache/|Caching Ghost with Nginx]]
* [[https://nystudio107.com/blog/static-caching-with-craft-cms|Static Page Caching with Craft CMS]]
===== Разное =====
* http://kevin.deldycke.com/2011/09/nginx-php-fpm-mysql-configuration/
* http://kbeezie.com/view/nginx-configuration-examples/
* http://wiki.rsu.edu.ru/index.php/Nginx
* http://tweaked.io/guide/nginx/
* [[http://slonik-v-domene.livejournal.com/141951.html|Apache vs Nginx: Расставим точки над ё.]]
* [[https://www.kinamo.be/en/kb/determining-the-correct-number-of-child-processes-for-php-fpm-on-nginx|Determining the correct number of child processes for PHP-FPM on NGinx]]
* [[https://nls.io/blog/optimize-nginx-and-php-fpm-max_children|Optimize nginx and PHP-FPM (max_children)]]
* [[https://www.getpagespeed.com/server-setup/nginx-try_files-is-evil-too|try_files is evil too]]
* [[https://medium.com/southbridge/nginx-as-reverse-proxy-a62815edd8c1|Nginx как обратный прокси на Docker]]
* [[https://tech.geekjob.ru/nginx-tips-tricks/|Выгружаем конфиг из памяти]]
* [[https://blog.serverdensity.com/troubleshoot-nginx/|Troubleshoot Nginx: 10 typical errors]]
* https://blog.blakeerickson.com/block-referral-spman-nginx
* https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/blob/master/deny.d/deny.conf
* [[https://github.com/trimstray/nginx-admins-handbook|Nginx Admin's Handbook]]
* [[https://github.com/jukbot/setup-nginx-webserver|Setup a perfect webserver on CentOS/Redhat 7.x guide with understanding]]
* [[https://github.com/kalyabin/kalyabin-ru/wiki/(debian)-Установка-и-настройка-php-fpm|(debian) Установка и настройка php fpm kalyabin-ru]]