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

Протокол прокси с обратным прокси Nginx

Обзор

У меня есть установка обратного прокси-сервера 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-адреса клиента.

Вы смотрите не в том направлении:

  1. В 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>
    

    за которыми следуют две пустые строки.

  2. В proxy_protocol on; директива (см. proxy_protocol) включит протокол прокси между Nginx и сервером SaaS. Последний, однако, не поддерживает протокол прокси, как вы говорите. Вам нужно будет его реализовать.

Однако у вас есть третье решение, которое работает, если nginx находится на пути между сервером SaaS и Интернетом:

  1. Использовать proxy_bind директива (см. proxy_bind) сказать nginx для подмены исходного адреса (чтобы использовать адрес клиента):

    proxy_bind $remote_addr transparent;
    
  2. 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