IP del cliente en PHP: cómo evitar errores en 2025

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

La caza de la IP: ¿por qué $_SERVER['REMOTE_ADDR'] ya no es suficiente?

\n\n

Imagina que lanzas un proyecto educativo increíble en PHP. Todo funciona, los usuarios están contentos. Pero decides añadir registro de visitantes, geolocalización o, por ejemplo, protección contra votos fraudulentos. Y de repente — ¡pum! — descubres que la mitad de tus visitantes "únicos" tienen la misma IP: 127.0.0.1 o 10.0.0.1. ¿Te suena?

\n\n

El problema de obtener la IP real del cliente en PHP es un clásico que nunca pasa de moda. La pregunta en Stack Overflow acumula miles de visitas, y tanto principiantes como expertos siguen cayendo en los mismos errores. En 2025, con Cloudflare, AWS, Nginx y un montón de proxies CDN como estándar, confiar solo en $_SERVER['REMOTE_ADDR'] es como leer el futuro en posos de café.

\n\n

En este artículo no solo te daremos una función lista para usar. Analizaremos la anatomía de las cabeceras HTTP, aprenderemos a distinguir aliados de enemigos y crearemos un método seguro y fiable para obtener la IP del visitante en PHP que no te fallará en 2025. ¡Allá vamos!

\n\n

REMOTE_ADDR: tu fiel pero ciego compañero

\n\n

Empecemos por lo básico. $_SERVER['REMOTE_ADDR'] es la IP de quien se conecta directamente a tu servidor web. Si tu sitio está en un servidor dedicado sin proxy, esa es la IP del cliente. Simple y fiable.

\n\n

Pero en el mundo actual, esto es raro. Normalmente, entre el usuario y tu script PHP hay toda una cadena:

\n
    \n
  • CDN (Cloudflare, Fastly)
  • \n
  • Balanceador de carga (Nginx, HAProxy)
  • \n
  • Proxy inverso (Varnish, Nginx)
  • \n
  • Hosting con arquitectura compartida
  • \n
\n\n

Y aquí REMOTE_ADDR muestra la IP del último eslabón (por ejemplo, tu balanceador), no la del usuario real. Para un sitio educativo, esto es un desastre: no podrás distinguir a un estudiante de Madrid de uno de Buenos Aires, y tu sistema antispam bloqueará a todos por igual.

\n\n

Cabeceras HTTP: ¿dónde se esconde la IP real?

\n\n

Para transmitir la IP real del cliente, los servidores proxy añaden cabeceras HTTP especiales. Las más populares en 2025 son:

\n\n

1. X-Forwarded-For (XFF)

\n

La cabecera clásica. Puede contener una cadena de IPs: client_ip, proxy1_ip, proxy2_ip. La primera IP de la lista es el cliente real. Pero hay un detalle: cualquier atacante puede falsificar esta cabecera si tu infraestructura no la limpia.

\n\n

2. X-Real-IP

\n

La cabecera favorita de Nginx. Contiene solo una IP: la real. Más simple y segura, pero no todos los proxies la soportan.

\n\n

3. CF-Connecting-IP (Cloudflare)

\n

Cabecera específica de Cloudflare. Si usas su CDN, es la opción más fiable. Pero solo si confías en Cloudflare (y deberías, son excelentes).

\n\n
\n Importante: Nunca confíes en las cabeceras X-Forwarded-For y X-Real-IP de fuentes desconocidas. Un atacante puede inyectar cualquier IP y tu sistema la considerará real.\n
\n\n

Mejor práctica 2025: protección en capas

\n\n

¿Entonces qué hacemos? No podemos simplemente tomar la primera IP de X-Forwarded-For — es peligroso. Pero tampoco podemos ignorar los proxies. La solución es una lista blanca de proxies de confianza.

\n\n

La idea es simple: conocemos las IPs de nuestros balanceadores y CDN. Si la solicitud viene de ellos, confiamos en sus cabeceras. Si no, usamos REMOTE_ADDR.

\n\n

Aquí tienes una clase funcional en PHP que implementa esta lógica:

\n\n
<?php\n\nclass ClientIP\n{\n    /**\n     * Lista de IPs y subredes de confianza (CIDR).\n     * Añade aquí las IPs de tus proxies, CDN y balanceadores.\n     */\n    private static array $trustedProxies = [\n        '127.0.0.1',          // localhost\n        '10.0.0.0/8',         // redes privadas\n        '172.16.0.0/12',                

Blogs

Book Recommendations