# конспект · шаг 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 - и посмотреть на симптом своими глазами.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий