Para ejecutar Cloudflare Tunnel en Docker, añade la imagen oficial cloudflare/cloudflared como un servicio en tu docker-compose.yml, pasa un token de túnel desde el panel de Cloudflare como la variable de entorno TUNNEL_TOKEN y coloca cloudflared en la misma red de Docker que la aplicación que quieres exponer. Ese es todo el truco: sin puertos abiertos en tu firewall, sin ningún proxy inverso que configurar, y cloudflared llega a tu aplicación por su nombre de contenedor a través de la red interna de Docker. Esta guía recorre la configuración exacta de Compose, el único detalle de red que hace tropezar a casi todo el mundo y los límites que conviene conocer antes de depender de ella.
Si quieres el panorama completo de cómo funcionan los túneles en cada método de instalación (systemd, macOS, túneles rápidos, además de Cloudflare Access por delante), consulta nuestra guía completa para configurar un Cloudflare Tunnel. Este artículo es más acotado a propósito: el patrón en contenedores, con Docker Compose, que la documentación oficial suele pasar por alto.
¿Por qué ejecutar cloudflared como contenedor?
La imagen de Docker cloudflare/cloudflared es el demonio conector que abre una conexión únicamente saliente hacia el edge de Cloudflare y reenvía las peticiones a tus servicios locales. Ejecutarla como contenedor en lugar de como paquete del sistema tiene tres ventajas reales para un stack autoalojado. Vive en el mismo docker-compose.yml que todo lo demás, así que todo el stack se levanta con un solo docker compose up -d. Está fijada a una etiqueta de imagen, de modo que las actualizaciones son un docker pull deliberado, no una actualización automática en segundo plano. Y puede comunicarse con tus demás contenedores directamente a través de una red privada de Docker, lo que significa que la aplicación que expones nunca necesita un puerto publicado.
El modelo de seguridad es la parte que la gente subestima. Como cloudflared marca hacia afuera a Cloudflare por QUIC/HTTPS, tu VPS o servidor doméstico puede mantener todos los puertos entrantes cerrados en el firewall. No hay ningún 80/443 a la escucha en la internet pública para escanear o forzar por fuerza bruta. Para un servidor autoalojado, eso supone una reducción significativa de la superficie de ataque frente a abrir agujeros para un proxy inverso tradicional.
Requisitos previos
- Un dominio incorporado a Cloudflare (usando los servidores de nombres de Cloudflare). La documentación oficial de configuración indica que esto es obligatorio para publicar una aplicación a través de un túnel.
- Docker y Docker Compose instalados en el host. Si partes de un servidor limpio, nuestra guía de la primera hora segura en un VPS cubre el endurecimiento antes de exponer nada.
- Un token de túnel, creado en un solo paso en el panel (siguiente sección).
El propio Cloudflare Tunnel es gratuito y con ancho de banda ilimitado: solo necesitas la cuenta gratuita de Cloudflare y un dominio en su DNS.
Paso 1 — Crea un túnel gestionado de forma remota y copia el token
En el panel de Cloudflare, ve a Zero Trust → Networks → Tunnels → Create a tunnel, elige Cloudflared, ponle nombre y guarda. En la pantalla de "instalar el conector", elige Docker. Cloudflare te muestra un comando docker run con un token largo incrustado; no necesitas el comando completo, solo la cadena del token que aparece después de --token. Ese token autentica el conector y a la vez le indica a qué túnel pertenece.
Este es el modelo gestionado de forma remota: las reglas de enrutamiento del túnel (qué nombre de host se asigna a qué servicio local) se configuran en el panel, no en un archivo de configuración local. Es el camino más sencillo para Docker y el que Cloudflare ahora usa por defecto. La alternativa, gestionado de forma local, mantiene un archivo config.yml y un archivo de credenciales dentro del contenedor: más portable y versionable, pero con más piezas en movimiento. La tabla siguiente los compara.
| Gestionado de forma remota (token) | Gestionado de forma local (config.yml) | |
|---|---|---|
| Dónde vive el enrutamiento | Panel de Cloudflare | config.yml en el host |
| Qué necesita el contenedor | Solo TUNNEL_TOKEN | Archivo de configuración + credenciales JSON montadas |
| Ideal para | La mayoría de configuraciones con Docker, arranque rápido | GitOps, muchos nombres de host, infraestructura reproducible |
| Ediciones de ingress | Un clic en el panel | Editar el archivo, reiniciar el contenedor |
| Secretos que proteger | El token | El archivo de credenciales |
Paso 2 — Añade cloudflared a docker-compose.yml
Aquí tienes un archivo Compose mínimo que expone un contenedor de aplicación (llámalo webapp, a la escucha en el puerto 3000) a través del túnel:
services:
webapp:
image: your/webapp:latest
restart: unless-stopped
networks: [internal]
# note: no "ports:" — nothing is published to the host
cloudflared:
image: cloudflare/cloudflared:latest
restart: unless-stopped
command: tunnel --no-autoupdate run
environment:
- TUNNEL_TOKEN=${TUNNEL_TOKEN}
networks: [internal]
networks:
internal:
Coloca el token en un archivo .env junto al archivo Compose (TUNNEL_TOKEN=ey...) y añade ese archivo a .gitignore. Nunca subas el token: cualquiera que lo tenga puede ejecutar tu túnel. Para una configuración endurecida, usa un Docker secret en lugar de una variable de entorno. El indicador --no-autoupdate es deliberado: la etiqueta de la imagen controla la versión, así que actualizas descargando una imagen nueva, no dejando que el demonio se parchee a sí mismo en tiempo de ejecución.
El comando puntual equivalente, si no usas Compose, es el mismo que imprime el panel:
docker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token <TUNNEL_TOKEN>
Paso 3 — Apunta el túnel a tu contenedor (el detalle clave)
Aquí es donde la mayoría de la gente se atasca, y aparece por todas partes en los foros de la comunidad de Cloudflare. De vuelta en el panel, abre tu túnel, ve a la pestaña Public Hostname y añade una ruta: elige un subdominio (digamos app.yourdomain.com) y define la URL del service.
El error es introducir http://localhost:3000. Dentro del contenedor de cloudflared, localhost es el propio contenedor de cloudflared, no tu aplicación ni el host de Docker. Como ambos contenedores comparten la red internal, cloudflared puede resolver la aplicación por su nombre de servicio de Compose. Así que el valor correcto de service es:
http://webapp:3000
El DNS integrado de Docker asigna webapp a la IP del contenedor de la aplicación en la red compartida. Si tu aplicación se ejecuta en otro sitio que no sea un contenedor hermano —digamos directamente en el host— usarías en su lugar http://host.docker.internal:3000 (con la entrada extra_hosts adecuada en Linux). Acertar con esta URL es el 90 % de un túnel que funciona; un 502 en el edge casi siempre significa que cloudflared no puede alcanzar la dirección que escribiste aquí.
Paso 4 — Levántalo y verifica
docker compose up -d
docker compose logs -f cloudflared
En los registros, busca líneas que confirmen las conexiones registradas con el edge de Cloudflare (normalmente cuatro, a distintos centros de datos). Una vez que estén activas, carga https://app.yourdomain.com: el TLS se termina en el edge de Cloudflare de forma automática, así que obtienes HTTPS sin instalar nunca un certificado en tu servidor. Si no resuelve, comprueba que se creó el registro DNS del Public Hostname (Cloudflare añade un CNAME con proxy por ti) y que la URL del service coincide con el nombre y el puerto de tu contenedor.
Límites que conviene conocer antes de depender de ello
Los túneles son sólidos, pero el proxy gratuito tiene sus fronteras rígidas:
- Tope de subida de 100 MB. Los planes Free y Pro de Cloudflare imponen un tamaño máximo del cuerpo de la petición de 100 MB. Sube un archivo más grande a través del túnel y el edge devuelve HTTP 413 antes de que llegue siquiera a tu contenedor. Esto afecta a las aplicaciones de subida de archivos, las copias de seguridad y las publicaciones de contenido multimedia de gran tamaño.
- No es para streaming intensivo de multimedia. El proxy de Cloudflare no está pensado para servir grandes volúmenes de contenido no HTML, como bibliotecas de vídeo; un Plex o Jellyfin autoalojado detrás de un túnel puede toparse con limitaciones de velocidad. Úsalo para aplicaciones y paneles, no como una CDN para una colección de películas.
- Los túneles rápidos son solo para pruebas. Los túneles desechables
trycloudflare.comtienen un límite de 200 peticiones concurrentes y no admiten Server-Sent Events. Bien para una demo, mal para producción: usa en su lugar un túnel con nombre y tu propio dominio. - Estás confiando en el edge de Cloudflare. Todo el tráfico atraviesa su red. Para la mayoría de quienes autoalojan es un intercambio aceptable a cambio de puertos entrantes cerrados; si no lo es para tu modelo de amenazas, un WireGuard o un proxy inverso autoalojados son la alternativa.
Para una capa de seguridad más profunda, también puedes poner Cloudflare Access por delante del nombre de host, de modo que solo los usuarios autenticados lleguen a la aplicación, algo que cubrimos en la guía general de túneles.
Dónde encaja esto en un stack autoalojado
El patrón de túnel con Docker brilla cuando ya ejecutas tus aplicaciones en contenedores, que es la dirección hacia la que se ha movido la mayor parte del autoalojamiento. Combínalo con nuestra guía paso a paso para autoalojar tus aplicaciones en un VPS y cloudflared se convierte en el único servicio de "puerta de entrada" portable que colocas en cada stack. Una imagen, una variable de entorno, cero puertos abiertos.
Preguntas frecuentes
¿Puedo ejecutar cloudflared en docker-compose?
Sí. Añade cloudflare/cloudflared:latest como servicio con command: tunnel --no-autoupdate run y una variable de entorno TUNNEL_TOKEN que contenga un token que hayas creado en el panel de Cloudflare Zero Trust. Colócalo en la misma red de Docker que la aplicación que expones para que pueda alcanzar el contenedor por su nombre.
¿Cómo llega cloudflared a otro contenedor?
A través del DNS interno de Docker. Cuando ambos contenedores comparten una red definida por el usuario, cloudflared resuelve el otro contenedor por su nombre de servicio de Compose, así que la URL del service del túnel es http://<service-name>:<port> (por ejemplo http://webapp:3000), nunca http://localhost:3000, porque localhost dentro del contenedor se refiere al propio cloudflared.
¿Necesito abrir puertos para un Cloudflare Tunnel en Docker?
No. cloudflared establece una conexión únicamente saliente hacia el edge de Cloudflare, así que no se publica ningún puerto entrante en el contenedor ni se abre nada en el firewall del host. Esa postura de puertos cerrados es el principal beneficio de seguridad frente a un proxy inverso tradicional.
¿Cloudflare Tunnel es gratis?
Sí. Cloudflare Tunnel es gratuito y con ancho de banda ilimitado en el plan gratuito; solo necesitas una cuenta gratuita de Cloudflare y un dominio que use el DNS de Cloudflare. Los planes de pago elevan algunos límites del proxy (como el tope de 100 MB por petición), pero no son necesarios para ejecutar un túnel.
¿Cloudflare Tunnel o un proxy inverso: cuál debería usar en Docker?
Usa un proxy inverso (Caddy, Traefik, Nginx) cuando te sientas cómodo abriendo 80/443 y quieras control total del TLS y el almacenamiento en caché en tu propio servidor. Usa un Cloudflare Tunnel cuando prefieras mantener todos los puertos entrantes cerrados y dejar que Cloudflare se encargue del TLS y el enrutamiento en el edge. Muchos stacks ejecutan ambos: un túnel para el acceso externo y un proxy para el enrutamiento interno.
Fuentes
- Cloudflare — Set up Cloudflare Tunnel: pasos oficiales de instalación, el comando
docker run cloudflare/cloudflaredy el requisito de tener el dominio en Cloudflare, actualizado en abril de 2026. - Docker Hub — cloudflare/cloudflared: la imagen oficial del conector usada en el archivo Compose.
- Cloudflare Community — cloudflared in docker-compose: la pregunta recurrente sobre la red de contenedores que resuelve esta guía.
- Cloudflare Community — maximum upload limit on the free plan: confirma el tope de 100 MB en el cuerpo de la petición que devuelve HTTP 413.
Waqas Ahmed Waseer
Waqas Ahmed Waseer es desarrollador y creador de automatizaciones con más de 8 años construyendo sistemas en producción que usan más de 100.000 personas. Crea SaaS multiinquilino a medida, automatización con IA (n8n, flujos LLM, bots de WhatsApp) e infraestructura de hosting (WHM/cPanel, CloudLinux), y es el creador de WaSphere, FlowMaticX y la marca de hosting WaseerHost. Más de 100 proyectos entregados para pymes, agencias y startups financiadas.



