Как передать в логи web-сервера виртуалки (ВМ) реальный IP адрес посетителя

virtualbox real_ip gateway apache nginx hosting redirect mod_rpaf rpaf

Для конкретики схема такова:
- Внешний IP-адрес хост-машины: 144.76.100.244
- Внутренний IP-адрес хост-машины: 192.168.17.1
- Внутренний IP-адрес гостевой машины (виртуалки): 192.168.17.18

На корневой хост-машине установлен nginx, который выступает в роли шлюза входящих извне http-запросов.
Т.к. для web-хостинга используются разные версии OC, apache, php и т.п., то сайты раскиданы по различным ВМ.
Нельзя просто сделать проброс 80-го порта в ВМ, т.к. их несколько.
Nginx работает в режиме proxy и просто перенаправляет по имени домена все запросы в нужную ВМ.

Здесь вкратце описано, как это сделать.

1. На хост-машине

Настройка nginx

Надо добавить в секцию http файла /etc/nginx/nginx.conf:

proxy_cache_key $scheme$proxy_host$request_uri;
include /etc/nginx/proxy.conf;

Файл /etc/nginx/proxy.conf

proxy_redirect off;
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_connect_timeout    90;
client_max_body_size 100m;
client_body_buffer_size    128k;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 32k;
proxy_buffers 32 16k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;

Пример рабочей конфигурации /etc/nginx/nginx.conf

user www-data;
worker_processes 4;
pid /var/run/nginx.pid;

events {
    worker_connections 768;
    # multi_accept on;
}

http {

    ##
    # Basic Settings
    ##

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 60;
    types_hash_max_size 2048;

    proxy_cache_key $scheme$proxy_host$request_uri;
    fastcgi_ignore_client_abort on;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;
    gzip_disable "msie6";

    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
    include /etc/nginx/proxy.conf;
}

Пример записи виртуального хоста /etc/nginx/sites-available/aizaro.ru

# Redirect to VM
server {
    listen 80; 
    server_name aizaro.ru;
    server_name www.aizaro.ru;
    access_log /data/www/logs/aizaro.ru.log;
    location / {
    proxy_pass http://192.168.17.18:82;
    }
}

Apache

Если в качестве прокси-сервера используется apache, то для того, чтобы в логах apache на виртуалке был виден реальный IP адрес надо установить модуль mod_rpaf.
Теперь рассмотрим варианты установки модуля rpaf для разных ОС.

Для FreeBSD

Ставим из портов /usr/ports/www/mod_rpaf2
В /usr/local/etc/apache24/httpd.conf добавляем строки:

...
LoadModule rpaf_module        libexec/apache24/mod_rpaf2.so
...
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
...
# Rpaf module
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 192.168.17.1
RPAFheader X-Real-IP
RPAFheader X-Forwarded-For

Перезапускаем apache, и все заработает.

Для Ubuntu

apt-get install libapache2-mod-rpaf
a2enmod rpaf
a2enmod proxy

Открываем конфиг-файл /etc/apache2/mods-enabled/rpaf.conf

Корректируем строку: RPAFproxy_ips 127.0.0.1, заменяя 127.0.0.1 на внутренний IP-адрес хост-машины.
Этот IP можно посмотреть в логах apache2 - он там прописывается вместо реального IP-адреса посетителя.

В нашем примере будет так: 

# Rpaf module
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 192.168.17.1 ::1
RPAFheader X-Real-IP
RPAFheader X-Forwarded-For

Перезапускаем: /etc/init.d/apache2 restart

2. На гостевой ВМ

Настройка трансляции реального IP адреса внутрь ВМ на гостевой ВМ.
Сначала надо поправить формат лога в конфигурации apache.
В файле apache2.conf (Ubuntu) или httpd.conf (FreeBSD) надо добавить тип лога для виртуалки vhost_combined (или поправить тип лога combined, если вам так больше нравится).
Различие во втором параметре:

LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined

Кроме того, надо указать тип лога vhost_combined в файле описания виртуального хоста на ВМ.

3. Дополнение

Если на приемной ВМ стоит второй nginx

http {
.....
  log_format vhosts '$host $proxy_add_x_forwarded_for - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';

  access_log /var/log/nginx/access.log vhosts;
  error_log /var/log/nginx/error.log vhosts;
.....
EOF