7.0 KiB
Traefik + Cloudflare Tunnel - Configuración
Esta guía explica cómo funciona Traefik detrás de Cloudflare Tunnel y cómo obtener las IPs reales de los visitantes.
🌐 Arquitectura
Internet → Cloudflare (SSL/DDoS) → Cloudflare Tunnel → Traefik (443) → Contenedores
📍 IPs Reales de Visitantes
¿Cómo funciona?
Cuando un usuario visita tu sitio:
- Cloudflare recibe la conexión y conoce la IP real del visitante
- Cloudflare envía la IP real en headers HTTP:
CF-Connecting-IP: IP real del cliente ✅ (más confiable)X-Forwarded-For: Cadena de proxiesX-Real-IP: IP real (alternativa)
- Traefik lee estos headers y los pasa a tus aplicaciones
Configuración aplicada
Ya está configurado en traefik/traefik.yml:
entryPoints:
websecure:
forwardedHeaders:
trustedIPs:
- "173.245.48.0/20" # Rangos de IPs de Cloudflare
- "103.21.244.0/22"
# ... etc (23 rangos en total)
Esto le dice a Traefik: "Confía en los headers de IPs que vienen de Cloudflare"
✅ Verificar que funciona
-
Inicia Traefik:
docker compose up -d -
Verifica los logs de acceso:
docker compose logs traefik | grep "CF-Connecting-IP" -
Deberías ver la IP real en los logs:
{ "ClientAddr": "173.245.48.5:12345", // IP de Cloudflare "headers": { "CF-Connecting-IP": "187.123.45.67" // ← IP REAL del visitante } }
🔍 Leer IP real desde tus aplicaciones
Node.js / Express
app.get('/', (req, res) => {
const realIP = req.headers['cf-connecting-ip']
|| req.headers['x-forwarded-for']?.split(',')[0]
|| req.connection.remoteAddress;
console.log('IP real del visitante:', realIP);
});
Python / Flask
from flask import Flask, request
@app.route('/')
def index():
real_ip = request.headers.get('CF-Connecting-IP') \
or request.headers.get('X-Forwarded-For', '').split(',')[0] \
or request.remote_addr
print(f'IP real del visitante: {real_ip}')
Go / Gin
func handler(c *gin.Context) {
realIP := c.GetHeader("CF-Connecting-IP")
if realIP == "" {
realIP = c.ClientIP()
}
fmt.Printf("IP real del visitante: %s\n", realIP)
}
PHP
<?php
$real_ip = $_SERVER['HTTP_CF_CONNECTING_IP']
?? explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]
?? $_SERVER['REMOTE_ADDR'];
echo "IP real del visitante: $real_ip";
Nginx (dentro de contenedor)
Si tienes nginx dentro de un contenedor detrás de Traefik:
server {
location / {
# Traefik ya pasó los headers, solo léelos
set $real_ip $http_cf_connecting_ip;
# O usa el módulo real_ip
real_ip_header CF-Connecting-IP;
# Loguea la IP real
access_log /var/log/nginx/access.log combined;
}
}
🛡️ Seguridad
¿Por qué confiar solo en IPs de Cloudflare?
La configuración trustedIPs es crucial para evitar IP spoofing:
❌ Sin trustedIPs:
Atacante envía: X-Forwarded-For: 1.1.1.1
Traefik cree que la IP real es 1.1.1.1 (FALSO)
✅ Con trustedIPs (configurado):
Si la petición viene de 192.168.1.1 (no es IP de Cloudflare):
→ Traefik IGNORA el header X-Forwarded-For
→ Usa la IP de conexión real
Si viene de 173.245.48.5 (IP de Cloudflare):
→ Traefik CONFÍA en CF-Connecting-IP ✅
Actualizar rangos de IPs de Cloudflare
Cloudflare publica sus IPs oficiales:
# IPv4
curl https://www.cloudflare.com/ips-v4
# IPv6
curl https://www.cloudflare.com/ips-v6
Si Cloudflare agrega nuevos rangos, actualiza traefik/traefik.yml.
🔐 SSL/TLS con Cloudflare
Opciones de SSL en Cloudflare
En el dashboard de Cloudflare → SSL/TLS, tienes 3 opciones:
-
Flexible (❌ No recomendado)
- Cloudflare ↔ Cliente: HTTPS ✅
- Cloudflare ↔ Traefik: HTTP ❌
- Vulnerable a ataques man-in-the-middle
-
Full (⚠️ Aceptable)
- Cloudflare ↔ Cliente: HTTPS ✅
- Cloudflare ↔ Traefik: HTTPS ✅ (autofirmado OK)
- Más seguro
-
Full (Strict) (✅ Recomendado)
- Cloudflare ↔ Cliente: HTTPS ✅
- Cloudflare ↔ Traefik: HTTPS con certificado válido ✅
- Máxima seguridad
Tu configuración actual
Con Cloudflare Tunnel apuntando a puerto 443:
- Cloudflare → Tunnel → Traefik:443 (HTTPS)
- Traefik puede usar:
- Certificados Let's Encrypt (ya configurado en
traefik.yml) - O certificados autofirmados para el túnel
- Certificados Let's Encrypt (ya configurado en
Recomendación: Usar Full o Full (Strict) en Cloudflare.
📊 Monitoreo de IPs
Ver IPs en logs de Traefik
# Ver logs en tiempo real con IPs
docker compose logs -f traefik
# Filtrar solo IPs de Cloudflare
docker compose logs traefik | grep "CF-Connecting-IP"
# Ver estadísticas de IPs únicas
docker exec traefik cat /var/log/traefik/access.log | \
jq -r '.headers["CF-Connecting-IP"]' | \
sort | uniq -c | sort -rn
Dashboard de Traefik
El dashboard muestra:
- ❌ IP de Cloudflare (173.245.x.x) en "Client Address"
- ✅ IP real disponible en logs JSON
🧪 Prueba rápida
Después de iniciar Traefik:
# 1. Simular petición desde "fuera" (pasando por Cloudflare)
curl -H "CF-Connecting-IP: 187.123.45.67" \
-H "Host: whoami.nucleoriofrio.com" \
http://localhost
# 2. Ver los logs y buscar la IP
docker compose logs traefik | tail -20
❓ FAQ
¿Necesito certificados SSL si uso Cloudflare?
Para el tunnel NO (Cloudflare maneja SSL público), pero sí es recomendable para:
- Seguridad adicional Cloudflare ↔ Traefik
- Servicios internos
- Modo Full (Strict) de Cloudflare
¿Puedo bloquear acceso directo al puerto 443?
SÍ, deberías hacerlo:
# Firewall: permitir solo Cloudflare IPs en 443
sudo ufw allow from 173.245.48.0/20 to any port 443
sudo ufw allow from 103.21.244.0/22 to any port 443
# ... agregar todos los rangos
# O usar iptables
sudo iptables -A INPUT -p tcp --dport 443 -s 173.245.48.0/20 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j DROP
Esto asegura que solo Cloudflare pueda llegar a Traefik.
¿Qué pasa si la IP en logs es de Cloudflare?
Verifica:
- Headers en logs:
grep "CF-Connecting-IP" access.log - trustedIPs configurado: Revisa
traefik.yml - Cloudflare enviando headers: Verifica en Cloudflare dashboard
¿Los rangos de IP de Cloudflare cambian?
Sí, ocasionalmente. Verifica periódicamente:
curl https://www.cloudflare.com/ips-v4
Y actualiza traefik.yml si hay cambios.
📚 Referencias
Última actualización: Octubre 2025 Rangos de IP Cloudflare verificados: Octubre 2025