Qué hace realmente un reverse proxy con tu IP
El reverse proxy hace que los visitantes solo vean la IP del proxy, pero el servidor backend sigue teniendo su propia IP pública y sigue aceptando conexiones de cualquiera que la conozca. Si alguien descubre esa dirección, se conecta directo y el proxy queda de adorno: sin filtrado, sin límites de tasa, sin nada.
Las formas habituales en que se filtra la IP de un backend supuestamente oculto son conocidas y no requieren gran habilidad:
- Historial de DNS. Antes de poner el proxy, tu dominio apuntaba directo al servidor. Numerosos servicios archivan registros DNS históricos y esa IP anterior sigue ahí.
- Registros de Certificate Transparency. Si el backend emitió alguna vez su propio certificado, el dominio o subdominio asociado figura en registros públicos y auditables.
- Correo saliente. Las cabeceras
Receivedde los correos que envía tu aplicación revelan la IP del servidor que los originó. - Subdominios olvidados. Un
mail.tudominio.como undev.tudominio.comapuntando directo al backend anula todo el esfuerzo. - Mensajes de error y cabeceras. Trazas de excepción, páginas de error de PHP o cabeceras que devuelven direcciones internas.
La conclusión práctica: el ocultamiento no es un secreto, es una regla de firewall. El backend debe rechazar cualquier conexión que no venga de la IP del proxy. Con esa regla, que alguien conozca la dirección deja de importar.
Qué necesitas antes de empezar
- Dos servidores: uno actuará como reverse proxy y otro como backend. Pueden ser dos VPS del mismo proveedor o de proveedores distintos.
- Acceso SSH con permisos de
sudoen ambos. - Un dominio con registro A apuntando a la IP del proxy, no a la del backend.
- Conectividad entre ambos, idealmente por una red privada si el proveedor la ofrece.
Un apunte importante sobre la topología: si configuras Nginx con proxy_pass http://127.0.0.1:8080, el proxy y la aplicación están en la misma máquina. Eso es perfectamente válido y aporta TLS, caché, compresión y filtrado, pero no oculta ninguna IP, porque solo hay una. Para ocultar el backend hacen falta dos servidores separados.
Ventajas de usar un reverse proxy
Un reverse proxy aporta cuatro beneficios concretos que se obtienen con una sola pieza de infraestructura, y solo el primero depende de tener dos servidores separados.
| Beneficio | Qué resuelve | Requiere backend separado |
|---|---|---|
| Ocultar el backend | Los ataques directos no encuentran destino | Sí, más regla de firewall |
| Filtrado y rate limiting | Fuerza bruta, scraping, bots | No |
| Terminación TLS centralizada | Un solo certificado que renovar, backends sin TLS | No |
| Balanceo de carga | Reparte tráfico y tolera caídas | Sí, dos o más backends |
| Caché de contenido estático | Reduce peticiones que llegan a la aplicación | No |
Paso 1: Instalar Nginx en el servidor proxy
Nginx está en los repositorios oficiales de todas las distribuciones principales y arranca funcionando con una página por defecto.
En Debian y Ubuntu:
sudo apt update
sudo apt install nginx -y
sudo systemctl enable --now nginx En AlmaLinux, Rocky Linux o RHEL 9 y 10:
sudo dnf install nginx -y
sudo systemctl enable --now nginx En las distribuciones Red Hat actuales el gestor de paquetes es dnf; yum sigue funcionando como alias por compatibilidad, pero es el gestor de CentOS 7, que llegó a fin de vida el 30 de junio de 2024.
Paso 2: Configurar el proxy hacia el backend
El bloque server recibe el tráfico del dominio y lo reenvía a la IP del servidor backend, añadiendo las cabeceras que le informan de quién es el visitante real. Sin esas cabeceras, tu aplicación registrará todas las visitas como si vinieran del proxy, lo que rompe los logs, la analítica y cualquier límite por IP.
sudo nano /etc/nginx/sites-available/mi_sitio server {
listen 80;
server_name tu-dominio.com;
location / {
proxy_pass http://10.0.0.20:8080; # IP privada del backend
proxy_http_version 1.1;
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_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 10s;
proxy_read_timeout 60s;
}
} Activa el sitio, comprueba la sintaxis y recarga:
sudo ln -s /etc/nginx/sites-available/mi_sitio /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx Usa reload en vez de restart: aplica la configuración sin cortar las conexiones en curso. Y no te saltes nginx -t: si haces restart con un error de sintaxis, Nginx no arranca y el sitio queda caído; con reload, rechaza el cambio y sigue sirviendo la configuración anterior.
Paso 3: Cerrar el backend al resto de internet
Este es el paso que convierte el proxy en protección real, y el que casi todas las guías omiten. El servidor backend debe aceptar conexiones al puerto de la aplicación únicamente desde la IP del proxy.
En el servidor backend, con UFW:
sudo ufw allow OpenSSH
sudo ufw allow from 10.0.0.10 to any port 8080 proto tcp # solo el proxy
sudo ufw default deny incoming
sudo ufw enable
sudo ufw status numbered Con Firewalld, en AlmaLinux o Rocky Linux:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.10" port port="8080" protocol="tcp" accept'
sudo firewall-cmd --reload Y refuerza el cierre en la propia aplicación, haciendo que escuche solo en la interfaz privada en lugar de en todas:
# En el Nginx del backend, si lo hay
listen 10.0.0.20:8080; Recuerda permitir SSH antes de activar el firewall, o perderás el acceso al servidor. Desarrollamos el procedimiento seguro y cómo recuperarte en la guía de firewalls en Linux.
Para verificar que el cierre funcionó, intenta conectarte al backend desde una máquina cualquiera:
curl -m 5 http://ip_publica_del_backend:8080 Debe agotar el tiempo de espera o rechazar la conexión. Si responde, la regla no está haciendo efecto y el backend sigue expuesto.
Paso 4: Habilitar HTTPS con Let's Encrypt
Con un reverse proxy, el certificado se instala en el proxy y no en el backend: es el proxy quien habla TLS con los visitantes. Esto simplifica la gestión, porque hay un solo certificado que renovar aunque tengas cinco backends detrás.
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d tu-dominio.com Certbot modifica tu bloque server para escuchar en el 443, añade la redirección desde HTTP y deja programada la renovación automática con un temporizador de systemd. No añadas una tarea de cron a mano: es redundante y puede provocar renovaciones simultáneas.
systemctl list-timers | grep certbot
sudo certbot renew --dry-run La automatización deja de ser opcional a corto plazo: Let's Encrypt está reduciendo la vida de sus certificados. El perfil clásico sigue en 90 días, el perfil tlsserver pasó a 45 días el 13 de mayo de 2026, el clásico bajará a 64 días el 10 de febrero de 2027 y la meta son 45 días en 2028.
Un detalle de la comunicación interna: si el proxy habla con el backend por HTTP en claro dentro de una red privada del proveedor, el riesgo es bajo y la configuración es sencilla. Si viajan por internet público, cifra también ese tramo con proxy_pass https://....
Paso 5: Filtrar tráfico por IP
Nginx permite permitir o denegar direcciones concretas dentro de un bloque location, y el orden de las directivas determina el resultado. Nginx evalúa allow y deny de arriba abajo y aplica la primera coincidencia.
Para bloquear IPs concretas y dejar pasar al resto:
location / {
deny 203.0.113.45;
deny 198.51.100.0/24;
allow all;
proxy_pass http://10.0.0.20:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
} Para restringir un panel de administración solo a tu oficina:
location /admin {
allow 190.0.0.0/24;
deny all;
proxy_pass http://10.0.0.20:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
} Ten cuidado con deny all en el location / principal: bloquea a todos los visitantes salvo los rangos que hayas permitido explícitamente antes. Es lo que quieres en /admin y casi nunca lo que quieres en la raíz del sitio.
Mantener listas de IPs a mano no escala: para bloqueo dinámico basado en comportamiento, la herramienta adecuada es Fail2Ban leyendo los logs de Nginx, que bloquea automáticamente a quien muestre patrones de ataque.
Paso 6: Limitar la tasa de peticiones
El rate limiting frena fuerza bruta y scraping limitando cuántas peticiones por segundo acepta Nginx de cada IP. La zona se declara en el bloque http de /etc/nginx/nginx.conf y se aplica donde la necesites.
http {
# 10 MB de memoria guardan el estado de unas 160.000 direcciones IP
limit_req_zone $binary_remote_addr zone=general:10m rate=20r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=2r/s;
limit_req_status 429;
} Y en el sitio:
location / {
limit_req zone=general burst=40 nodelay;
proxy_pass http://10.0.0.20:8080;
}
location /login {
limit_req zone=login burst=5;
proxy_pass http://10.0.0.20:8080;
} Qué significa cada parámetro, porque la combinación no es intuitiva:
-
rate=20r/s: la tasa media permitida por IP. Nginx la aplica por milisegundos, no por segundos completos. -
burst=40: cuántas peticiones extra se encolan antes de empezar a rechazar. Sinburst, una página con 30 recursos dispararía el límite al cargar. -
nodelay: sirve las peticiones en ráfaga de inmediato en lugar de espaciarlas. Sin él, el sitio se siente lento aunque no se rechace nada. -
limit_req_status 429: devuelve «Too Many Requests», el código correcto, en lugar del 503 por defecto que sugiere que el servidor está caído.
El límite de /login es deliberadamente más estricto: dos peticiones por segundo son de sobra para una persona e insuficientes para un ataque de diccionario.
Paso 7: Balanceo de carga entre varios backends
Un bloque upstream con dos o más servidores reparte el tráfico entre ellos y deja de enviar peticiones a los que fallan. Es el mismo mecanismo del proxy simple, con una lista en lugar de un destino único.
upstream backend {
least_conn;
server 10.0.0.20:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.21:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.22:8080 backup;
}
server {
listen 80;
server_name tu-dominio.com;
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout http_502 http_503;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
} Los algoritmos disponibles y cuándo usar cada uno:
| Algoritmo | Cómo reparte | Cuándo conviene |
|---|---|---|
| Round-robin (por defecto) | Secuencialmente entre todos | Backends idénticos y peticiones homogéneas |
least_conn | Al que tenga menos conexiones activas | Peticiones de duración muy variable |
ip_hash | Cada IP siempre al mismo backend | Sesiones guardadas en memoria del backend |
weight=N | Proporcional al peso asignado | Servidores de distinta capacidad |
max_fails=3 fail_timeout=30s significa que tras tres fallos en 30 segundos el servidor se considera caído y queda fuera de rotación durante otros 30. El servidor marcado como backup solo recibe tráfico cuando todos los demás están fuera. Conviene saber que Nginx de código abierto detecta los fallos de forma pasiva, cuando una petición real falla; las comprobaciones activas de salud son una función de Nginx Plus, la versión comercial. Si necesitas comprobaciones activas sin licencia, HAProxy las incluye en su versión libre.
Paso 8: Añadir un WAF (opcional)
Un WAF (Web Application Firewall) inspecciona el contenido de cada petición HTTP y bloquea patrones de ataque conocidos como inyección SQL o cross-site scripting. Es una capa adicional, no un sustituto de escribir código seguro.
En Debian y Ubuntu, el módulo dinámico de ModSecurity para Nginx se instala con:
sudo apt install libnginx-mod-http-modsecurity -y El paquete instala el módulo pero no lo activa; hay que cargarlo y apuntarlo a un archivo de reglas. Lo que realmente aporta protección no es el motor, sino el conjunto de reglas: el OWASP Core Rule Set (CRS), que hay que descargar y ajustar aparte.
Antes de instalarlo, ten en cuenta dos cosas honestas sobre el estado del proyecto y sobre su coste operativo:
- ModSecurity pasó a la OWASP Foundation en enero de 2024, cuando Trustwave transfirió el proyecto, y su patrocinio comercial terminó en julio de ese mismo año. Sigue recibiendo parches de seguridad, pero el ritmo de desarrollo de nuevas funciones es menor. La alternativa moderna es Coraza, una reimplementación en Go también bajo el paraguas de OWASP, compatible con el lenguaje de reglas SecLang y con el mismo Core Rule Set.
- Un WAF mal calibrado genera falsos positivos que bloquean a usuarios legítimos. Actívalo primero en modo de solo detección (
SecRuleEngine DetectionOnly), revisa el log durante una o dos semanas y solo después pásalo a bloqueo.
Si tu aplicación es pequeña y bien mantenida, el orden de prioridades es actualizaciones al día, contraseñas fuertes, rate limiting y Fail2Ban. El WAF viene después, no antes.
Reverse proxy, CDN, firewall y WAF: qué hace cada uno
Son cuatro capas distintas que suelen confundirse porque todas «protegen el servidor», pero actúan en momentos diferentes de la conexión.
| Herramienta | Dónde actúa | Qué decide | Qué no hace |
|---|---|---|---|
| Firewall (UFW, Firewalld) | Red, antes de la aplicación | Qué IPs y puertos pueden conectar | No entiende HTTP ni URLs |
| Reverse proxy (Nginx) | Capa HTTP, en tu infraestructura | A qué backend va cada petición | No absorbe ataques volumétricos |
| CDN con proxy (Cloudflare y otros) | Red del proveedor, antes de llegar a ti | Filtra y cachea en el borde | Depende de un tercero; puede filtrar datos si se configura mal |
| WAF (ModSecurity, Coraza) | Contenido de cada petición | Si el payload parece un ataque | No arregla código vulnerable |
Un matiz sobre DDoS que conviene tener claro: ni el reverse proxy ni el firewall del servidor detienen un ataque volumétrico, porque el tráfico ya consumió tu ancho de banda antes de que cualquiera de los dos pueda descartarlo. Para eso hace falta mitigación aguas arriba, en la red del proveedor o en un servicio de scrubbing.
Endurecer el propio proxy
El servidor proxy pasa a ser la pieza más expuesta de tu infraestructura, así que merece el mismo cuidado que dabas al backend. Estas medidas son el mínimo razonable.
Oculta la versión de Nginx en las cabeceras y páginas de error, para no regalar información a los escaneos automatizados:
http {
server_tokens off;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
} Limita el tamaño de las peticiones y el tiempo que una conexión puede permanecer abierta enviando datos a cuentagotas:
client_max_body_size 20M;
client_body_timeout 12s;
client_header_timeout 12s; Y mantén el sistema actualizado, que en un proxy no es un consejo genérico: una vulnerabilidad en Nginx afecta a todo el tráfico de todos los sitios que hay detrás.
sudo apt update && sudo apt upgrade -y
sudo systemctl reload nginx Problemas frecuentes al montar un reverse proxy
| Síntoma | Causa habitual | Solución |
|---|---|---|
| Error 502 Bad Gateway | El backend no responde o el firewall bloquea al proxy | curl al backend desde el proxy |
| Todas las visitas figuran con la IP del proxy | Faltan X-Real-IP y X-Forwarded-For | Añadirlas al bloque location |
La app redirige a http:// con HTTPS activo | Falta X-Forwarded-Proto o el backend no la lee | Enviarla y configurar la app para confiar en el proxy |
| El backend sigue accesible por su IP | No se aplicó la regla de firewall | Cerrar el puerto salvo desde la IP del proxy |
| Usuarios legítimos reciben 429 o 503 | rate demasiado bajo o sin burst | Subir el límite y añadir burst con nodelay |
| Redirecciones infinitas | Proxy y backend redirigen ambos a HTTPS | Dejar la redirección solo en el proxy |
| Las sesiones se pierden al recargar | Balanceo sin afinidad y sesiones en memoria | ip_hash o sesiones en Redis o base de datos |
| Los WebSockets no conectan | Faltan proxy_http_version 1.1 y cabeceras Upgrade | Añadirlas al location |
Un reverse proxy con Nginx aporta tres cosas con relativamente poco esfuerzo: una capa de filtrado y límites antes de que el tráfico llegue a tu aplicación, terminación TLS centralizada, y la base para escalar horizontalmente con balanceo de carga. Sobre el ocultamiento de la IP conviene ser preciso: el proxy es la mitad del trabajo, y la otra mitad —la que de verdad protege— es la regla de firewall que hace al backend rechazar todo lo que no venga del proxy. Sin ella, basta con que alguien consulte el historial DNS de tu dominio para saltarse toda la configuración. Empieza por lo básico y bien hecho —proxy, firewall del backend cerrado, HTTPS automatizado y rate limiting sensato— y añade el WAF después, en modo detección, cuando el resto esté estable. Si necesitas dos servidores separados para montar este esquema, nuestros planes de VPS y servidores dedicados permiten desplegar proxy y backend en la misma red privada. Si tienes dudas durante la implementación, nuestro equipo de soporte técnico está disponible 24/7 para ayudarte.
Hosting con LiteSpeed, NVMe y soporte 24/7 desde $3/mes.