TLS-терминация в Nginx: разбор инцидента
После переноса TLS на Nginx приложение начало возвращать редиректы, терять IP клиента и иногда отдавать 502. Разбираем, как найти границу сбоя, проверить конфигурацию и не сломать проксирование повторно.

Реконструкция типичного инцидента: после переноса TLS-терминации на Nginx приложение за прокси стало отправлять пользователей по кругу на HTTPS, записывать адрес Nginx вместо IP клиента, а часть запросов завершалась ошибкой 502. Причина обычно не в самом сертификате, а в несогласованности трёх уровней: TLS-соединения, HTTP-заголовков и соединения Nginx с upstream. Ниже разберём, как локализовать сбой и какие проверки оставить в проде.
Что именно сломалось на границе TLS
До изменения схемы клиент устанавливал HTTPS-соединение непосредственно с приложением или старым прокси. После изменения TLS завершается на Nginx, а дальше он отправляет обычный HTTP-запрос во внутреннюю сеть:
- клиент устанавливает TLS с Nginx;
- Nginx расшифровывает запрос и выбирает виртуальный сервер по SNI;
- Nginx проксирует запрос на upstream, часто по HTTP;
- приложение должно узнать, что исходный запрос был HTTPS, из заголовка
X-Forwarded-Proto; - приложение формирует ответ, абсолютные ссылки, cookie и редиректы с учётом этой информации.
Если заголовок не передан или приложение не доверяет прокси, оно видит обычный HTTP. Для URL, где обязательна защита, приложение отвечает редиректом на HTTPS. Клиент снова приходит на Nginx, а тот снова передаёт приложению HTTP. Так появляется цикл.
TLS-терминация заканчивается не на строке
ssl_certificate. Она заканчивается только тогда, когда приложение корректно понимает исходную схему, хост и адрес клиента.
* TLS-терминация — расшифровка HTTPS на пограничном прокси. После неё прокси может передавать запрос дальше по HTTP или устанавливать новое TLS-соединение с upstream. Эти два участка защищаются независимо.
Реконструкция инцидента по симптомам
Симптом 1. Редирект повторяется бесконечно
Проверяйте цепочку заголовков, а не только сертификат в браузере. Запрос к публичному адресу должен показать конечный ответ или понятный единичный редирект:
curl -I -L --max-redirs 5 https://example.com/
Если команда завершается сообщением о превышении числа редиректов, зафиксируйте каждый ответ без автоматического перехода:
curl -sS -D - -o /dev/null https://example.com/
В ответах ищите Location. Если URL в нём постоянно меняет http на https или повторяет тот же адрес, сравните это с логом приложения. В Nginx полезно временно добавить в формат access log значения $scheme, $http_x_forwarded_proto, $host и $upstream_status. Постоянно логировать все заголовки не стоит: среди них могут оказаться персональные данные.
Симптом 2. В приложении виден IP Nginx
Адрес клиента должен передаваться отдельно и обрабатываться приложением только после настройки доверенных прокси. В базовой конфигурации Nginx обычно используют:
location / {
proxy_pass http://app_backend;
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;
}
X-Forwarded-For нельзя бездумно считать достоверным на внешнем входе: клиент может прислать такой заголовок сам. Доверять цепочке следует только после ограничения доступа к Nginx и настройки доверенных адресов в самом приложении. Иначе в логах, rate limit и правилах доступа можно получить подменённый IP.
Симптом 3. Часть запросов отвечает 502
Код 502 означает, что Nginx не получил корректный ответ от upstream. TLS на внешнем участке не доказывает, что внутреннее соединение работает. Наиболее частые причины:
- в
proxy_passуказан неправильный порт или имя сервиса; - приложение слушает только
127.0.0.1, а Nginx работает в другом контейнере; - upstream ожидает HTTPS, а Nginx подключается по HTTP, либо наоборот;
- приложение закрывает соединение из-за слишком короткого тайм-аута;
- после изменения DNS Nginx продолжает использовать старый адрес до перезагрузки конфигурации.
Сначала проверьте конфигурацию и примените её безопасно:
nginx -t
nginx -s reload
Затем смотрите error log Nginx в момент запроса. Сообщения вроде connect() failed (111: Connection refused), upstream timed out и no live upstreams ведут к разным веткам диагностики. Проверяйте соединение с upstream из той же сетевой среды, где работает Nginx, а не только с ноутбука администратора.
Как должна выглядеть минимальная схема
Ниже пример для Nginx 1.24.x и 1.26.x. Директивы относятся к стандартным модулям HTTP; конкретные пути к сертификатам и имя upstream замените своими. В примере TLS заканчивается на Nginx, а приложение получает HTTP.
upstream app_backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/tls/example.com.fullchain.pem;
ssl_certificate_key /etc/nginx/tls/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://app_backend;
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;
}
}
Сервер на 80-м порту нужен только для перенаправления. На 443-м Nginx принимает TLS и передаёт приложению исходную схему через $scheme. Если внутренний участок тоже должен быть зашифрован, в proxy_pass указывают HTTPS-схему и отдельно настраивают проверку сертификата upstream. Это уже другая модель доверия, а не автоматическое продолжение внешнего TLS.
Сравнение вариантов терминации
| Схема | Что происходит | Цена и риск | Когда выбирать |
|---|---|---|---|
| TLS на Nginx, HTTP до приложения | Nginx расшифровывает запрос и проксирует его внутри сети | Проще диагностика и меньше накладных расходов, но внутренний трафик не шифруется | Одна защищённая внутренняя сеть с контролируемым доступом |
| TLS на Nginx, HTTPS до приложения | Nginx устанавливает новое TLS-соединение с upstream | Нужны сертификаты, доверие к CA и проверка имени; больше точек для ошибки | Недоверенная сеть между узлами или требования комплаенса |
| Проброс TLS без расшифровки | Nginx или балансировщик передаёт TCP дальше | Прокси не видит HTTP и не может менять заголовки или маршрутизировать URL | Когда TLS должен завершаться на приложении |
Что проверять перед повторным включением
- Сертификат и имя. Проверьте, что сертификат покрывает реальное имя, цепочка полная, а приватный ключ доступен процессу Nginx. Ошибка на этом этапе обычно видна ещё до запроса к приложению.
- Выбор виртуального сервера. Сверьте
server_name, порт 443 и SNI. Запрос к соседнему домену не должен попадать в конфигурацию другого сайта. - Исходная схема. Убедитесь, что в upstream приходит
X-Forwarded-Proto: https, а настройки приложения разрешают доверие к нему только от нужного прокси. - Хост и порты. Сравните DNS-имя или адрес в
upstreamс фактическим портом прослушивания. Проверяйте соединение из контейнера или виртуальной машины Nginx. - Куки и абсолютные URL. После входа проверьте флаги
Secure, домен cookie и адреса в ответах. Ошибка здесь может проявиться только после авторизации. - Откат. Сохраните рабочую конфигурацию и меняйте только один участок за раз. Перезагрузка после
nginx -tне должна быть заменой полноценной проверке через внешний адрес.
Где схема ломается под нагрузкой
Даже исправная конфигурация может упереться не в TLS, а в лимиты соединений. Смотрите одновременно число активных соединений Nginx, время TLS-handshake, время ожидания upstream и долю кодов 499, 502 и 504. Если клиент закрывает соединение раньше ответа, Nginx может записать 499; это не то же самое, что ошибка приложения.
Не делайте вывод по одному среднему времени ответа. Разделяйте p95 и p99 для первого байта, время установки TLS и время ответа upstream. Условия замера нужно записывать: версия Nginx и OpenSSL, число воркеров, размер ответа, количество параллельных клиентов, HTTP/1.1 или HTTP/2. Без этих параметров сравнение «до и после» не доказывает улучшение.
Отдельно проверьте WebSocket и длинные запросы. Для них могут понадобиться дополнительные заголовки Upgrade и увеличенные тайм-ауты. Не добавляйте их глобально без необходимости: обычные HTTP-запросы от этого не становятся надёжнее.
Если не получилось
- «redirected you too many times». Приложение не видит исходный HTTPS или доверяет не тому заголовку. Сравните
$schemeв Nginx с настройкой secure-прокси в приложении. - «502 Bad Gateway» и «Connection refused». Upstream не слушает указанный адрес и порт либо недоступен из сети Nginx. Проверьте bind-адрес и правила firewall.
- «upstream timed out». Приложение не ответило за отведённое время. Найдите медленный запрос и только потом меняйте тайм-ауты.
- Клиентский IP равен адресу прокси. Не передан
X-Forwarded-Forили приложение не настроено его разбирать. Меняйте обе стороны одновременно. - Браузер сообщает о проблеме с сертификатом. Проверьте имя, срок действия, полную цепочку и сертификат, который реально отдаёт нужный виртуальный сервер, а не только файл на диске.
Что делать дальше
Оставьте в мониторинге четыре раздельных показателя: ошибки TLS-handshake, коды 4xx и 5xx на Nginx, ошибки upstream и время ответа приложения. После этого добавьте синтетическую проверку, которая проходит редирект, авторизацию и один запрос к защищённому ресурсу. Для каждого изменения сначала фиксируйте конфигурацию и версию Nginx, затем измеряйте результат на том же сценарии. Инвалидация кеша и настройка HSTS требуют отдельного разбора: они могут изменить симптомы, но не исправляют неверную передачу схемы до приложения.
Разбор научной статьи: Сложный текст — понятным языком, с терминами
Спросить за 12 ₽Источники: NGINX HTTP SSL module documentation, NGINX HTTP proxy module documentation
Частые вопросы
Нужно ли шифровать соединение между Nginx и приложением?
Почему появляется бесконечный редирект с HTTP на HTTPS?
Опасно ли передавать X-Forwarded-For?
Подойдут ли эти настройки для другой версии Nginx?
Что делать, если после настройки всё ещё появляется 502?
Какие подводные камни важны в проде?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.