HTTPS и TLS: сертификаты, протоколы, шифры (2026)

Рейтинг: 61% · 6 голосов
Самый подробный курс по Nginx - от первого конфига до production API-gateway. Архитектура и event loop, контексты и location, виртуальные хосты, статика, reverse proxy и upstream-балансировка, кэширование, HTTPS и TLS (post-quantum), HTTP/2 и HTTP/3 QUIC, безопасность и rate limiting, realip, JSON-логи и сквозная трассировка, метрики, тюнинг и траблшутинг. Плюс OpenResty (Lua, фазы, JWT, динамика) и Angie (нативные Prometheus, ACME, dynamic upstream). На основе эталонного gateway и лучших практик. Для новичков и SRE/DevOps. Актуально на 2026 (nginx 1.30/1.31, Angie, ingress-nginx EOL -> Gateway API).
Ответить
Аватара пользователя
Igor_NgINX
Сообщения: 44
Зарегистрирован: 11 май 2026, 05:31

HTTPS и TLS: сертификаты, протоколы, шифры (2026)

Сообщение Igor_NgINX »

Оглавление курса (44)
  1. Что такое Nginx и почему он захватил веб
  2. Установка Nginx, Angie и OpenResty: пакеты, версии, Docker
  3. Первый конфиг с нуля: минимальный сервер за 5 минут
  4. Архитектура процессов: master, worker и event loop
  5. Анатомия конфигурации: контексты, наследование и модульность
  6. Виртуальные хосты: server и server_name
  7. Директива location: матчинг и приоритеты по шагам
  8. Раздача статики: root, alias, try_files, sendfile
  9. Переменные, map и блок if
  10. rewrite, return и канонизация URL
  11. Работа с заголовками: add_header и proxy_set_header
  12. Модель доверия прокси-заголовков: realip и защита от спуфинга
  13. Сжатие: gzip, brotli и zstd
  14. Reverse proxy: proxy_pass и проброс запроса
  15. upstream и балансировка нагрузки
  16. Таймауты, повторы и устойчивость прокси
  17. FastCGI и PHP: nginx + PHP-FPM (и uwsgi/scgi)
  18. WebSocket, gRPC и стриминг через Nginx
  19. Кэширование ответов: proxy_cache и микрокэш
  20. HTTPS и TLS: сертификаты, протоколы, шифры (2026) (вы здесь)
  21. Let's Encrypt и ACME: certbot, acme.sh, нативный ACME Angie
  22. HTTP/2 и HTTP/3 (QUIC) в 2026
  23. Безопасность: заголовки, скрытие версии, ограничения
  24. Rate limiting и защита от перегрузки
  25. Контроль доступа: allow/deny, auth_basic, auth_request и mTLS
  26. Логирование: access_log, форматы и структурированный JSON
  27. Сквозная трассировка запросов и OpenTelemetry
  28. Метрики и мониторинг Nginx
  29. Производительность и тюнинг под нагрузку
  30. Траблшутинг: 502, 504, 403, 404 и debug-лог
  31. OpenResty: Nginx как платформа на LuaJIT
  32. Фазы обработки запроса и Lua-хуки
  33. Lua API: ngx.*, shared dict, cosocket и lua-resty-core
  34. Практика OpenResty: авторизация, JWT, кэш, Redis
  35. Angie: современный форк Nginx 2026
  36. Динамическая конфигурация и service discovery
  37. Nginx как API-gateway и Kubernetes Gateway API
  38. Динамические модули, njs и WAF
  39. Stream-модуль: проксирование TCP и UDP
  40. Деплой, перезагрузка и конфиг как код
  41. Сценарий: статика, SPA и кэширование за CDN
  42. Сценарий: микросервисный gateway по образцу ngx-trace-gateway
  43. Капстоун: собираем production-gateway с нуля
  44. Чек-лист безопасности, CVE 2026 и аудит конфигурации
Открываешь сайт по https, видишь зелёный замок и думаешь, что всё хорошо. А под капотом может тлеть TLS 1.0, RSA-сертификат без цепочки и шифр, который SSL Labs ставит на C. Этот урок про то, как nginx настройка ssl делается в 2026 году, а не по гайду пятилетней давности. Мы разберём терминацию TLS, цепочку сертификата, протоколы и шифры, и три вещи, которые в 2026 ломают старые конфиги: TLS 1.3 не слушает ssl_ciphers, OCSP stapling для Let's Encrypt мёртв, а пост-квантовый обмен ключами внезапно стал реальностью прямо в браузерах.

Боль, которую решаем: ты копируешь чужой ssl-блок из интернета, он "работает", но половина директив либо устарела, либо вообще не применяется к твоему трафику. Разберёмся, что на самом деле делает каждая строчка.

Что такое терминация TLS и как nginx ssl вообще работает

Терминация TLS - это когда nginx сам расшифровывает входящее TLS-соединение и дальше к бэкенду ходит уже по обычному http (или по отдельному внутреннему TLS). Клиент устанавливает шифрованный канал именно до nginx. Это и есть классическая роль reverse-proxy: один узел держит сертификаты, терминирует криптографию и снимает эту нагрузку с приложений.

Чтобы nginx https заработал, нужны три кита: слушающий сокет на 443 с признаком ssl, сертификат и приватный ключ. Минимум выглядит так:

Код: Выделить всё

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;

    server_name cyberlake.ru;

    ssl_certificate     /etc/nginx/ssl/cyberlake.ru/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/cyberlake.ru/privkey.pem;

    location / {
        proxy_pass http://backend_upstream;
    }
}
Обрати внимание: http2 включается отдельной директивой http2 on; - так с nginx 1.25.1. Старый синтаксис listen 443 ssl http2 (параметром listen) считается устаревшим, хотя пока и работает. В современном nginx 1.30/1.31 пиши http2 on; - это единообразно и понятно. В эталонном проекте ngx-trace-gateway https_server.conf исторически использует listen 443 ssl http2, и это рабочий вариант, но на новых сборках лучше переписать на отдельную директиву.

Изображение

Цепочка сертификата: главная ловушка nginx сертификат

Самая частая ошибка новичка - подсунуть в ssl_certificate только сам листовой сертификат домена. В Chrome всё зелёное (у него свой кэш промежуточных), а на curl, мобильном приложении или старом Android вылезает "unable to get local issuer certificate".

Причина: клиент должен построить цепочку доверия от твоего сертификата до корневого CA. Промежуточные сертификаты CA в эту цепочку должен подложить сервер. Поэтому в ssl_certificate всегда подаётся fullchain - листовой сертификат плюс промежуточные, склеенные в один PEM-файл, именно в таком порядке (свой - первым, корневой не нужен):

Код: Выделить всё

ssl_certificate     /etc/nginx/ssl/cyberlake.ru/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/cyberlake.ru/privkey.pem;
Certbot и acme.sh генерируют fullchain.pem сами - бери именно его, а не cert.pem. Проверить порядок и полноту цепочки локально:

Код: Выделить всё

openssl s_client -connect cyberlake.ru:443 -servername cyberlake.ru < /dev/null 2>/dev/null \
  | openssl x509 -noout -issuer -subject -dates
Если в выводе s_client раздел "Certificate chain" содержит 0 (твой) и 1 (промежуточный) - всё на месте. Если только 0 - цепочка неполная, чини fullchain.

nginx ssl_protocols: только TLS 1.2 и TLS 1.3

В 2026 году живых протокола ровно два. TLS 1.0 и 1.1 признаны небезопасными давно (RC4, слабый MAC, отсутствие AEAD), а в nginx они по умолчанию выключены с версии 1.27. Но не полагайся на дефолт - пиши явно, чтобы конфиг был самодокументированным:

Код: Выделить всё

ssl_protocols TLSv1.2 TLSv1.3;
Это ровно то, что стоит в global_ssl.conf эталонного проекта. TLS 1.3 - это не косметика: он убрал целый класс уязвимых режимов, сократил рукопожатие до 1-RTT (а с 0-RTT и ssl_early_data - до нуля для повторных), и оставил только AEAD-шифры. Если у тебя в проде ещё включён TLSv1.1 "на всякий случай для старых клиентов" - этих клиентов в 2026 почти нет, а дыра реальна. Выключай.

Шифры в 2026: почему ssl_ciphers НЕ применяется к TLS 1.3

Вот фундаментальный момент, который ломает интуицию. Директива ssl_ciphers управляет только шифрами TLS 1.2 и ниже. К TLS 1.3 она не применяется вообще - ни одной буквы из неё TLS 1.3 не читает.

Почему так. В TLS 1.3 набор шифров жёстко зафиксирован стандартом - их всего пять, и все они AEAD: TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256 и пара с CCM. Договариваться о "плохих" шифрах там просто не из чего, поэтому отдельная гибкая строка как в TLS 1.2 не нужна. Технически nginx для ssl_ciphers зовёт openssl-функцию для TLS 1.2 (set_cipher_list), а ciphersuites TLS 1.3 настраиваются другой функцией.

Что это значит на практике. Твоя строка ssl_ciphers с длинным списком ECDHE-ECDSA-AES256-GCM... работает ровно для TLS 1.2. Для TLS 1.3 список фиксирован, и если ты хочешь, например, исключить CHACHA20 или поменять приоритет - это делается другой директивой:

Код: Выделить всё

# TLS 1.2 - сюда смотрит ssl_ciphers
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

# TLS 1.3 - сюда ssl_ciphers НЕ смотрит, нужен ssl_conf_command
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256;
ssl_conf_command - это прямая передача параметра в OpenSSL, доступна с nginx 1.19.4. Большинству проектов трогать ciphersuites TLS 1.3 не нужно - дефолтные пять и так безопасны. Но знать, что ssl_ciphers их не покрывает, обязательно: иначе ты будешь править строку шифров и удивляться, почему SSL Labs не реагирует.

ssl_prefer_server_ciphers и кривые ssl_ecdh_curve

ssl_prefer_server_ciphers on; в эпоху TLS 1.2 заставляло сервер навязывать свой порядок шифров клиенту - это защищало от клиента, который предлагает слабый шифр первым. В TLS 1.3 это снова неактуально (там сервер и так выбирает), но для TLS 1.2 директива остаётся полезной и стоит в global_ssl эталона.

Код: Выделить всё

ssl_prefer_server_ciphers on;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
ssl_ecdh_curve задаёт эллиптические кривые для ECDHE-обмена ключами - это то, на чём строится forward secrecy. X25519 - быстрая и безопасная кривая по умолчанию, prime256v1 (она же secp256r1) и secp384r1 - для совместимости.

Пост-квантовый обмен ключами - реальность 2026. Большие квантовые компьютеры угрожают именно обмену ключами: запиши шифрованный трафик сегодня, расшифруй через 10 лет, когда появится квантовый компьютер ("harvest now, decrypt later"). Ответ - гибридный обмен X25519MLKEM768: классический X25519 плюс пост-квантовый ML-KEM-768, оба дают вклад в общий секрет. Если квантовый компьютер сломает один - второй держит.

Код: Выделить всё

ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1;
Требует OpenSSL 3.5+ (в nginx 1.29.8 уже идёт связка с OpenSSL 4.0). Chrome и Firefox уже умеют X25519MLKEM768 - то есть это не лаба, а живой трафик: ставь гибрид первым, классику оставь в списке для клиентов, которые ещё не умеют. Накладные минимальные (плюс пара килобайт в рукопожатии). Это самый дешёвый способ сделать nginx tls квантово-устойчивым уже сегодня.

OCSP stapling - в 2026 это legacy для Let's Encrypt

Раньше всех учили: включай ssl_stapling, чтобы сервер сам прикладывал свежий ответ OCSP (статус отзыва сертификата) и клиенту не надо было ходить к CA. Звучало правильно.

В 2026 картина изменилась. Let's Encrypt убрал OCSP-URL из своих сертификатов 7 мая 2025 года и перешёл на CRL-схему. Для LE-сертификата ssl_stapling теперь сшивать нечего - в сертификате просто нет ссылки на OCSP-ответчик.

Код: Выделить всё

# Legacy: для Let's Encrypt в 2026 БЕСПОЛЕЗНО (OCSP-URL убран).
# Оставлять только если CA реально выдаёт OCSP (некоторые коммерческие).
# ssl_stapling on;
# ssl_stapling_verify on;
# resolver 1.1.1.1 8.8.8.8 valid=300s;
Вывод: если у тебя сертификат от Let's Encrypt - не пиши ssl_stapling, он ничего не даст и только засорит конфиг. В эталонном global_ssl директивы stapling присутствуют - это нормально для коммерческих CA, но для LE их можно смело убирать. Не копируй stapling вслепую "потому что в гайде было".

Сессии: переиспользование рукопожатия

TLS-рукопожатие стоит дорого (асимметричная криптография). Чтобы повторные соединения не платили эту цену, есть кэш сессий:

Код: Выделить всё

ssl_session_cache   shared:SSL:50m;
ssl_session_timeout 10m;
ssl_session_tickets off;
shared:SSL:50m - разделяемый между всеми воркерами кэш на 50 МБ (примерно 200 тысяч сессий; число до двоеточия - не размер, а имя зоны). ssl_session_timeout - сколько сессия валидна.

А вот ssl_session_tickets off; - осознанное решение, и оно стоит в эталоне. Тикеты позволяют возобновлять сессию без серверного состояния, но если не ротировать ключ тикетов, они ломают forward secrecy: украв один ключ, злоумышленник расшифрует весь записанный трафик. Без грамотной ротации ключей безопаснее тикеты выключить и полагаться на session cache. В TLS 1.3 механизм возобновления другой (PSK), но логика та же - не раздавай долгоживущие секреты бесконтрольно.

HSTS, ssl_dhparam и несколько сертификатов

HSTS. Заголовок Strict-Transport-Security говорит браузеру "ходи сюда только по https, http не пробуй вообще":

Код: Выделить всё

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
В эталоне HSTS закомментирован в global_ssl - и это правильная осторожность: включай его на уровне server и только когда уверен, что весь домен и поддомены живут на https. Иначе с includeSubDomains можно отрезать себе поддомен, который ещё на http, на два года (max-age). Флаг always; обязателен, чтобы заголовок ставился и на ответах с ошибкой.

ssl_dhparam - частый карго-культ. Эта директива задаёт параметры Diffie-Hellman и нужна только для классических DHE-шифров (без EC). Если у тебя современный набор на ECDHE (а он у тебя такой) и TLS 1.3 с ECDHE - DHE не используется, и ssl_dhparam не нужен. Не копируй генерацию 4096-битного dhparam "потому что все так делают" - на чистом ECDHE/TLS 1.3 это мёртвая строка. Нужна она, только если ты осознанно держишь DHE-шифры для каких-то древних клиентов.

Несколько сертификатов - RSA и ECDSA. nginx умеет отдавать разные сертификаты на один server_name в зависимости от того, что поддерживает клиент. ECDSA быстрее и компактнее, но старый клиент может его не понять - тогда отдаём RSA:

Код: Выделить всё

ssl_certificate     /etc/nginx/ssl/cyberlake.ru/ecdsa_fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/cyberlake.ru/ecdsa_privkey.pem;

ssl_certificate     /etc/nginx/ssl/cyberlake.ru/rsa_fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/cyberlake.ru/rsa_privkey.pem;
Две пары директив в одном server-блоке - nginx сам выберет нужный по ClientHello. А SNI (Server Name Indication) - это поле в ClientHello, по которому nginx понимает, какой server_name запрашивают, ещё до выбора сертификата. Без SNI на одном IP жил бы только один https-сайт; благодаря SNI nginx на одном 443-порту обслуживает десятки доменов, каждый со своим сертификатом.

Типичные грабли
  • В ssl_certificate подложен только листовой сертификат без промежуточных. Chrome молчит, curl и мобилки ругаются. Всегда fullchain.
  • Правишь ssl_ciphers и ждёшь, что изменится TLS 1.3. Не изменится - для 1.3 это ssl_conf_command Ciphersuites.
  • Скопировал ssl_stapling из старого гайда на Let's Encrypt-сертификат. Бесполезно с мая 2025, OCSP-URL у LE нет.
  • Сгенерил dhparam.pem на 4096 бит и подключил, хотя весь трафик на ECDHE. Мёртвая директива, форвард-секреси она тебе не добавит.
  • Включил HSTS с includeSubDomains и preload, а поддомен blog. ещё на http. Браузеры на max-age отказываются туда ходить.
  • Забыл http2 on; и удивляешься, почему мультиплексирование не работает. Параметр listen ... http2 устарел.
  • Положил приватный ключ с правами 644. Любой пользователь системы его прочитает. chmod 600, владелец root.
Мини-лаба: собери боевой ssl-блок руками

Повтори по шагам на тестовом nginx (1.30+).
  • Шаг 1. Получи сертификат LE: certbot certonly --webroot -w /var/www/html -d test.example.com. Найди в /etc/letsencrypt/live/test.example.com/ файлы fullchain.pem и privkey.pem.
  • Шаг 2. Создай global_ssl.conf с ssl_protocols TLSv1.2 TLSv1.3; набором ssl_ciphers, ssl_prefer_server_ciphers on; ssl_ecdh_curve X25519:prime256v1; session_cache 50m, session_tickets off. Подключи его include в http-блок.
  • Шаг 3. В server-блоке пропиши listen 443 ssl; listen [::]:443 ssl; http2 on; и обе директивы ssl_certificate/ssl_certificate_key на fullchain.
  • Шаг 4. Проверь конфиг: nginx -t, затем nginx -s reload.
  • Шаг 5. Локальная проверка цепочки: openssl s_client -connect test.example.com:443 -servername test.example.com < /dev/null 2>/dev/null | openssl x509 -noout -dates. Убедись, что в "Certificate chain" есть и 0, и 1.
  • Шаг 6. Проверь протокол: openssl s_client -connect test.example.com:443 -tls1_3 - должно подключиться. Затем -tls1_1 - должно отлететь (протокол выключен).
  • Шаг 7. Прогони домен через SSL Labs (ssllabs.com/ssltest) и сверь конфиг с Mozilla SSL Configuration Generator (ssl-config.mozilla.org), профиль Intermediate. Это эталон, на который стоит равняться.
  • Шаг 8 (продвинутый). Если OpenSSL 3.5+ - добавь ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1; перезагрузи и открой сайт в свежем Chrome: в DevTools -> Security увидишь согласованную пост-квантовую группу.
Контрольные вопросы
  • Почему правка ssl_ciphers не влияет на соединения по TLS 1.3 и какой директивой настраиваются ciphersuites 1.3?
  • Что должно лежать в файле, указанном в ssl_certificate, и почему Chrome может не заметить проблему, которую видит curl?
  • Почему в 2026 году ssl_stapling для сертификата Let's Encrypt не имеет смысла?
  • В каком случае ssl_dhparam реально нужен, а в каком это мёртвая строка в конфиге?
Итог

Рабочий nginx ssl в 2026 - это fullchain в ssl_certificate, ssl_protocols TLSv1.2 TLSv1.3, понимание что ssl_ciphers - только про TLS 1.2 (а 1.3 - это ssl_conf_command), выключенные тикеты, осознанный HSTS на уровне server, отсутствие культовых dhparam и мёртвого OCSP stapling для LE, и гибридный X25519MLKEM768, если OpenSSL это уже умеет. Не копируй чужие ssl-блоки вслепую: сверяйся с Mozilla SSL Config Generator и SSL Labs, и каждая строка должна делать ровно то, что ты от неё ждёшь.
👍2 ❤️5 🔥2 😄 🤔3
Аватара пользователя
khinzman
Сообщения: 1
Зарегистрирован: 12 май 2026, 02:49

Re: HTTPS и TLS: сертификаты, протоколы, шифры (2026)

Сообщение khinzman »

Блин, я годами таскал ssl_dhparam во всех конфигах и ни разу не задумался что у меня везде ECDHE. Только что выпилил 4 строки и nginx -t зелёный. Спасибо за ssl_ciphers/TLS1.3 момент, реально не знал что 1.3 её игнорит.
👍2 ❤️1 🔥 😄 🤔1
Аватара пользователя
Lankd
Сообщения: 1
Зарегистрирован: 26 май 2026, 08:59

Re: HTTPS и TLS: сертификаты, протоколы, шифры (2026)

Сообщение Lankd »

Вопрос по двум сертификатам в одном server: а если положить ECDSA первым и RSA вторым, nginx точно сам разрулит по ClientHello или порядок важен? И как проверить что старому клиенту реально уехал RSA, а не ECDSA?
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Кэширование ответов: proxy_cache и микрокэш
Следующая глава →
Let's Encrypt и ACME: certbot, acme.sh, нативный ACME Angie

Все главы курса «Nginx профессионально: от первого конфига до API-gateway на OpenResty и Angie»

Поделиться темой: ✈ Telegram VK
  • Похожие темы
Похожие запросы: HTTPS и TLS в nginx: сертификаты и протоколыLet's Encrypt для nginx: бесплатный сертификатHTTP/2 и HTTP/3 (QUIC) в nginx

Вернуться в «Nginx профессионально: от первого конфига до API-gateway на OpenResty и Angie»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 0 гостей