1. 1

# конспект · шаг 1 из 1

Шпаргалка по всему курсу

выжимка - её можно унести в заметки

Весь курс на одной странице: шесть решений, все приоритеты, карта диагностики и готовые блоки конфига.

Шесть решений по каждому запросу

1. какой server?      listen (адрес+порт) → server_name → default_server → первый блок
2. какой location?    =  →  ^~ длинный префикс  →  регулярки сверху вниз  →  префикс
3. выйти досрочно?    return / rewrite  (фаза rewrite - ДО access!)
4. кто отдаёт?        root/alias + try_files  |  proxy_pass / fastcgi_pass
5. чем обвесить?      add_header, expires, gzip
6. что в лог?         access_log (пишется ПОСЛЕ ответа)

Полный конвейер фаз

server rewrite → find location → rewrite → preaccess (limit_*)
→ access (allow/deny, auth) → try_files → content → filters

Отсюда: return в location бьёт deny; return в server{} бьёт выбор location; лимиты считаются после перезаписи URI.

Приоритеты, которые спрашивают

Что Порядок
server_name точное → *.имяимя.* → регулярка (последняя!)
location =^~ → регулярки по порядку в файле → длинный префикс
наследование ближайшее значение побеждает; массивы замещаются целиком

Директивы-массивы (наследуются «всё или ничего»)

add_header, proxy_set_header, fastcgi_param, limit_req, allow/deny. Одна такая директива в location отменяет все унаследованные.

Готовые блоки

# catch-all: чужой Host не должен видеть твой сайт
server { listen 80 default_server; server_name _; return 444; }

# http → https с исключением для ACME
server {
    listen 80;
    location /.well-known/acme-challenge/ { root /var/www/certbot; }
    location / { return 301 https://$host$request_uri; }
}

# SPA + ассеты
location / { try_files $uri $uri/ /index.html; }
location /assets/ {
    try_files $uri =404;                       # честная 404 на отсутствующий файл
    add_header Cache-Control "public, max-age=31536000, immutable" always;
}

# прокси к группе
upstream app { server app-1:8000 max_fails=3 fail_timeout=15s; keepalive 32; }
location /api/ {
    proxy_pass http://app;
    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_set_header X-Forwarded-Proto $scheme;
}

# WebSocket
map $http_upgrade $connection_upgrade { default upgrade; '' close; }
location /ws/ {
    proxy_pass http://app;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_read_timeout 3600s;
}

# лимит на вход
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
location = /api/login { limit_req zone=login burst=5 nodelay; limit_req_status 429; }

# кеш ответов
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=API:10m inactive=60m max_size=2g;
location /api/catalog/ {
    proxy_cache API;
    proxy_cache_key "$scheme$request_method$host$request_uri";
    proxy_cache_valid 200 1m;
    proxy_cache_bypass $cookie_session;
    proxy_no_cache     $cookie_session;
    add_header X-Cache-Status $upstream_cache_status always;
    proxy_pass http://app;
}

Команды

Задача Команда
итоговый конфиг nginx -T
проверить и применить nginx -t && systemctl reload nginx
карта чужого сервера nginx -T \| grep -n "server_name\|listen\|proxy_pass"
переоткрыть логи nginx -s reopen
коды ответов за период awk '{print $9}' access.log \| sort \| uniq -c \| sort -rn
проверить цепочку TLS openssl s_client -connect host:443 -servername host
замер отдачи curl -o /dev/null -s -w 'ttfb=%{time_starttransfer} total=%{time_total}\n' URL
состояние сервера curl -s http://127.0.0.1/nginx_status

Что делать, если…

Ситуация Ответ
открывается не тот сайт нет default_server; отвечает первый блок на порту
чужой домен показывает твой сертификат нет catch-all на 443 / ssl_reject_handshake
в блок попал не тот запрос префикс - это строка: /app ловит /application.log
регулярный server_name не срабатывает его перебивает маска
403 на каталоге нет index и autoindex off
«у меня работает, у интеграции нет» указали cert.pem вместо fullchain.pem
пропала строка запроса при редиректе $uri вместо $request_uri
исчезли заголовки безопасности add_header в location отменил унаследованные
бэкенд видит Host: app нет proxy_set_header Host $host
502 too big header увеличить proxy_buffer_size
504 proxy_read_timeout - это пауза между чтениями
502 no live upstreams слишком агрессивные max_fails; при одном сервере в группе не бывает
499 клиент ушёл: смотреть время ответа бэкенда
gzip не сжимает шесть причин: типы, размер, proxied, клиент, уже сжато, 1.0
кеш не работает нет proxy_cache_valid
чужая корзина в кеше нет bypass/no_cache
лимит отдаёт 503 limit_req_status 429
за прокси все клиенты - один нужен realip
продление сертификата сломалось блок ACME стоит после return 301
HTTP/3 не включается UDP/443 закрыт или нет Alt-Svc
SPA отдаёт 200 на отсутствующий ассет ассетам нужен свой location с =404
после reload висят воркеры worker_shutdown_timeout
логи пишутся «в никуда» после ротации nginx -s reopen
reload вернул ноль, а конфиг не применился занят порт или нет файла - смотреть error_log, код возврата врёт
проксируемый запрос отдаёт 500 кончились слоты: в worker_connections входят и соединения к бэкендам
белая страница при 200 в логах нет include mime.types, а nosniff запрещает исполнять text/plain
404 ассета закешировался на год always на вечном кеше уводит заголовок и на ошибку
SMTP или IMAP за stream не работает ssl_preread ждёт первых байтов клиента: 30 секунд и обрыв
forward proxy отвечает 502 на всё не задан resolver

Свежее, чего нет в старых статьях

  • http2 on; директивой (1.25.1), а не флагом в listen;
  • proxy_http_version по умолчанию 1.1 и keepalive включён сам (1.29.7);
  • least_time открыт для всех (1.31.0), sticky с route/drain (1.29.6);
  • ssl_stapling с сертификатами Let's Encrypt - мёртвая строка (OCSP выключен в 2025);
  • server push мёртв, вместо него early_hints on; (1.29.0);
  • add_header_inherit (1.29.3), max_headers (1.29.8);
  • нативный ACME-модуль (1.29.0), forward proxy tunnel_pass (1.31.0);
  • виртуальные серверы и pass в stream - с 1.25.5;
  • json_set - разбор JSON прямо в конфиге, путь пишется точками;
  • njs 1.0 объявил старый движок устаревшим, но пакет под 1.31.5 несёт именно его;
  • brotli и zstd не входят в стандартную сборку.

Куда идти дальше

Своя песочница в контейнере и повторить разбор поломок руками: снять default_server, перепутать слеши в proxy_pass, поставить add_header в location, включить лимит 1r/s - и посмотреть на симптом своими глазами.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.