Cloudflare Tunnel a fondo: publica servicios sin abrir puertos ni exponer tu IP

Cómo funciona Cloudflare Tunnel y cloudflared: conexiones solo salientes, túneles gestionados desde el panel o en local, reglas ingress, Quick Tunnels, límites y seguridad con Access. Con una configuración de ingress validada con cloudflared.

Portada: Cloudflare Tunnel a fondo

Publicar en internet algo que corre en tu casa o en un servidor privado siempre ha tenido el mismo peaje: abrir puertos en el router, pelearte con la IP dinámica, exponer tu IP pública y confiar en que nadie encuentre el servicio antes de que lo protejas. Y si estás detrás de un CG-NAT de tu operador, ni siquiera puedes.

Cloudflare Tunnel le da la vuelta. Instalas un pequeño programa, cloudflared, en la máquina o la red donde está el servicio, y es él quien abre conexiones salientes hacia Cloudflare. Cuando alguien visita app.tudominio.com, Cloudflare le manda la petición por ese túnel. No abres ningún puerto de entrada, tu IP no aparece en el DNS y el tráfico pasa por la caché, el WAF y la protección DDoS como cualquier otro sitio proxied.

En este artículo vemos cómo funciona, los dos tipos de túnel, las reglas ingress, los Quick Tunnels sin cuenta, los límites y cómo cerrarlo con Access. Con una configuración real validada con cloudflared.

🧪
He instalado cloudflared 2026.9.3 el 3 de octubre de 2026 y he validado de verdad la configuración ingress de este artículo con sus comandos ingress validate e ingress rule, que funcionan sin conexión. No he llegado a abrir un túnel funcionando: el Quick Tunnel obtuvo su URL de trycloudflare.com, pero mi entorno de pruebas bloquea el tráfico UDP de QUIC y no lo repetí por HTTP/2. Los túneles con nombre, el enrutado DNS y Access tampoco están probados: necesitan cuenta y dominio. Todo lo demás sale de la documentación oficial, revisada ese mismo día.

Cómo funciona

  1. Instalas cloudflared en tu servidor, en una Raspberry Pi o en un contenedor de tu red.
  2. cloudflared abre conexiones salientes y cifradas (con criptografía post-cuántica) hacia Cloudflare. Cada túnel mantiene cuatro conexiones de larga duración a dos centros de datos distintos, para tener redundancia.
  3. Asocias nombres públicos (app.ejemplo.com) a servicios locales (http://localhost:8080).
  4. Cuando llega una visita, Cloudflare aplica caché y seguridad y envía la petición por el túnel; cloudflared la entrega al servicio local.
Esquema de Cloudflare Tunnel: el visitante entra por Cloudflare, donde se aplican DNS, WAF y Access; las peticiones viajan por conexiones salientes que cloudflared abrió desde la red privada; cloudflared las entrega a los servicios locales; el router no tiene puertos abiertos
Las conexiones las abre cloudflared desde dentro. Desde fuera no hay nada que escanear. Diagrama: devutilites.

Además de HTTP y HTTPS, un túnel puede llevar SSH, RDP, TCP arbitrario y sockets Unix. Para esos protocolos el cliente suele necesitar cloudflared también, o usar el acceso desde el navegador que ofrece Access.

Tunnel está disponible en todos los planes, también en el gratuito. Para publicar aplicaciones con un nombre propio necesitas una cuenta y un dominio en Cloudflare. Si tu red tiene un cortafuegos de salida restrictivo, comprueba que puede llegar a Cloudflare por el puerto 7844.

Dos formas de gestionar un túnel

  • Gestionado desde el panel (o la API). Creas el túnel en Networking > Tunnels, el panel te da un comando de instalación con un token y las rutas se definen allí. Es lo que recomienda la documentación para empezar: en cinco minutos lo tienes.
  • Gestionado en local. Creas el túnel con cloudflared tunnel create, que genera un fichero de credenciales, y defines las rutas en un config.yml. Útil si quieres versionar la configuración con el resto de tu infraestructura.

El flujo en local sería este (no lo he probado):

cloudflared tunnel login                      # autoriza cloudflared con tu cuenta
cloudflared tunnel create homelab             # crea el túnel y su fichero de credenciales
cloudflared tunnel route dns homelab app.ejemplo.com   # CNAME app → el túnel
cloudflared tunnel run homelab                # arranca usando ~/.cloudflared/config.yml

Reglas ingress

En un túnel gestionado en local, el config.yml lista las reglas ingress. Cada petición se compara con las reglas de arriba abajo; gana la primera que coincide, por hostname, por path (expresión regular) o por ambos. La última regla debe capturarlo todo.

# ~/.cloudflared/config.yml de un túnel gestionado en local
tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef
credentials-file: /home/yo/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json

ingress:
  # La API, solo las rutas /api/*, a un servicio en el puerto 3000
  - hostname: app.ejemplo.com
    path: ^/api/
    service: http://localhost:3000
  # El resto de app.ejemplo.com, al frontend
  - hostname: app.ejemplo.com
    service: http://localhost:5173
  # Grafana en el homelab, en otra máquina de la red local
  - hostname: grafana.ejemplo.com
    service: http://192.168.1.20:3000
  # SSH (el cliente necesita cloudflared o el acceso por navegador de Access)
  - hostname: ssh.ejemplo.com
    service: ssh://localhost:22
  # Regla final obligatoria: todo lo demás, 404
  - service: http_status:404

Y aquí la parte que sí he podido probar. cloudflared valida el fichero y te dice qué regla se aplicaría a una URL, sin conectarse a nada:

$ cloudflared tunnel --config config.yml ingress validate
Validating rules from config.yml
OK
$ cloudflared tunnel --config config.yml ingress rule https://app.ejemplo.com/api/usuarios
Using rules from config.yml
Matched rule #0
	hostname: app.ejemplo.com
	path: ^/api/
	service: http://localhost:3000
$ cloudflared tunnel --config config.yml ingress rule https://app.ejemplo.com/login
Using rules from config.yml
Matched rule #1
	hostname: app.ejemplo.com
	service: http://localhost:5173
$ cloudflared tunnel --config config.yml ingress rule https://grafana.ejemplo.com/
Using rules from config.yml
Matched rule #2
	hostname: grafana.ejemplo.com
	service: http://192.168.1.20:3000
$ cloudflared tunnel --config config.yml ingress rule https://otro.ejemplo.com/
Using rules from config.yml
Matched rule #4
	service: http_status:404

Si quitas la regla final, la validación falla:

$ cloudflared tunnel --config sin-final.yml ingress validate   # sin la regla final
Validating rules from sin-final.yml
Validation failed: The last ingress rule must match all URLs (i.e. it should not have a hostname or path filter)

Dos detalles de la documentación. cloudflared usa path para elegir la regla, pero envía la ruta completa al servicio: /api/usuarios llega como /api/usuarios, no como /usuarios. Y los comodines (*.ejemplo.com) funcionan en hostname, pero no en mitad del nombre.

Quick Tunnels: sin cuenta y sin dominio

Para enseñar algo un rato, no hace falta ni cuenta:

cloudflared tunnel --url http://localhost:8080

cloudflared imprime una URL aleatoria de trycloudflare.com y cualquiera que la tenga puede entrar. En mi prueba, la URL se generó en unos seis segundos. Además, puedes restringir quién entra con --allowed-mail: el visitante recibe un código de un solo uso por correo (puedes repetir el parámetro o usar '*@ejemplo.com').

Sus límites, según la documentación:

  • sin garantía de disponibilidad, solo para pruebas;
  • 200 peticiones en vuelo como máximo; las demás reciben un 429;
  • no soportan Server-Sent Events;
  • la URL cambia cada vez que lo arrancas.

Límites

ConceptoLímite
Túneles cloudflared por cuenta1000
Réplicas activas por túnel25
Conexiones por réplica4, a 2 centros de datos

Las réplicas son varias instancias de cloudflared con el mismo túnel en máquinas distintas: si una cae, el tráfico sigue por las demás.

Cerrar el túnel con Access

Un túnel solo cambia por dónde entra el tráfico; no decide quién entra. Si publicas Grafana, Home Assistant o un panel de administración, ponle delante una aplicación de Cloudflare Access: antes de llegar al túnel, el visitante tendrá que identificarse (con Google, GitHub, un código por correo…) y cumplir tus políticas. Lo cuento en el artículo sobre Zero Trust. Y el mismo mecanismo, con un token de servicio, es el que usa Hyperdrive para llegar a una base de datos privada.

⚠️
Tunnel no sustituye a la autenticación. Un servicio publicado con un túnel y sin Access es tan público como si hubieras abierto el puerto, solo que sin exponer tu IP.

Errores comunes (y cómo evitarlos)

  • Olvidar la regla final. El fichero no valida. Termina siempre con service: http_status:404.
  • Orden de las reglas. Una regla general antes que una específica se lo queda todo. Pon primero las de path.
  • Esperar que path recorte la ruta. No lo hace; si tu servicio espera otra ruta, reescríbela con una regla de Cloudflare o en un proxy local.
  • Publicar sin Access. Cualquier panel de administración necesita autenticación.
  • Origen HTTPS con certificado propio. Si el servicio local usa HTTPS con un certificado autofirmado, cloudflared no podrá verificarlo (la opción de origen noTLSVerify viene desactivada por defecto). Usa un certificado válido, configura las opciones de origen o usa HTTP en local.
  • Una sola réplica en producción. Si esa máquina se reinicia, el sitio cae. Usa al menos dos.
  • Usar Quick Tunnels en producción. No tienen garantía, la URL cambia y no soportan SSE.
  • Dejar el puerto abierto «por si acaso». El sentido del túnel es no tener puertos de entrada. Ciérralos en el router y haz que el origen escuche solo en local.

Cuándo usar Tunnel (y cuándo no)

Úsalo para publicar servicios de un homelab o de una red privada, para servidores detrás de CG-NAT, para quitarle la IP pública a un origen y que solo se llegue a él a través de Cloudflare, y para enseñar un desarrollo local un rato con un Quick Tunnel.

No es la herramienta para tráfico UDP de juegos o VoIP hacia el público, ni para mover grandes volúmenes de vídeo que no quieres que pasen por Cloudflare. Y si lo que quieres es que tus dispositivos lleguen a toda tu red privada como con una VPN, el túnel es solo una pieza: necesitas también el cliente de Cloudflare One, que vemos en el artículo de Zero Trust.

Sigue leyendo