В процессе организации отказоустойчивого решения для WWW сервисов возникла проблема проброса реальных IP адресов на WWW сервисы, находящиеся за балансировщиком нагрузки. Понятно, что делается это через HTTP заголовки, например, X-FORWARDED-FOR. Но в моей схеме есть нюансы.
Итак, обо всем по порядку.
Описание
Очень упрощенно схема выглядит следующим образом:
В качестве балансировщика нагрузки выступает «черный ящик», который записывает реальный IP адрес в HTTP заголовок X-FORWADED-FOR. От этого и буду отталкиваться.
Связка NGINX — Apache уже настроена и работает, отмечу только изменения.
NGINX
Сначала сделаю логирование реального IP у nginx.
Для этого в /etc/nginx/nginx.conf
в секции логирования вношу следующие изменения:
- log_format common '$remote_addr - - [$time_local - $upstream_response_time] "$request" $status $bytes_sent "$http_referer" "$http_user_agent" $msec'; + log_format common '$http_x_forwarded_for - - [$time_local - $upstream_response_time] "$request" $status $bytes_sent "$http_referer" "$http_user_agent" $msec';
Затем нужно организовать передачу реального IP далее на Apache. Для этого в секции проксирования вношу следующие изменения:
- proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Real-IP $http_x_forwarded_for;
Apache
Затем в в описание формата лога Apache следующие изменения:
- LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%{X-Real-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
В итоге в логах как Apache, так и NGINX появляются реальные IP адреса вместо адреса балансировщика.
Post Scriptum
Стоит отметить, что если в HTTP запросе не указан X-FORWARD-FOR, то запрос прошел не через балансировщик, и как следствие в логах записи о его IP не будет. Предполагаю, что для исправления этого недостатка в конфиги нужно добавить проверку на наличие в HTTP headers X-FORWARDED-FOR. Мне рабираться смысла не было.. Но если кто подскажет решение — буду рад.
Кроме логирования запросов преследовались и другие цели, а именно заставить нормально работать приложение с GEOIP сервисом. Проблема была в том, что сервису для проверки посетителя передавался локальный адрес балансировщика. Разработчики вместо REMOTE_ADD стали передавать X-REAL-IP и все встало на свои места.