У меня есть установка обратного прокси-сервера Nginx, указывающая на приложение SaaS (BigCommerce). Хотя моя конфигурация отлично работает, я не могу гарантировать клиентский IP отображается в серверной части SaaS вместо Обратный прокси IP. В бэкэнде SaaS нет механизма для добавления списка доверенных IP-адресов или использования set_real_ip_from
и real_ip_header
поэтому вместо этого мне было поручено реализовать proxy_protocol
на обратном прокси-сервере, чтобы гарантировать, что заголовки IP передаются через обратный прокси-сервер с IP-адресом клиента, а не с его собственным.
В http
server
контекст
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;
proxy_set_header X-Forwarded-Host $host:$server_port;
# support http 1.1 persistent connections
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
Когда я включаю proxy_protocol
на моем listen
директива в контексте http-сервера (например, listen 443 ssl http2 proxy_protocol
), Я получаю Broken Header
ошибка в nginx и connection_reset
в моем браузере.
Кроме того, я попытался включить proxy_protocol
через stream
контекст, как это указано в «Протокол принятия прокси» документы от Nginx:
В stream
контекст
stream {
server {
listen 12345;
proxy_pass example.com:12345;
proxy_protocol on;
}
}
Я не знаком с proxy_protocol
поэтому я не знаю, что мне не хватает, чтобы это работало.
Технически говоря, я действительно пытаюсь сделать свой обратный прокси-сервер «прозрачным прокси», но, похоже, это не работает с серверной частью SaaS, потому что он регистрирует IP-адрес прокси вместо IP-адреса клиента.
Вы смотрите не в том направлении:
В listen 443 ssh http2 proxy_protocol;
директива (см. Слушать) позволяет анализировать Протокол прокси о входящих соединениях. Ваш браузер не поддерживает протокол, поэтому Bad Header
ошибка. Если вы хотите увидеть минимальный пример использования протокола прокси:
openssl s_client -connect <nginx_ip>:https -crlf
и введите:
PROXY TCP4 10.0.0.1 10.0.0.1 443 443
GET / HTTP/1.1
Host: <nginx_host_name>
за которыми следуют две пустые строки.
В proxy_protocol on;
директива (см. proxy_protocol) включит протокол прокси между Nginx и сервером SaaS. Последний, однако, не поддерживает протокол прокси, как вы говорите. Вам нужно будет его реализовать.
Однако у вас есть третье решение, которое работает, если nginx находится на пути между сервером SaaS и Интернетом:
Использовать proxy_bind
директива (см. proxy_bind) сказать nginx для подмены исходного адреса (чтобы использовать адрес клиента):
proxy_bind $remote_addr transparent;
nginx может легко подделать адрес источника, но ответный пакет от сервера SaaS будет перенаправлен клиенту, а не nginx. Поэтому вам необходимо перехватывать пакеты, приходящие с сервера SaaS. Вам нужна новая таблица маршрутизации, назовем ее transparent
добавляя:
100 transparent
к /etc/iproute2/rt_tables
. Затем вам нужно принять любой адрес как локальный:
ip route add local default dev lo table transparent
наконец, вам нужно добавить правило брандмауэра, чтобы принудительно использовать таблицу маршрутизации transparent
на весь трафик, возвращаемый с сервера SaaS (предположим, что его адрес 10.10.10.10
):
iptable -t mangle -A PREROUTING -p tcp -s 10.10.10.10 --sport 80 -m socket\
--transparent -j MARK --set-mark 1
ip rule add fwmark 1 lookup transparent