Obtener la IP del cliente en NGINX cuando está detrás de HAProxy

Cuando un servidor está detrás de un proxy, la IP del cliente que ve el servidor es la IP del proxy. Si bien esto no afecta directamente al servicio, no es útil por varias razones como por ejemplo:

  1. En los logs no se registra la IP correcta del cliente.
  2. No es posible implementar ningún sistema, basado en IP, para limitar los ataques de fuerza bruta contra el sistema de login.
  3. Si desea usar usar algún módulo de localización geográfica como por ejemplo el módulo ngx_http_geoip_module de NIGNX.

Para lograr esto, es necesario:
1.- Usar el parámetro real_ip_header, del módulo ngx_http_realip_module de NGINX, para modificar la cabecera que contiene la IP del cliente.
2.- Configurar HAProxy para que añada la cabecera X-Forwarded-For o X-Real-IP.
3.- Configurar NGINX para que reemplace el parámetro fastcgi REMOTE_ADDR con la IP de la cabecera X-Forwarded-For o X-Real-IP.

Configurar real_ip_header en NGINX

La sintaxis del parámetro es:

1
real_ip_header field | X-Real-IP | X-Forwarded-For | proxy_protocol;

donde,

  • X-Real-IP, reemplaza la cabecera de la IP del cliente por la IP de la cabecera X-Real-IP.
  • X-Forwarded-For, reemplaza la cabecera de la IP del cliente por la IP de la cabecera X-Forwarded-For..
  • proxy_protocol, reemplaza la cabecera de la IP del cliente por la IP de la cabecera proxy_protocol, para usar esta opción es necesario que activar el parámetro proxy_protocol en la directiva listen. Más información en Module ngx_http_core_module - listen y The Proxy Protocol.

Configurar HAProxy para que añada la cabecera X-Forwarded-For o X-Real-IP

HAProxy puede aplicar acciones sobre las peticiones HTTP (capa 7) mediante la palabra clave http-request, algunas de estas acciones permiten añadir una cabecera (add-header), configurar el valor de una cabecera (set-header) o borrar una cabecera (del-header).

La principal diferencia entre add-header y set-header, es que set-header primero elimina la cabecera y después la añade con el valor indicado, esto permite garantizar que dicha cabecera no podrá ser manipulada por un usuario externo.

  • Añadir la cabecera X-Forwarded-For:
    1
    http-request set-header X-Forwarded-For %[src]

O bien mediante:

1
option forwardfor

  • Añadir la cabecera X-Client-IP:
    1
    http-request set-header X-Client-IP %[src]

O bien mediante:

1
option forwardfor header X-Client-IP

Configurar fastcgi_param REMOTE_ADDR

En el bloque donde se invoque a fastcgi_pass, es necesario añadir include fastcgi_params; y fastcgi_param REMOTE_ADDR $http_x_forwarded_for;. Ejemplo:

1
2
3
4
5
6
7
8
9
10
11
12
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param REMOTE_ADDR $http_x_forwarded_for;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass php-handler;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
}

Entradas de interés

Contenidos
  1. 1. Configurar real_ip_header en NGINX
  2. 2. Configurar HAProxy para que añada la cabecera X-Forwarded-For o X-Real-IP
  3. 3. Configurar fastcgi_param REMOTE_ADDR