# теория · шаг 2 из 5
Включаем HTTP/3
Коротко
HTTP/3 добавляют вторым listen рядом с обычным - это два разных сокета, UDP и
TCP, и нужны оба.
listen 443 quic reuseport;плюсlisten 443 ssl;. Сертификат обязателен и для QUIC: без негоno "ssl_certificate" is defined for the "listen ... quic".reuseportпишется один раз на порт, иначеduplicate listen options.- Без
add_header Alt-Svcбраузеры про QUIC не узнают, без открытого UDP в файрволе он не заработает молча, без единой ошибки в логах. - Проверять - переменной
$http3в логе.curl --http3без-onlyумеет тихо откатиться на TCP и соврать.
Если знаешь про два listen, Alt-Svc и UDP в файрволе - листай до «Теперь сам».
Сначала ответь сам
Конфиг написан по статье, сертификат на месте, nginx -t доволен, порт слушает.
Браузер упорно ходит по HTTP/2, в логах ошибок нет. Что забыли?
Вариантов ровно три, и все три - вне блока server, где ты ищешь: не открыт
UDP в файрволе, не отдаётся Alt-Svc или заголовок съело наследование в
location. Ни один из них не даёт ни строчки в error_log: HTTP/3 не
«ломается», он просто не используется.
На что это похоже
Второй вход в здание, о котором никому не сказали. Дверь есть, ключи есть, охрана на месте - а люди ходят через главный, потому что о втором написано на табличке внутри здания, куда они попадают только через главный.
Табличка - это Alt-Svc. Пока её не увидели по TCP, в UDP никто не постучится.
Механизм: два сокета на одном номере порта
Правило
server {
listen 443 quic reuseport; # UDP - для HTTP/3
listen 443 ssl; # TCP - для HTTP/2 и HTTP/1.1
http2 on;
server_name shop.local;
ssl_certificate /etc/letsencrypt/live/shop.local/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/shop.local/privkey.pem;
add_header Alt-Svc 'h3=":443"; ma=86400' always;
root /var/www/shop;
}
Директиву http3 писать не нужно - она on по умолчанию (в отличие от
http2). А сертификат для QUIC обязателен ровно так же, как для ssl:
nginx: [emerg] no "ssl_certificate" is defined for the "listen ... quic" directive in /etc/nginx/conf.d/shop.local.conf:2
nginx: configuration file /etc/nginx/nginx.conf test failed
reuseport включает распределение соединений по рабочим процессам силами ядра.
Параметр относится к сокету, поэтому написать его в двух блоках на одном порту
нельзя:
nginx: [emerg] duplicate listen options for 0.0.0.0:443 in /etc/nginx/conf.d/shop.local.conf:2
nginx: configuration file /etc/nginx/nginx.conf test failed
Сайтов на порту несколько - reuseport пишется в одном из них, любом.
Разбор: Alt-Svc и его цена
add_header Alt-Svc 'h3=":443"; ma=86400' always;
h3=":443" - на каком порту слушает HTTP/3 (пустой хост означает «тот же»),
ma - на сколько секунд запомнить. Флаг always нужен, чтобы анонс уезжал и с
ответами 404: иначе клиент, чей первый запрос не попал в 200, останется на TCP
до следующего раза.
Заголовок ставится на уровне server, и правило наследования из второго раздела
никуда не делось: собственный add_header в каком-нибудь location /api/
отбросит Alt-Svc вместе с остальными. Лечится директивой add_header_inherit merge на уровне http (разбор -
в разделе про наследование).
ma=86400 означает, что браузер сутки будет считать сайт умеющим HTTP/3. Если
после выключения QUIC клиенты жалуются на медленный первый запрос - это они
безуспешно стучатся по UDP и ждут таймаута. Перед экспериментами разумно взять
ma=300, а на сутки переходить, когда всё устоялось.
Разбор: как убедиться, что он работает
Самый честный способ - переменная $http3 в логе: она равна h3 только для
соединений, реально пришедших по QUIC.
log_format quic '$remote_addr "$request" $status proto=$http3 $server_protocol';
Со стороны клиента - curl со сборкой, умеющей QUIC. И тут ловушка:
proto=HTTP/2.0 quic=
proto=HTTP/3.0 quic=h3
Флаг --http3 разрешает попробовать QUIC и молча откатывается на TCP, если
что-то не вышло. Проверять надо --http3-only: он либо соединится по HTTP/3,
либо честно упадёт с ошибкой. В браузере смотри колонку Protocol во вкладке
Network - и помни, что первый запрос всегда придёт по TCP.
Что ломается без этого
Правило файрвола, о котором забывают все. listen 443 quic открывает
UDP-порт, а в файрволе разрешён TCP - его открывали, когда поднимали HTTPS.
Снаружи это выглядит как «HTTP/3 не работает, хотя конфиг правильный»: ошибок
нет, в логах пусто, браузер молча остаётся на TCP.
ufw allow 443/udp
ufw - частый фронтенд к файрволу в Ubuntu/Debian; эта строка открывает
UDP-порт 443. То же самое проверь в облачной security group и на пограничном роутере. И учти:
если перед nginx стоит L4-балансировщик, он тоже должен уметь и пробрасывать
UDP.
Убранная TCP-строка. Оставить один listen 443 quic - значит выключить сайт
для всех, кто не умеет HTTP/3 или чей провайдер режет UDP. И заодно лишить
браузеры возможности узнать про QUIC: Alt-Svc приходит по TCP.
Зачем это в работе
Четыре директивы, которые стоит знать после включения:
quic_retry on - валидация адреса клиента: сервер отвечает пакетом Retry и
продолжает, только если клиент его вернул. На публичных сайтах включать стоит:
без этого QUIC-сервер удобно использовать как усилитель в атаках с подменой
адреса отправителя.
quic_host_key file - ключ, которым шифруются токены проверки адреса и
stateless reset. Без него ключ генерируется случайно при каждом старте, и токены
перестают действовать после reload; за балансировщиком из нескольких серверов
файл должен быть общим.
quic_gso on - отправка пачками через UDP-сегментацию, заметно снимает
нагрузку на процессор. Только Linux с поддержкой UDP_SEGMENT.
quic_bpf on (контекст main, Linux 5.7+) - маршрутизация пакетов по
Connection ID силами ядра. Именно она позволяет мигрирующему соединению
оставаться на своём рабочем процессе.
Про 0-RTT отдельно: ssl_early_data on разрешает клиенту прислать запрос вместе
с первым пакетом, но такой запрос можно записать и воспроизвести повторно.
Для GET каталога это безразлично, для «спиши деньги» - нет. Включать только если
приложение защищено от повторов; работает начиная с nginx 1.29.1 и OpenSSL 3.5.1.
Теперь сам
HTTP/3 включили, curl --http3-only отвечает HTTP/3 200, в логе появились
строки с proto=h3. Через неделю доля h3 в логах - полпроцента, хотя браузеры у
клиентов свежие. Где искать?
Смотри на Alt-Svc в ответах разных маршрутов: скорее всего, на главной он
есть, а на том пути, с которого начинается сессия пользователя, его съел
собственный add_header в location. Проверяется одной командой на каждый
подозрительный путь:
curl -sI https://shop.local/api/config | grep -i alt-svc
Второй кандидат - UDP, открытый на сервере, но зарезанный где-то по пути: облачной security group или корпоративной сетью клиентов. Первый случай чинится, второй - нет, и это нормально: HTTP/3 всегда дополнение к HTTP/2.
Главное
HTTP/3 добавляют вторым listen 443 quic reuseport рядом с listen 443 ssl -
это два сокета, UDP и TCP, и нужны оба. Сертификат обязателен и для QUIC,
reuseport пишется один раз на порт, http3 уже включён по умолчанию. Без
add_header Alt-Svc браузеры про QUIC не узнают, а без открытого UDP в файрволе
он не заработает молча, без единой строки в логах. Проверять - переменной
$http3 в логе и curl --http3-only: обычный --http3 тихо откатывается на
TCP и врёт.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий