Tutorial

Cloudflare Tunnel: exponer una app VPS sin abrir puertos

Despliegue10 min de lectura7 pasos

Acaba de desplegar una aplicación en su VPS y se encuentra bloqueado: IP dinámica, firewall corporativo que filtra el puerto 443 entrante o negativa a exponer directamente su servidor a Internet. Un Cloudflare Tunnel resuelve el problema invirtiendo la conexión: es `cloudflared` quien llama a Cloudflare, no al revés. Resultado: su aplicación queda accesible por HTTPS en su dominio, sin abrir ni un solo puerto entrante y sin tocar su configuración DNS.

Contenido· Por qué un Cloudflare Tunnel en lugar de abrir un puerto1/10
  1. 01Por qué un Cloudflare Tunnel en lugar de abrir un puerto
  2. 02Lo que aporta Cloudflare Tunnel en la práctica
  3. 03Requisitos previos
  4. 04Instalar y configurar cloudflared en el VPS
  5. 05Configuración posterior a la instalación
  6. 06Hardening: cierre los puertos 80 y 443 entrantes
  7. 07Cloudflare Tunnel frente a Nginx / Traefik: enfoques complementarios
  8. 08Cloudflare Tunnel frente a un reverse proxy local
  9. 09Resolución de problemas: mensajes de error frecuentes
  10. 10Cloudflare Tunnel como arquitectura de referencia en un VPS

Por qué un Cloudflare Tunnel en lugar de abrir un puerto

La configuración clásica — abrir los puertos 80 y 443 en el firewall, apuntar un registro DNS a la IP del servidor, instalar un reverse proxy — funciona bien cuando usted controla la red. Pero hay tres situaciones que la hacen fracasar: un proveedor de acceso o una red corporativa que bloquea las conexiones entrantes en el 443, una IP dinámica que invalida sus registros DNS cada 24 horas, o un VPS situado detrás de un NAT estricto que no permite ningún port forwarding.

Cloudflare Tunnel sortea estos tres casos con un mismo mecanismo: el demonio cloudflared establece una conexión saliente persistente hacia los puntos de presencia de Cloudflare. Su servidor no acepta nada, Cloudflare recibe las peticiones HTTPS y las transmite por ese túnel cifrado. El tráfico entrante nunca llega directamente a su servidor.

Lo que aporta Cloudflare Tunnel en la práctica

  • Cero puertos abiertos — el firewall del VPS puede bloquear todo el tráfico entrante (80 y 443 incluidos) sin afectar a la accesibilidad de la aplicación.
  • HTTPS automático — Cloudflare gestiona el certificado TLS del lado del cliente: nada de Let's Encrypt que configurar, ninguna renovación que vigilar.
  • NAT e IP dinámica transparentes — la conexión saliente de cloudflared atraviesa cualquier NAT; la IP del servidor puede cambiar sin reconfigurar el DNS.
  • Red corporativa o proveedor restrictivo — si el puerto 443 entrante está bloqueado en su ubicación, el túnel sigue funcionando porque se apoya en conexiones salientes HTTP/2 o QUIC.
  • Integración Zero Trust opcional — los túneles se combinan con Cloudflare Access para restringir el acceso a usuarios autenticados, sin VPN.
  • Protección de Cloudflare incluida — el tráfico pasa por la red de Cloudflare: mitigación de DDoS, WAF y rate limiting se aplican sin configuración adicional.
  • Plan gratuito disponible — un túnel sencillo, sin load balancing, se puede usar sin ninguna suscripción de pago de Cloudflare.

Requisitos previos

Para seguir esta guía necesita:

Un VPS con acceso root. La instalación de cloudflared como servicio systemd — la única manera de garantizar el reinicio automático — exige permisos de root. Un alojamiento compartido o una instancia sin acceso root no permite esta configuración.

Recursos mínimos. cloudflared consume menos de 50 MB de RAM y un CPU despreciable. Cuente 1 vCPU y 512 MB de RAM como mínimo estricto solo para el demonio; la restricción real viene de la aplicación que va a exponer.

Un dominio gestionado por Cloudflare. El dominio debe estar registrado o transferido a Cloudflare (o con delegación NS hacia Cloudflare). Sin una zona Cloudflare activa, un túnel named no puede crear el registro DNS automático.

Docker Engine (si utiliza la variante Docker Compose de esta guía). Disponible en Ubuntu 22.04/24.04, Debian 12 y las distribuciones compatibles con RHEL.

Una cuenta gratuita de Cloudflare. No se requiere ninguna suscripción de pago para un túnel único sin load balancing.

Instalar y configurar cloudflared en el VPS

  1. Instalar cloudflared desde el repositorio de Cloudflare

    Cloudflare publica cloudflared como paquete .deb / .rpm y como binario estático. Para una instalación con APT en Debian/Ubuntu:

    curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg > /dev/null
    echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
    sudo apt update && sudo apt install cloudflared

    Compruebe que la instalación se ha realizado correctamente:

    cloudflared --version

    El comando debe devolver una línea del tipo cloudflared version 2025.x.x (built ...). La versión exacta depende del momento de la instalación; consulte el repositorio oficial cloudflare/cloudflared para conocer el número actual.

  2. Autenticar cloudflared ante Cloudflare

    En el VPS (o de forma local si dispone de acceso gráfico), ejecute:

    cloudflared tunnel login

    En la terminal aparece un enlace. Ábralo en un navegador, seleccione la zona de Cloudflare que desea autorizar y confirme. Se crea un certificado ~/.cloudflared/cert.pem en la máquina.

  3. Crear un túnel con nombre

    Cree un túnel con un nombre descriptivo:

    cloudflared tunnel create mon-tunnel

    Cloudflare genera un identificador UUID y un archivo de credenciales ~/.cloudflared/<UUID>.json. Anote el UUID; lo necesitará en los pasos siguientes.

  4. Escribir el archivo de configuración config.yml

    Cree /etc/cloudflared/config.yml:

    sudo mkdir -p /etc/cloudflared

    Contenido del archivo (adapte <UUID>, votre-domaine.com y el puerto de su aplicación):

    tunnel: <UUID>
    credentials-file: /home/<user>/.cloudflared/<UUID>.json
    
    ingress:
      - hostname: app.votre-domaine.com
        service: http://localhost:3000
      - service: http_status:404

    La última regla — service: http_status:404 sin hostname — es obligatoria: sirve de regla catch-all. Sin ella, cloudflared se niega a arrancar y devuelve el error "You must specify an ingress rule that matches all incoming requests". Si su aplicación se ejecuta en otro puerto o con otro protocolo, sustituya http://localhost:3000 en consecuencia (por ejemplo http://localhost:8080 o tcp://localhost:22 para SSH).

  5. Crear el registro DNS y arrancar el túnel

    Registre automáticamente el subdominio en su zona de Cloudflare:

    cloudflared tunnel route dns mon-tunnel app.votre-domaine.com

    Luego pruebe el túnel en modo foreground para validar la configuración:

    cloudflared tunnel run mon-tunnel

    Abra https://app.votre-domaine.com en un navegador. Si la aplicación responde, detenga el proceso (Ctrl+C) y pase al paso siguiente.

  6. Instalar cloudflared como servicio systemd

    Para que el túnel se reinicie automáticamente al arrancar el servidor, instálelo como demonio del sistema:

    sudo cloudflared service install
    sudo systemctl enable cloudflared
    sudo systemctl start cloudflared
    sudo systemctl status cloudflared

    El archivo unit de systemd creado por Cloudflare se encuentra en /etc/systemd/system/cloudflared.service. Su contenido se parece a esto:

    [Unit]
    Description=cloudflared
    After=network.target
    
    [Service]
    TimeoutStartSec=0
    Type=notify
    ExecStart=/usr/bin/cloudflared --no-autoupdate tunnel run
    Restart=on-failure
    RestartSec=5s
    
    [Install]
    WantedBy=multi-user.target

    Con este servicio activo, el túnel queda operativo desde el arranque del VPS, sin intervención manual.

  7. Integrar cloudflared en un Docker Compose existente

    Si su aplicación ya se ejecuta en un stack de Docker Compose, añada un servicio cloudflared en el mismo archivo. El enfoque por token (sin archivo de credenciales) es el más sencillo para un contenedor:

    services:
      app:
        image: mon-image
        networks:
          - internal
    
      cloudflared:
        image: cloudflare/cloudflared:latest
        command: tunnel --no-autoupdate run
        environment:
          - TUNNEL_TOKEN=${TUNNEL_TOKEN}
        networks:
          - internal
        restart: unless-stopped
    
    networks:
      internal:

    Defina TUNNEL_TOKEN en un archivo .env al mismo nivel. El token se obtiene desde el panel de Cloudflare → Zero Trust → Networks → Tunnels → su túnel → Configure → Conectores Docker. El servicio cloudflared y su aplicación comparten la red internal; en config.yml o mediante el token, apunte a la aplicación por su nombre de servicio Docker (http://app:3000 en lugar de http://localhost:3000).

Configuración posterior a la instalación

Una vez operativo el túnel, algunos ajustes complementarios mejoran la robustez de la configuración.

Recuperar la IP real del cliente. Por defecto, su aplicación recibe las peticiones desde 127.0.0.1 o desde la IP interna del túnel. Para obtener la IP real del visitante, lea la cabecera CF-Connecting-IP que Cloudflare inyecta automáticamente. Configure su aplicación o su reverse proxy local para confiar en esa cabecera.

Cifrado de extremo a extremo. El túnel cifra la conexión entre cloudflared y Cloudflare. La conexión entre cloudflared y su aplicación local va en HTTP por defecto (loopback o red interna de Docker). Si su aplicación expone HTTPS en local, añada originServerName: app.votre-domaine.com en la regla de ingress correspondiente para que cloudflared valide el certificado.

Varios servicios, un solo túnel. Un túnel puede exponer varios servicios en subdominios distintos: basta con añadir entradas adicionales en el bloque ingress de config.yml, antes de la regla catch-all.

Hardening: cierre los puertos 80 y 443 entrantes

La principal ventaja de esta arquitectura es poder cerrar todos los puertos entrantes del VPS. Una vez validado el túnel, aplique estas reglas de UFW:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enable

Su aplicación sigue siendo accesible a través del túnel de Cloudflare (que se apoya en conexiones salientes), y el puerto SSH permanece abierto para la administración. Ninguna conexión directa al 80 o al 443 llega ya al servidor. Consulte la guía Configurar UFW en un VPS para la configuración completa.

Cloudflare Tunnel frente a Nginx / Traefik: enfoques complementarios

Una objeción frecuente: «Ya tengo Nginx y Traefik haciendo ese trabajo, ¿por qué añadir una capa de Cloudflare?» La respuesta es que ambos enfoques no resuelven el mismo problema.

Un reverse proxy local (Nginx, Traefik, Caddy) gestiona el enrutamiento entre servicios de la misma red y la renovación del SSL, pero da por supuesto que el tráfico entrante llega al servidor. Si el puerto 443 está bloqueado por la red situada aguas arriba, el reverse proxy no sirve de nada.

Cloudflare Tunnel resuelve precisamente lo que el reverse proxy local no puede: el tráfico llega a Cloudflare sea cual sea la conectividad de red del servidor. Los dos son complementarios: puede perfectamente colocar Traefik detrás del túnel para gestionar el enrutamiento interno y dejar que Cloudflare se encargue del TLS público.

Cloudflare Tunnel frente a un reverse proxy local

Desplace la tabla

CriterioCloudflare TunnelReverse proxy local (Nginx/Traefik)
Puerto entrante necesarioNo — solo conexión salienteSí — 80/443 deben estar accesibles
TLS públicoGestionado por Cloudflare, automáticoLet's Encrypt vía ACME (certbot, Traefik…)
IP dinámica / NAT estrictoTransparente — no hay DNS que actualizarProblemático — requiere un DynDNS o una IP fija
Load balancingPlan de pago (Cloudflare Load Balancing)Disponible de forma nativa (Traefik, Nginx upstream)
LatenciaLigeramente superior (enrutamiento vía POP de Cloudflare)Mínima — tráfico directo hacia el servidor
Dependencia externaSí — Cloudflare debe estar accesibleNo — funciona sin terceros

Resolución de problemas: mensajes de error frecuentes

You must specify an ingress rule that matches all incoming requests
Falta la regla catch-all o está mal ubicada en config.yml. Debe ser la última entrada del bloque ingress, sin hostname, con service: http_status:404.

Unable to locate config file in default locations
cloudflared busca su configuración en ~/.cloudflared/config.yml o en /etc/cloudflared/config.yml. Indique la ruta de forma explícita con cloudflared tunnel --config /etc/cloudflared/config.yml run mon-tunnel.

ERR connection to origin timed out en los logs
La aplicación de destino no es accesible desde cloudflared. Compruebe que el servicio local se está ejecutando (curl http://localhost:3000) y que el puerto de config.yml coincide. En un contexto de Docker Compose, utilice el nombre del servicio (http://app:3000) en lugar de localhost.

Token caducado: tunnel credentials file not found o token is expired
Los tokens generados desde la interfaz de Cloudflare tienen una vida útil limitada si el conector nunca se ha registrado. Regenere el token desde Zero Trust → Networks → Tunnels → Configure → Conectores y actualice después la variable TUNNEL_TOKEN de su .env.

Límites del plan Free: load balancing y SSH por túnel
El plan gratuito no admite load balancing entre varios orígenes. El acceso SSH por túnel (cloudflared access ssh) en el plan gratuito requiere una configuración específica de Cloudflare Access y no está activado por defecto. El número de conectores por túnel está limitado a unas pocas instancias en el plan gratuito.

Cloudflare Tunnel como arquitectura de referencia en un VPS

Cloudflare Tunnel ilustra bien lo que hace posible el acceso root en un VPS: instalar cloudflared como demonio del sistema, modificar las reglas del firewall, controlar servicios systemd. En un alojamiento compartido sin acceso root, ninguno de estos pasos es viable: el demonio no se puede instalar, el firewall no está bajo su control y el servicio no se puede configurar para arrancar con el sistema.

Esta arquitectura encaja especialmente en situaciones donde la conectividad de red es limitada o incierta: laboratorios de desarrollo, oficinas con un firewall corporativo estricto, servidores edge o, simplemente, cuando no se quiere exponer una IP pública. Se combina de forma natural con reverse proxies locales como Traefik o Nginx Proxy Manager para el enrutamiento interno, y con el hardening del sistema para cerrar las superficies de ataque directas.

Un VPS con acceso root para instalar cloudflared

El demonio `cloudflared` y su servicio systemd requieren acceso root, algo que un alojamiento compartido no permite. Un VPS ServOrbit le da el control total: elección de sistema operativo, acceso root, IPv4 dedicada y las plantillas del Marketplace para empezar rápido.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva