Вопрос или проблема
Моя ситуация:
У меня установлен nginx на ubuntu 24.04. Он имеет несколько конфигураций, в которых выступает как обратный прокси, завершающий соединения для TLS-доменов, локальных для этого сервера (например, wordpress). Для них настроены сертификаты с помощью Let’s Encrypt. Это работает хорошо. Примеры таких доменов: https://blog.domain/
Теперь я хочу добавить поддомен, например, https://*.A.domain/, и хочу, чтобы nginx посредством SNI перенаправлял все эти запросы на один upstream. Причина в том, что у меня на хосте работает kubernetes и я хочу, чтобы он контролировал этот поддомен, не требуя постоянной перенастройки "внешнего" nginx.
Я видел у других создание карт, например:
stream {
map $ssl_preread_server_name $name {
.A.domain $ssl_preread_server_name;
}
server {
listen 0.0.0.0;
proxy_pass 10.244.0.1:30443;
ssl_preread on;
}
}
в их блоке stream, но кажется, что я не могу понять, как сделать так, чтобы это не мешало, например, блогу на хосте, который имеет свой собственный блок server, как:
server {
listen 443 ssl;
http2 on;
ssl_certificate /etc/letsencrypt/live/domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain/privkey.pem;
...
server_name blog.domain;
location {
...
proxy_pass http://172.17.0.1:8181;
}
}
Как я могу достичь этой цели совместного использования порта 443, чтобы домены, соответствующие условиям, завершались по SSL nginx, а несовпадающие (или совпадающие с поддоменом через SNI) пересылались дальше как TCP-прокси?
Ответ или решение
Настройка nginx для реализации SSL-приёма на свой адрес (SNI) с маршрутизацией wildcard для поддоменов, а также проксирование и завершение подключения для других доменов, является сложной, но важной задачей, особенно при наличии разнообразных приложений, работающих как на одном хосте, так и через внешние системы, такие как Kubernetes.
Теория
Nginx прежде всего используется для обработки HTTP/HTTPS-запросов. Однако конфигурация на уровне SSL/TLS часто требует нестандартных методов, особенно при работе с поддоменами через TLS SNI (Server Name Indication). SNI позволяет одному IP-адресу обслуживать несколько SSL-сертификатов для разных доменов, что критически для сценариев с множеством поддоменов.
Основные задачи:
- Обработка поддоменов (
*.A.domain
) c использованием SNI для маршрутизации на upstream Kubernetes. - Обработка доменов без вмешательства в работу существующих проксирований, например,
blog.domain
.
Использование блока stream
в Nginx позволяет маршрутизировать TCP/SSL-трафик на основе имени сервера (SNI) перед тем, как будет установлено шифрование, что важно, если нужно передать соединение как есть, не расшифровывая.
Пример
Вот пример конфигурации для реализации заданных задач:
Конфигурация для SNI маршрутизации:
- Stream Block для Поддоменов:
stream {
map $ssl_preread_server_name $sni_host {
.A.domain 10.244.0.1:30443; # IP и порт вашего Kubernetes ingress
}
server {
listen 443;
proxy_pass $sni_host;
ssl_preread on;
}
}
- HTTP Block для Обычных Доменов:
http {
server {
listen 443 ssl http2;
server_name blog.domain;
ssl_certificate /etc/letsencrypt/live/domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain/privkey.pem;
location / {
proxy_pass http://172.17.0.1:8181;
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;
}
}
}
Применение
-
Управление Поддоменами (.A.domain):
- Блок
stream
позволяет принимать входящие соединения на уровне TCP без вмешательства в их шифрование, полезно для случаев, когда соединение должно быть передано незашифрованным. map
использует переменную$ssl_preread_server_name
, чтобы направить входящие коннекшены на Kubernetes, благодаря IP и порту, которые вы указываете.
- Блок
-
Работа с Обычными Доменами (
blog.domain
):- Блок
http
обеспечивает обработку и маршрутизацию трафика, поступающего через обычные HTTPS-запросы, напрямую отнимая TLS-соединение для домена, указанного вserver_name
. - Сертификат и ключ предоставлены, чтобы обеспечить надёжное шифрование и авторизацию соединений.
- Блок
Заключение
Интеграция nginx для работы c SNI и TCL-потоком требует чёткого понимания, как именно Nginx управляет соединениями на разных уровнях. В этом случае блок stream
предоставляет гибкость для выполнения маршрутизации на основе имени сервера, что позволяет поддерживать современные требования к обработке поддоменов и обеспечит легкое управление с существующими конфигурациями.
Рекомендуется также регулярная проверка сертификатов и их обновление через Let’s Encrypt, чтобы обеспечить безопасность и доверие пользователей. В случае сложных архитектур, возможно потребуется установка и использование дополнительных инструментов мониторинга для отслеживания производительности и стабильности системы.