Configurar GeoIP2 en Nginx detrás de Nginx Proxy Manager (NPM)

NPM-nginx-geoIP.png

Introducción

En este artículo quiero mostrar cómo configurar GeoIP2 en Nginx cuando el servidor web se encuentra detrás de un proxy inverso administrado mediante Nginx Proxy Manager (NPM).

El objetivo es identificar la IP real de los visitantes, conocer su país y ciudad, y posteriormente utilizar esta información para generar estadísticas o alertas de seguridad.

Arquitectura

La arquitectura utilizada es la siguiente:

Cliente → Nginx Proxy Manager (NPM) → Nginx Backend

NPM recibe las conexiones HTTPS desde Internet y las reenvía hacia un servidor Nginx interno.

Configurando la IP real del visitante

Como el servidor se encuentra detrás de Nginx Proxy Manager, inicialmente Nginx registraba la IP privada del proxy en lugar de la IP pública del visitante.

Para solucionarlo agregué al archivo /etc/nginx/sites-available/misitio dentro del bloque server {}:

set_real_ip_from 192.0.2.255;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Donde 192.0.2.255 corresponde a la IP interna de mi servidor Nginx Proxy Manager.

Posteriormente validé la configuración:

nginx -t

Y recargué el servicio:

systemctl reload nginx

Verificando la IP real del visitante

Una vez aplicada la configuración, verifiqué el contenido del log:

tail -f /var/log/nginx/access.log

Comencé a observar registros similares a:

198.51.100.0 - - [16/Jun/2026:11:19:11 -0300] "GET /favicon.ico HTTP/1.1" 200
203.0.113.0 - - [16/Jun/2026:11:20:01 -0300] "GET /api/live/matches HTTP/1.1" 304

Como aparecen direcciones IP públicas reales y no la IP privada de NPM, confirmé que el proxy estaba reenviando correctamente la información del cliente.

Instalación del módulo GeoIP2

Instalé el módulo GeoIP2 para Nginx:

apt update
apt install libnginx-mod-http-geoip2

Luego verifiqué que el módulo estuviera cargado:

nginx -T | grep load_module

Resultado:

load_module modules/ngx_http_geoip2_module.so;

Descarga de las bases GeoLite2

Registré una cuenta gratuita en MaxMind y descargué:

  • GeoLite2-Country.mmdb

  • GeoLite2-City.mmdb

Creé el directorio:

mkdir -p /etc/nginx/geoip

Y copié los archivos:

cp GeoLite2-Country.mmdb /etc/nginx/geoip/
cp GeoLite2-City.mmdb /etc/nginx/geoip/

Configuración de GeoIP2 en Nginx

Dentro del bloque http {} del archivo /etc/nginx/nginx.conf agregué:

geoip2 /etc/nginx/geoip/GeoLite2-Country.mmdb {
    auto_reload 5m;

    $geoip2_country_code country iso_code;
    $geoip2_country_name country names en;
}

geoip2 /etc/nginx/geoip/GeoLite2-City.mmdb {
    auto_reload 5m;

    $geoip2_city_name city names en;
}

Endpoint de prueba

Para validar la configuración agregué al archivo /etc/nginx/sites-available/misitio dentro del bloque server {}:

location /geoiptest {
    default_type text/plain;
    return 200 "$remote_addr | $geoip2_country_code | $geoip2_country_name | $geoip2_city_name\n";
}

Luego validé la configuración:

nginx -t
systemctl reload nginx

Al acceder a:

https://misitio.com/geoiptest

obtuve:

192.0.2.0 | UY | Uruguay | Montevideo

Lo que confirmó que GeoIP2 estaba funcionando correctamente.

Incorporando GeoIP al access.log

La configuración del formato de log debe realizarse dentro del bloque http {} del archivo:

/etc/nginx/nginx.conf

Agregué el siguiente formato personalizado:

log_format geoip '$remote_addr [$time_local] '
                 '$geoip2_country_code '
                 '$geoip2_country_name '
                 '$geoip2_city_name '
                 '"$request" $status';

Luego configuré el archivo de log para utilizar dicho formato.

Esto puede hacerse de forma global dentro del bloque http {} en /etc/nginx/nginx.conf:

access_log /var/log/nginx/access.log geoip;

o de forma específica para un sitio dentro del bloque server {} ubicado normalmente en:

/etc/nginx/sites-available/misitio

o

/etc/nginx/sites-enabled/misitio

Ejemplo:

server {

    access_log /var/log/nginx/access.log geoip;

    ...

}

Después de aplicar los cambios validé la configuración:

nginx -t

Y recargué Nginx:

systemctl reload nginx

Los registros comenzaron a verse así:

198.52.100.255 [16/Jun/2026:13:15:00 -0300] UY Uruguay Montevideo "GET / HTTP/1.1" 200

A partir de este momento cada acceso queda registrado junto con el país y la ciudad del visitante obtenidos mediante GeoIP2.

Además, si tienes varios virtual hosts detrás de NPM, probablemente te convenga definir el log_format geoip en /etc/nginx/nginx.conf (una sola vez) y luego activar access_log ... geoip; únicamente en los sitios donde quieras registrar geolocalización. Esto te da más flexibilidad para el futuro.

Conclusión

La combinación de Nginx Proxy Manager, Nginx y GeoIP2 permite obtener información geográfica de los visitantes con muy poco consumo de recursos. Esta información puede utilizarse tanto para análisis de tráfico como para mejorar la seguridad del servidor mediante sistemas de monitoreo y alertas.


¡Salud y buen blogging!
— Valerka (Montevideo, Uruguay)
¿Te gustó el post? ¿Dudas, comentarios o querés compartir tu experiencia?
Escribime a: valerkasystem@protonmail.com — ¡Siempre leo los mails y trato de responder cuando puedo!