1. 1

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

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

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

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

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

Схема для диагностики, а не точный порядок фаз: return в самом server срабатывает до выбора location, а смена URI запускает выбор заново - точная картина в конвейере ниже.

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 отменяет все унаследованные.

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

Это фрагменты, а не файл для вставки целиком: у каждого подписан контекст. upstream, map, зоны лимитов и кеша живут в http, location - внутри своего server. Имена (shop.local, app-1), пути и сертификаты - стенда, их заменяют на свои. Блоки ниже прогнаны вместе на nginx 1.31.8.

# ── http: общие объявления ────────────────────────────────────
upstream app { server app-1:8000 max_fails=3 fail_timeout=15s; keepalive 32; }
map $http_upgrade $connection_upgrade { default upgrade; '' close; }
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=API:10m
                 inactive=60m max_size=2g;

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

# ── http: http → https с исключением для ACME ─────────────────
server {
    listen 80;
    server_name shop.local www.shop.local;   # без имён ответит catch-all
    location ^~ /.well-known/acme-challenge/ { root /var/www/certbot; }
    location / { return 301 https://$host$request_uri; }  # не в server!
}
# ── файл /etc/nginx/snippets/proxy-headers.conf ───────────────
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;
# ── server: SPA + ассеты ──────────────────────────────────────
location / { try_files $uri $uri/ /index.html; }
location /assets/ {
    try_files $uri =404;              # честная 404 на отсутствующий файл
    # вечный кеш - только файлам с хешем в имени, и без always:
    # иначе на год запомнится и 404
    add_header Cache-Control "public, max-age=31536000, immutable";
}

# ── server: прокси к группе ───────────────────────────────────
location /api/ {
    proxy_pass http://app;
    include /etc/nginx/snippets/proxy-headers.conf;
}

# ── server: лимит на вход ─────────────────────────────────────
# точный location не наследует proxy_pass от /api/ - повторяем
location = /api/login {
    limit_req zone=login burst=5 nodelay;
    limit_req_status 429;
    proxy_pass http://app;
    include /etc/nginx/snippets/proxy-headers.conf;
}

# ── server: WebSocket ─────────────────────────────────────────
location /ws/ {
    proxy_pass http://app;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_read_timeout 3600s;
}

# ── server: кеш ответов ───────────────────────────────────────
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

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

Частые причины и с чего начать, а не доказательства: один и тот же симптом дают разные поломки, и причину называет строка в error_log.

Ситуация С чего начать
открывается не тот сайт нет 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 этап назван в строке upstream timed out; proxy_read_timeout - пауза между чтениями
502 no live upstreams слишком агрессивные max_fails; при одном сервере - только от down и max_conns
499 клиент ушёл: смотреть время ответа бэкенда
gzip не сжимает шесть причин: типы, размер, proxied, клиент, уже сжато, 1.0
кеш не работает нет срока: ни proxy_cache_valid, ни Cache-Control от бэкенда; или ответ с Set-Cookie
чужая корзина в кеше нет bypass/no_cache
лимит отдаёт 503 limit_req_status 429
за прокси все клиенты - один нужен realip
продление сертификата сломалось return 301 стоит прямо в server, а не в location /
HTTP/3 не включается UDP/443 закрыт или нет Alt-Svc
SPA отдаёт 200 на отсутствующий ассет ассетам нужен свой location с =404
после reload висят воркеры worker_shutdown_timeout
логи пишутся «в никуда» после ротации nginx -s reopen
reload вернул ноль, а конфиг не применился занят порт или нет файла - смотреть error_log, код возврата врёт
проксируемый запрос отдаёт 500 часто кончились слоты (в worker_connections входят и соединения к бэкендам) - ищи [alert] в error_log
белая страница при 200 в логах нет include mime.types, а nosniff запрещает исполнять text/plain
404 ассета закешировался на год always на вечном кеше уводит заголовок и на ошибку
SMTP (25, 587) или IMAP (143) за stream не работает там первым говорит сервер, а ssl_preread ждёт клиента: 30 секунд и обрыв; на 465 и 993 TLS сразу, и ssl_preread работает
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 не публикуется. Войти, чтобы не вводить имя каждый раз.