Перейти к содержимому
Глоссарий 8 мин чтения 2 просмотров

PROXY Protocol

Статья объясняет, что такое PROXY Protocol, как он решает проблему потери реального IP при использовании прокси-серверов GProxy для HTTP/S и TCP.

PROXY Protocol — это сетевой протокол, предназначенный для передачи информации о реальном IP-адресе и порте клиента через прокси-сервер к бэкенд-серверу, сохраняя исходные метаданные соединения.

Что такое PROXY Protocol?

Когда клиент подключается к серверу через прокси, бэкенд-сервер видит IP-адрес прокси-сервера, а не реальный IP-адрес клиента. Это затрудняет ведение точных логов, применение IP-ориентированных правил безопасности, геолокацию и другие задачи, требующие информации об источнике соединения. PROXY Protocol решает эту проблему, инкапсулируя данные о реальном клиенте (IP-адрес, порт) и прокси-сервере (IP-адрес, порт) в специальный заголовок, который передается в начале TCP-соединения между прокси и бэкендом.

Протокол был разработан HAProxy и впоследствии стал стандартом де-факто для многих прокси-серверов и балансировщиков нагрузки, включая Nginx, Envoy, AWS ELB/NLB, Google Cloud Load Balancing и другие.

Как работает PROXY Protocol

PROXY Protocol работает путем добавления небольшого текстового (v1) или бинарного (v2) заголовка в начало каждого соединения, которое прокси-сервер устанавливает с бэкендом. Этот заголовок содержит следующую информацию:
* Версия протокола (v1 или v2).
* Тип протокола транспортного уровня (TCP4, TCP6, UDP4, UDP6).
* Реальный IP-адрес клиента (источник).
* Порт клиента (источник).
* IP-адрес прокси-сервера (назначение).
* Порт, который прокси использовал для соединения с бэкендом (назначение).

Бэкенд-сервер, поддерживающий PROXY Protocol, считывает этот заголовок, извлекает необходимую информацию и затем обрабатывает остаток соединения как обычный трафик. Если бэкенд-сервер не поддерживает PROXY Protocol, он будет интерпретировать заголовок как часть данных приложения, что приведет к ошибкам.

PROXY Protocol v1

PROXY Protocol v1 — это текстовая, человекочитаемая версия протокола. Она проще в отладке и понимании, но имеет ограничения по функциональности и производительности.

Формат PROXY Protocol v1

Заголовок v1 представляет собой одну строку текста, завершающуюся последовательностью \r\n.

Пример формата:
PROXY TCP4 192.168.0.1 192.168.0.100 1234 80\r\n

  • PROXY: Сигнатура, идентифицирующая протокол.
  • TCP4: Указывает на использование IPv4 и TCP. Допустимы также TCP6 для IPv6.
  • 192.168.0.1: IP-адрес клиента.
  • 192.168.0.100: IP-адрес прокси-сервера.
  • 1234: Исходный порт клиента.
  • 80: Порт назначения на прокси (тот, к которому подключился клиент).

Если прокси не может определить IP-адрес или порт клиента (например, из-за ошибки или если прокси не является прямым источником), он может отправить заголовок с информацией об UNKNOWN:

PROXY UNKNOWN\r\n

В этом случае бэкенд-сервер должен использовать IP-адрес и порт прокси-сервера как fallback.

Ограничения v1

  • Только TCP: Поддерживает только TCP-соединения (IPv4 и IPv6).
  • Текстовый формат: Накладывает небольшой оверхед на парсинг и увеличивает размер заголовка по сравнению с бинарным.
  • Фиксированная структура: Не поддерживает передачу дополнительной информации.

PROXY Protocol v2

PROXY Protocol v2 — это бинарная версия протокола, разработанная для повышения эффективности, расширяемости и поддержки большего числа протоколов. Она сложнее для ручной отладки, но предпочтительнее для высоконагруженных систем.

Формат PROXY Protocol v2

Заголовок v2 начинается с 12-байтовой сигнатуры \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x51\x0D\x0A\x7F, за которой следуют бинарные поля.

Основные поля заголовка v2:

  1. 12-байт сигнатура: \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x51\x0D\x0A\x7F
  2. 1-байт ver_cmd:
    • Версия (4 бита): Всегда 0x2 для v2.
    • Команда (4 бита):
      • 0x0 (LOCAL): Соединение было установлено на самом прокси-сервере. Не содержит адресной информации.
      • 0x1 (PROXY): Соединение было перенаправлено прокси-сервером. Содержит адресную информацию.
  3. 1-байт fam_prot:
    • Семейство адресов (4 бита):
      • 0x0 (UNSPEC): Неуказанное семейство (например, для LOCAL команды).
      • 0x1 (AF_INET): IPv4.
      • 0x2 (AF_INET6): IPv6.
      • 0x3 (AF_UNIX): Unix-сокеты.
    • Протокол (4 бита):
      • 0x0 (UNSPEC): Неуказанный протокол.
      • 0x1 (STREAM): TCP или UNIX_STREAM.
      • 0x2 (DGRAM): UDP или UNIX_DGRAM.
  4. 2-байта len: Общая длина (в байтах) всех последующих полей (адреса и TLV).

После этих 16 байт следуют:
* Адресная информация: Зависит от fam_prot.
* Для AF_INET (IPv4): 4 байта Source IP, 4 байта Destination IP, 2 байта Source Port, 2 байта Destination Port. (12 байт всего)
* Для AF_INET6 (IPv6): 16 байт Source IP, 16 байт Destination IP, 2 байта Source Port, 2 байта Destination Port. (36 байт всего)
* Для AF_UNIX: 108 байт Source UNIX socket path, 108 байт Destination UNIX socket path. (216 байт всего)
* TLV (Type-Length-Value): Опциональные поля, позволяющие передавать дополнительную информацию. Каждое TLV состоит из:
* Type (1 байт): Тип данных (например, PP2_TYPE_SSL, PP2_TYPE_ALPN, PP2_TYPE_AUTHORITY).
* Length (2 байта): Длина значения.
* Value (Length байт): Сами данные.

Примеры TLV:
* PP2_TYPE_SSL: Информация о SSL/TLS соединении (версия, шифр, клиентский сертификат).
* PP2_TYPE_ALPN: Протокол прикладного уровня (например, h2, http/1.1).
* PP2_TYPE_UNIQUE_ID: Уникальный идентификатор соединения.

Преимущества v2

  • Эффективность: Бинарный формат уменьшает размер заголовка и ускоряет его парсинг.
  • Расширяемость: Поддержка TLV позволяет добавлять новые типы данных без изменения основного формата.
  • Поддержка UDP и UNIX-сокетов: В отличие от v1.
  • Гибкость: Команда LOCAL позволяет прокси сообщать, что соединение не было перенаправлено.

Сравнение PROXY Protocol v1 и v2

Характеристика PROXY Protocol v1 PROXY Protocol v2
Формат Текстовый, человекочитаемый Бинарный
Поддерживаемые L3/L4 TCP4, TCP6 TCP4, TCP6, UDP4, UDP6, UNIX-сокеты
Размер заголовка Переменный, но обычно 20-30 байт Фиксированные 16 байт + размер адресной информации + TLV
Производительность Немного ниже из-за текстового парсинга Выше, благодаря бинарному формату
Расширяемость Отсутствует Присутствует через TLV (Type-Length-Value)
Отладка Проще (можно прочитать Wireshark/tcpdump) Сложнее (требует декодирования)
Случаи UNKNOWN PROXY UNKNOWN\r\n LOCAL команда (ver_cmd=0x20)
Доп. информация Нет Да, через TLV (SSL, ALPN, Unique ID и т.д.)

Реализация и конфигурация

Для использования PROXY Protocol требуется настройка как на прокси-сервере, так и на бэкенд-сервере.

Настройка прокси-сервера

Прокси-сервер должен быть сконфигурирован для добавления заголовка PROXY Protocol к исходящим соединениям.

HAProxy

В HAProxy это делается с помощью директив send-proxy (для v1) или send-proxy-v2 (для v2) в секции server или default_server.

listen http_proxy
    bind *:80
    mode tcp
    default_backend webservers

backend webservers
    mode tcp
    server web1 192.168.1.10:80 send-proxy-v2 # Отправка PROXY Protocol v2
    server web2 192.168.1.11:80 send-proxy    # Отправка PROXY Protocol v1

Nginx (stream module)

Для проксирования TCP-трафика и добавления PROXY Protocol, Nginx использует stream модуль.

stream {
    upstream backend_servers {
        server 192.168.1.10:80;
        server 192.168.1.11:80;
    }

    server {
        listen 80;
        proxy_pass backend_servers;
        proxy_protocol on; # Включает отправку PROXY Protocol v1
        # Для v2 требуются дополнительные директивы или сборка с модулем pp_v2
        # или использование `proxy_protocol v2;` в Nginx Plus / более новых версиях
    }
}

Примечание: в более новых версиях Nginx и Nginx Plus есть поддержка proxy_protocol v2;.

Envoy Proxy

Envoy по умолчанию поддерживает PROXY Protocol и может быть настроен для его использования в listener или cluster конфигурации.

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 80
    filter_chains:
    - filters:
      - name: envoy.filters.network.proxy_protocol
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.proxy_protocol.v3.ProxyProtocol
          # Если Envoy _получает_ PROXY Protocol от предыдущего прокси
      - name: envoy.filters.network.tcp_proxy
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
          stat_prefix: ingress_tcp
          cluster: service_cluster
          # Для _отправки_ PROXY Protocol к бэкенду
          proxy_protocol_config:
            version: V2 # Или V1
  clusters:
  - name: service_cluster
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 192.168.1.10
                port_value: 80

Настройка бэкенд-сервера

Бэкенд-сервер должен быть сконфигурирован для чтения заголовка PROXY Protocol и извлечения из него реального IP-адреса клиента.

Nginx (http module)

Для веб-сервера Nginx, работающего с HTTP-трафиком, нужно использовать директивы set_real_ip_from и real_ip_header в секции http, server или location.

http {
    # ...
    set_real_ip_from 192.168.1.0/24; # IP-адреса прокси-серверов
    set_real_ip_from 10.0.0.0/8;
    real_ip_header proxy_protocol; # Указывает Nginx использовать PROXY Protocol
    # real_ip_recursive on; # Если есть несколько прокси
    # ...

    server {
        listen 80 proxy_protocol; # Включает PROXY Protocol для этого сервера
        # ...
    }
}

Директива listen 80 proxy_protocol; указывает Nginx ожидать PROXY Protocol заголовок на порту 80. Если заголовок отсутствует, соединение будет отклонено.

Apache HTTP Server

Apache может обрабатывать PROXY Protocol с помощью модуля mod_remoteip.

<IfModule mod_remoteip.c>
    RemoteIPProxyProtocol On
    RemoteIPHeader X-Forwarded-For # Или другой заголовок, если требуется
    RemoteIPInternalProxy 192.168.1.0/24 # IP-адреса ваших прокси
    RemoteIPInternalProxy 10.0.0.0/8
</IfModule>

RemoteIPProxyProtocol On активирует поддержку PROXY Protocol.

Другие приложения и фреймворки

Если ваше приложение не использует веб-сервер, который поддерживает PROXY Protocol напрямую (например, если это кастомный TCP-сервер), вам потребуется реализовать парсинг заголовка PROXY Protocol в коде вашего приложения. Библиотеки для парсинга PROXY Protocol доступны для большинства языков программирования.

Пример псевдокода для парсинга v1:

function parse_proxy_protocol_v1(socket_stream):
    first_line = read_line_from_stream(socket_stream)
    if starts_with(first_line, "PROXY"):
        parts = split(first_line, " ")
        if len(parts) == 6:
            protocol = parts[1]
            client_ip = parts[2]
            proxy_ip = parts[3]
            client_port = parts[4]
            proxy_port = parts[5]
            # Используйте client_ip и client_port
        else if parts[1] == "UNKNOWN":
            # Используйте IP и порт сокета, так как клиентский IP неизвестен
        else:
            # Ошибка парсинга, закрыть соединение или использовать IP сокета
    else:
        # Это не PROXY Protocol, обработать как обычное соединение

Сценарии использования и преимущества

  • Точное логирование: Веб-серверы и приложения могут записывать в логи реальные IP-адреса клиентов, что критично для аналитики и аудита.
  • Безопасность: Применение IP-ориентированных правил безопасности (брандмауэры, WAF, списки доступа) становится возможным на уровне бэкенд-сервера.
  • Геолокация: Точное определение географического положения пользователя для персонализации контента или региональных ограничений.
  • Ограничение частоты запросов (Rate Limiting): Применение лимитов на основе реального IP-адреса клиента.
  • Балансировка нагрузки: Сохранение информации о клиенте может использоваться для более интеллектуальных алгоритмов балансировки нагрузки, например, для "липких сессий" (session stickiness).
  • SSL/TLS Offloading: Если SSL-терминирование происходит на прокси, PROXY Protocol v2 может передавать информацию о параметрах SSL-соединения (версия, шифр, сертификат клиента) бэкенду.

Рекомендации и лучшие практики

  • Доверие к источникам: PROXY Protocol должен приниматься только от доверенных прокси-серверов. Несанкционированный источник может подделать заголовок PROXY Protocol, что приведет к ложной информации о клиенте. Настройте бэкенд-серверы так, чтобы они принимали PROXY Protocol только от IP-адресов ваших прокси.
  • Совместимость: Убедитесь, что и прокси, и бэкенд-сервер поддерживают выбранную версию PROXY Protocol. Несоответствие версий или отсутствие поддержки приведет к ошибкам соединения.
  • Фаерволы и ACL: Убедитесь, что правила фаервола между прокси и бэкендом разрешают трафик.
  • Тестирование: Всегда тщательно тестируйте конфигурацию PROXY Protocol в тестовой среде перед внедрением в продакшн.
  • Мониторинг: Отслеживайте логи бэкенд-серверов на предмет ошибок, связанных с PROXY Protocol, чтобы оперативно выявлять проблемы.
  • Выбор версии: В новых развертываниях предпочтительнее использовать PROXY Protocol v2 из-за его эффективности, расширяемости и поддержки UDP. v1 может быть оправдан для простых случаев или обратной совместимости.
Обновлено: 03.03.2026
Назад к категории

Попробуйте наши прокси

20,000+ прокси в 100+ странах мира