HTTPS и TLS-терминация на Nginx
Nginx снимает с приложения всю тяжесть шифрования: клиент общается с ним по HTTPS, а внутрь, к бэкенду, трафик идёт уже расшифрованным.
«TLS-терминация — это когда Nginx распаковывает шифрование на входе, и бэкенду не нужно ничего знать про сертификаты.»
HTTPS — обязательный стандарт современного веба. Шифрование защищает данные пользователя в пути. Заниматься им должен Nginx, а не приложение: это и быстрее, и проще в управлении сертификатами. Подход называется TLS-терминацией.
Базовый HTTPS-сервер
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000; # к бэкенду — по http
proxy_set_header X-Forwarded-Proto https;
}
}
# отдельный server для редиректа http -> https
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
listen 443 ssl включает HTTPS. Два файла — цепочка сертификата (fullchain.pem) и приватный ключ (privkey.pem). Второй server на порту 80 жёстко перенаправляет всех на https.
Схема TLS-терминации
Клиент Nginx (:443) Бэкенд (:8000)
| | |
|== HTTPS (шифр)=> | |
| |-- расшифровал |
| | http (открыто) --->|
| | <-- http -----------|
|<= HTTPS (шифр)== | |
| | |
Снаружи — зашифрованный канал, внутри (Nginx-бэкенд, обычно по локальной сети или localhost) — открытый http. Бэкенд узнаёт, что исходный запрос был по https, из заголовка X-Forwarded-Proto — иначе он может строить http-ссылки или зациклить редиректы.
Как работает под капотом
При подключении происходит TLS-рукопожатие: клиент и Nginx договариваются о версии протокола и наборе шифров, Nginx предъявляет сертификат, стороны вырабатывают общий сеансовый ключ. Дальше весь трафик шифруется этим ключом. Самая дорогая часть — асимметричная криптография в начале рукопожатия; поэтому Nginx кеширует TLS-сессии и держит keepalive, чтобы не повторять рукопожатие на каждый запрос. Бэкенду шифрование не видно вовсе — Nginx сделал всю работу.
Частые ошибки
- Указать
cert.pemвместоfullchain.pem. Без промежуточных сертификатов часть клиентов не построит цепочку доверия и увидит ошибку. - Забыть
X-Forwarded-Proto. Приложение решит, что запрос по http, и устроит цикл редиректов или смешанный контент. - Оставить http без редиректа. Часть пользователей останется на незащищённой версии.
- Приватный ключ с открытыми правами.
privkey.pemдолжен быть доступен только root.
Best practices
- Всегда
fullchain.pem(цепочка), а не голый сертификат. - Жёсткий редирект
301с http на https отдельным server-блоком. - Передавай
X-Forwarded-Proto httpsна бэкенд. - Права на приватный ключ — строго
600, владелец root.
Терминация против сквозного шифрования
TLS-терминация на Nginx — самый распространённый подход, но важно понимать его компромисс и альтернативы. При терминации трафик между Nginx и бэкендом идёт незашифрованным (http). Если они на одной машине через localhost — это абсолютно безопасно, никто посторонний этот трафик не увидит. Если бэкенд в той же защищённой внутренней сети — тоже обычно приемлемо. Преимущества огромны: сертификат живёт в одном месте, бэкенду вообще не нужно знать про шифрование, и Nginx может смотреть внутрь запроса для маршрутизации, кеширования и сжатия.
Но бывают сценарии со строгими требованиями (финансы, медицина, комплаенс), где недопустим даже незашифрованный участок во внутренней сети. Тогда применяют TLS-сквозь (re-encryption): Nginx терминирует внешний TLS, а к бэкенду подключается уже по новому TLS-соединению через proxy_pass https://... с проверкой сертификата бэкенда. Есть и крайний вариант — TLS passthrough, когда Nginx вообще не расшифровывает трафик, а пробрасывает его на бэкенд как есть (по SNI, средствами stream-модуля); но тогда теряются кеширование и разбор HTTP. Для большинства проектов простая терминация — правильный выбор по умолчанию, а более сложные схемы подключают осознанно, когда того требует модель угроз. Понимание этих вариантов помогает не переусложнять там, где достаточно localhost-проксирования, и не недооценить требования там, где они реально строгие.
Итоги
Nginx терминирует TLS: снаружи HTTPS, к бэкенду — http, плюс заголовок X-Forwarded-Proto. Нужны fullchain.pem и приватный ключ, редирект с http на https и аккуратные права на ключ. Дальше получим бесплатные сертификаты автоматически и закрутим TLS до оценки A+.