Выберите продукт

Apache mod_remoteip: real IP клиента за reverse proxy без поломки логов

Когда Apache работает за reverse proxy, в логах и REMOTE_ADDR часто виден IP прокси, а не клиента. Разберём mod_remoteip: какой RemoteIPHeader выбрать, как задать trusted proxies, проверить результат и избежать подмены real IP через X-Forwarded-For.
Apache mod_remoteip: real IP клиента за reverse proxy без поломки логов

Зачем нужен mod_remoteip и почему «реальный IP» пропадает

Типичный сценарий: сайт работает за reverse proxy (Nginx/HAProxy, балансировщик, CDN, WAF), а на бэкенде Apache в логах и в переменной REMOTE_ADDR вы видите один и тот же адрес — IP прокси. Это нормально: для Apache TCP-соединение приходит именно от прокси.

Проблема начинается дальше: защита по IP (allowlist/denylist), антифрод, rate-limit на уровне приложения, гео-логика, аудит и расследования опираются на адрес клиента. Если вместо клиента везде «адрес прокси», вы теряете смысл этих механизмов.

mod_remoteip решает задачу штатно: он заменяет «адрес клиента» в Apache на значение из заголовка, который добавляет доверенный прокси. В результате:

  • в access log появляется real IP клиента;
  • в приложении/CGI корректно заполняется REMOTE_ADDR;
  • правила, завязанные на IP, начинают работать ожидаемо.

Главное правило безопасности: доверяем не заголовку, а прокси

Заголовок X-Forwarded-For клиент может подделать сам. Если Apache «верит» ему без ограничений, злоумышленник легко подменит IP на любой (включая 127.0.0.1 или адрес из вашей allowlist).

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

Поэтому настройка всегда состоит из двух частей: выбираем RemoteIPHeader и одновременно задаём trusted proxies через RemoteIPTrustedProxy (или список/диапазоны). Без trusted proxies конфигурация почти всегда уязвима.

Схема прохождения запроса через reverse proxy к Apache с заголовком X-Forwarded-For

Как работает цепочка X-Forwarded-For

В большинстве прокси по умолчанию X-Forwarded-For содержит список адресов через запятую. Слева — исходный клиент, дальше — прокси по пути. Пример:

X-Forwarded-For: 203.0.113.10, 198.51.100.23, 192.0.2.5

Смысл такой: клиент 203.0.113.10 пришёл на прокси 198.51.100.23, тот — на следующий 192.0.2.5, а уже он подключился к Apache.

mod_remoteip «разматывает» цепочку справа налево, отбрасывает доверенные прокси и выбирает первый недоверенный адрес как IP клиента. Это обычно надёжнее, чем вручную парсить заголовки в приложении.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Включение модуля mod_remoteip

Debian/Ubuntu

sudo a2enmod remoteip
sudo systemctl reload apache2

RHEL/AlmaLinux/Rocky

Обычно модуль доступен в составе пакета httpd. Проверить загрузку можно так:

sudo httpd -M | grep -i remoteip

Если в выводе есть remoteip_module — модуль активен. Если нет, проверьте установленные пакеты и конфигурацию подключаемых модулей.

Базовая настройка: RemoteIPHeader и trusted proxies

Минимально безопасная конфигурация:

  • указываем заголовок, где прокси передаёт адрес клиента (RemoteIPHeader);
  • перечисляем доверенные прокси, которые имеют право задавать этот заголовок (RemoteIPTrustedProxy или список подсетей).

Чаще всего используют X-Forwarded-For. Пример (добавьте в нужный контекст: глобально, в VirtualHost или отдельный include-файл):

RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 192.0.2.10
RemoteIPTrustedProxy 192.0.2.11
RemoteIPTrustedProxy 198.51.100.0/24

Если фронтенд-прокси на той же машине (Apache слушает 127.0.0.1, а Nginx проксирует локально), доверенным прокси будет loopback (и, при необходимости, IPv6):

RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 127.0.0.1
RemoteIPTrustedProxy ::1

Отдельно проверьте сетевую архитектуру: если между вашим «последним прокси» и Apache есть ещё один балансировщик, именно он будет источником подключения, и его адрес тоже должен быть в trusted.

RemoteIPHeader vs Forwarded: что выбрать

Кроме X-Forwarded-For существует стандартизированный заголовок Forwarded (RFC 7239). Он удобен структурой, но на практике чаще встречается именно X-Forwarded-For, а в длинных цепочках легко получить смешанную картину (часть узлов пишет одно, часть — другое).

Рекомендация по эксплуатации:

  • если у вас один контролируемый прокси (Nginx/HAProxy) — используйте X-Forwarded-For и явно настройте его формирование на прокси;
  • если цепочка сложная и вы уверены, что все узлы корректно формируют Forwarded, можно рассмотреть RemoteIPHeader Forwarded, но обязательно тестируйте на реальном трафике;
  • в смешанных схемах часто проще нормализовать всё в один заголовок на последнем прокси перед Apache.

Если хотите глубже разобраться в общей гигиене заголовков на фронтенде (не только IP), пригодится материал про настройку HTTP security headers в Nginx и Apache.

Как убедиться, что Apache действительно видит real IP

Проверка удобна в три шага: (1) какой IP приходит на сокет, (2) какие заголовки видит Apache, (3) что ушло в лог после обработки mod_remoteip.

1) Проверяем, что Apache получает соединение от прокси

sudo ss -tnp | grep ':80 '
sudo ss -tnp | grep ':443 '

В ESTAB-сессиях вы увидите адрес прокси (или 127.0.0.1), это ожидаемо.

2) Проверяем, что прокси вообще передаёт X-Forwarded-For

Самый быстрый путь — временно залогировать заголовок (см. следующий раздел). Важно: mod_remoteip не «придумает» IP — он использует то, что реально пришло от доверенного узла.

3) Проверяем access log

После включения mod_remoteip стандартный %h (адрес клиента) начнёт показывать итоговый адрес, вычисленный модулем. Это и есть критерий, что настройка работает.

Логи: как записать и real IP, и цепочку прокси

Для расследований полезно хранить две сущности одновременно:

  • итоговый адрес клиента по мнению Apache (после mod_remoteip);
  • оригинальную цепочку из X-Forwarded-For (как прислал прокси), чтобы видеть маршрут и быстро ловить аномалии.

Пример формата для Apache (обратите внимание: это конфиг, а не HTML):

LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" xff=\"%{X-Forwarded-For}i\"" vhost_with_xff
CustomLog logs/access_log vhost_with_xff

Здесь %h — уже «исправленный» адрес клиента, а %{X-Forwarded-For}i — значение заголовка как есть.

Если формат хотите подключать внутри виртуального хоста, используйте блок как текст (угловые скобки экранируем):

<VirtualHost *:80>
    ServerName example.test
    LogFormat "%h %l %u %t \"%r\" %>s %b xff=\"%{X-Forwarded-For}i\"" vhost_with_xff
    CustomLog logs/example-access.log vhost_with_xff
</VirtualHost>

Пример настройки LogFormat в Apache для записи real IP и X-Forwarded-For

Типовые ошибки и как их быстро диагностировать

Ошибка 1: «Включил RemoteIPHeader, но IP не меняется»

Чаще всего причины такие:

  • прокси не отправляет X-Forwarded-For (или отправляет другой заголовок);
  • не настроены trusted proxies, и модуль игнорирует заголовок;
  • между прокси и Apache появился ещё один узел (балансировщик/маршрутизатор), и trusted-адрес указан не тот;
  • на фронтенде заголовок затирается (overwrite), а не дополняется (append), из-за чего теряется исходный клиент.

Диагностика: временно добавьте в лог xff=\"%{X-Forwarded-For}i\" и сравните с тем, что стало в %h. Если xff пустой — проблема на прокси. Если xff есть, но %h не меняется — почти всегда вопрос в trusted proxies или в том, что директивы применились не в том контексте.

Ошибка 2: «В логах появился странный IP, которого точно нет»

Это классический симптом доверия к заголовку без ограничений. Проверьте, что у вас задан RemoteIPTrustedProxy и что он не слишком широк. Делать trusted для 0.0.0.0/0 нельзя.

Также помните про NAT и корпоративные сети: «реальный» IP может оказаться публичным адресом организации или адресом внешнего провайдера, а не конкретной рабочей станции — это нормально и объяснимо.

Ошибка 3: «Сломались allowlist/denylist и ограничения по IP»

После включения mod_remoteip Apache начинает использовать новый адрес как «адрес клиента» для многих механизмов. Если раньше вы разрешали доступ по IP прокси, теперь правила нужно пересмотреть.

Практический подход: админские зоны и технические endpoint’ы лучше ограничивать на уровне фронтенд-прокси, а на Apache минимизировать шанс прямого доступа извне (чтобы не смешивать прямые и проксированные запросы).

Сложные схемы: несколько прокси и CDN перед вашим reverse proxy

Если перед вашим Nginx/HAProxy стоит CDN или внешний балансировщик, цепочка становится длиннее. Подход всё равно тот же: доверяем только тем прокси, которые контролируем (или чьи адреса гарантированно принадлежат вашему провайдеру/платформе и документированы).

На практике чаще всего проще так:

  • на последнем прокси перед Apache нормализовать заголовок и передавать дальше предсказуемо;
  • в Apache доверять только этому последнему прокси (или их кластеру);
  • в лог писать и %h, и X-Forwarded-For, чтобы видеть всю цепочку.

Так вы уменьшаете поверхность ошибок: Apache «разговаривает» только с вашим trusted reverse proxy, а всё внешнее остаётся на границе.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Практический чек-лист перед продом

  1. Убедитесь, что прямого доступа к Apache снаружи нет (или он минимизирован): иначе клиент может обойти прокси и вы получите смесь прямых и проксированных запросов в одном виртуальном хосте.

  2. Проверьте, что прокси всегда добавляет X-Forwarded-For корректно (дописывает цепочку, а не затирает), и отдельно передаёт X-Forwarded-Proto при HTTPS-терминации (важно для приложений).

  3. Настройте RemoteIPTrustedProxy максимально узко: только реальные IP/подсети ваших прокси.

  4. Обновите формат логов, чтобы фиксировать и итоговый IP, и исходный X-Forwarded-For.

  5. Проверьте правила доступа и лимиты, завязанные на IP — поведение могло измениться после «исправления» адреса клиента.

  6. Сделайте тестовый запрос и сравните: что пришло в заголовке, что записалось в access log, что видит приложение как REMOTE_ADDR.

Что в итоге

mod_remoteip — правильный способ вернуть real IP клиента за reverse proxy и привести в порядок логи. Ключ к безопасной настройке — не просто включить RemoteIPHeader, а строго определить trusted proxies. Иначе вы рискуете подменой IP и некорректными решениями в безопасности и аналитике.

Если Apache размещён на сервере/VM, где вы сами контролируете сетевую часть, под такие задачи удобно выделять отдельный VDS: проще изолировать фронтенд и бэкенд, закрыть прямой доступ к Apache и предсказуемо управлять цепочкой прокси.

Поделиться статьей

Вам будет интересно

SSH зависает на Connecting и banner exchange: диагностика MTU, DNS, GSSAPI и KEX OpenAI Статья написана AI (GPT 5)

SSH зависает на Connecting и banner exchange: диагностика MTU, DNS, GSSAPI и KEX

Если SSH зависает на Connecting или banner exchange, причина обычно в конкретном шаге: проблемы TCP/фильтрации, MTU/PMTUD, задержк ...
TLS 1.3 и HTTP/2: что видно в ClientHello/ServerHello и как разбирать ошибки рукопожатия OpenAI Статья написана AI (GPT 5)

TLS 1.3 и HTTP/2: что видно в ClientHello/ServerHello и как разбирать ошибки рукопожатия

Практический разбор TLS 1.3 на уровне ClientHello/ServerHello: где увидеть SNI и ALPN, как сервер выбирает HTTP/2, почему возникае ...
Git bisect: как найти «плохой» коммит и быстро остановить regression OpenAI Статья написана AI (GPT 5)

Git bisect: как найти «плохой» коммит и быстро остановить regression

Регрессия в проекте — это часы на угадывание «кто сломал». Git bisect делает бинарный поиск по истории и находит bad commit за 8–1 ...