Назад | Перейти на главную страницу

NginX (Host) как прозрачный прокси для NginX-Proxy (Docker Container)

Проблема

Я настраиваю Nginx-прокси в докере на моем сервере. NginX-Proxy предназначен для прямого доступа из Интернета, и я хотел бы разместить перед ним прокси.

В идеале NginX (Host) должен быть веб-сервером и обратным прокси-сервером для NginX-Proxy (Docker), который обслуживается с адреса обратной связи (127.0.0.2).

По сути, мне нужна конфигурация прокси для нераспознанных поддоменов, которая передает эти запросы на прокси-сервер NginX-Docker, на котором размещены эти поддомены, в любом из которых может быть включен или не включен SSL.

Домашнее задание

NginX поддерживает проксирование различными способами, но ни один из них не подходит для моего случая использования.

  1. Я надеялся, что NginX на хосте сможет прозрачно проксировать экземпляр докера, используя конфигурацию, аналогичную конфигурации Дэниел Джеймс. Эта конфигурация выполняет завершение SSL на хосте, что не кажется особенно СУХИМ, учитывая, что контейнеры докеров, маршрутизируемые через Nginx-Proxy, сами (возможно) выполняют завершение SSL. Обычно это делается с перенаправлением 301 (из-за ограничений более старых версий Nginx), чтобы заставить весь входящий клиентский трафик использовать https, и заставляет серверную часть / восходящий поток использовать исключительно HTTP или HTTPS. Я хотел бы избежать прерывания на NginX (Host) и позволить Nginx-Proxy справиться с этим. Приятной особенностью здесь является то, что можно фильтровать доменное имя, например. .domain.tld и *.domain.tld узоры. Я видел, как на него ссылались как на человека в среднем посреднике.

  1. NginX обсуждает своего рода комплименты в этом Прокси-протокол документы Я попытался настроить поток, как показано, но, похоже, нельзя фильтровать поток по имени домена в блоке сервера. Хотя, похоже, он перенаправляет трафик HTTP и HTTPS без изменений. Я понимаю, что это своего рода прокси-сервер (используется больше для балансировки / формирования нагрузки).

  1. Прозрачность IP кажется, предлагает решение, которое больше соответствует моим требованиям. У него есть обратная сторона: бегуны / поток NginX (Host) должны запускаться с привилегиями root, и я не уверен, каковы здесь последствия для безопасности (не то, чтобы я размещал совершенно секретные вещи, но дыра - это дыра). Это также требует, чтобы можно было изменить таблицы маршрутизации / IP-адресов контейнеров докеров, что я не уверен, что это возможно.

  2. В Прозрачность IP doc также упоминает DSR как альтернативное средство проксирования другого сервера, но затем сообщает, что NginX не поддерживает это. Я не знаю, что это.

MWE

В моих первоначальных усилиях я хешировал следующее, которое нормально возвращает сайт через HTTP, но не может вернуть сайт через HTTPS. Это требует стратегии MitM / обратного прокси. Я оставил это для согласования с комментариями.

server {
 server_name .domain.tld;
 # note : .domain.tld matches both *.domain.tld and domain.tld
 listen X.X.X.X:80;
 listen [X:X:X:X:X:X:X]:80;
 listen X.X.X.X:443 ssl;
 listen [X:X:X:X:X:X:X]:443 ssl;

 server_tokens off;

 # Logging
 access_log /var/log/nginx/docker_proxy-access.log main;
 error_log /var/log/nginx/docker_proxy-error.log info;

 location / {
  proxy_pass $scheme://127.X.X.X; # Local service IP Address 
  # Alternatively : proxy_pass $scheme://$http_host$uri$is_args$args;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Host $host;
 }
}

Как мне пройти через запрошенный домен? С помощью 127.X.X.X похоже, сбивает с толку вышестоящую службу, которой требуется доменное имя для разрешения контейнера докеров, который предоставляет службу (это было разрешено в комментариях). Я не уверен, следует ли мне настраивать восходящую службу или использовать proxy_bind Вот ? Должен ли я установить proxy_redirect атрибут тоже? Должен ли я иметь отдельные серверные блоки для HTTP и HTTPS?

Поскольку я впервые спросил об этом, я попробовал предложения @ c4f4t0r о прямом использовании Traefik. Это в значительной степени сработало, но Traefik - это прокси-сервер уровня 7, то есть он работает на уровне приложения, а не на транспортном уровне. Он не может перенаправить любой HTTPS-трафик на локальный веб-сервер вместе с ним на хосте. Таким образом, сквозной протокол SSL (SNI) здесь не подходит. Кажется, можно выполнить SSL-Bridging, то есть разорвать SSL-соединение на Traefik и создать новое для локального сервера.

В совете @Ernest Kiwele я пропустил проверку, обрабатывает ли вышестоящий сервер протокол прокси, но я не знал, что это так, и не включал его в то время.

Здесь также есть тонкость: в приведенной выше конфигурации я по существу разрываю HTTP-соединение, изменяю заголовок и устанавливаю новый. Это делается через прокси-протокол для вышестоящей службы. Поскольку это HTTP, такой способ соединения довольно распространен. HTTPS дополнительно требует повторного шифрования на каждом этапе завершения / инициации. Я надеялся передать его без расшифровки / повторного шифрования трафика. Как оказалось, это возможно с потоками NginX, как показано на этом рисунке. ответ.

Чтобы решить мою проблему, мне пришлось создать как http{server{}} серверный блок и stream{server{}} блок. Прежний мост и упаковка HTTP-соединения в протоколе прокси в NginX. Последний оборачивает поток HTTPS в оболочку прокси-протокола, определяемую SNI, и передает его непосредственно соответствующему бэкэнду, эффективно передавая NginX и необходимость моста и де / шифрования.