SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-30

Cloudflare Tunnel sin puertos abiertos en un VPS

Configura un túnel nombrado con credenciales, ingress y systemd; cierra 80 y 443 y enlaza la aplicación a localhost para evitar el acceso directo.

Qué hace Cloudflare Tunnel y qué significa realmente no tener puertos abiertos

Cloudflare Tunnel instala un daemon pequeño llamado cloudflared en su VPS. Ese daemon abre una conexión saliente hacia Cloudflare y la mantiene abierta. Las peticiones dirigidas a su nombre de host llegan al edge de Cloudflare y se reenvían a través de esa conexión existente, por lo que nada tiene que conectarse hacia dentro de su servidor.

El paso al que nunca llegan la mayoría de las guías: instalar el túnel no cierra ningún puerto. Si 80 y 443 siguen abiertos en el firewall y la aplicación sigue escuchando en 0.0.0.0, ha añadido una segunda vía de acceso en lugar de sustituir la primera. La IP de origen sigue siendo accesible, y cualquiera que la encuentre accederá directamente sin pasar por Cloudflare. Cerrar esos puertos es un paso manual. Ese paso es el que hace que todo lo anterior valga la pena.

cloudflared necesita conectividad saliente hacia region1.v2.argotunnel.com y region2.v2.argotunnel.com en el puerto 7844. Usa UDP para el protocolo QUIC y recurre a TCP para HTTP/2. En una red con filtrado de salida, permita ambos protocolos o fuerce la ruta TCP con --protocol http2.

Antes de empezar

  • Un dominio ya añadido a una cuenta de Cloudflare, con los servidores de nombres de Cloudflare sirviendo la zona. cloudflared tunnel route dns escribe registros en esa zona, por lo que la zona debe existir primero.
  • Acceso saliente por el puerto 7844 desde el VPS, mediante UDP y TCP.
  • Una aplicación que ya escuche localmente, aunque sólo sea python3 -m http.server 8080 para la primera prueba.
  • sudo en el servidor y una segunda sesión SSH abierta antes de modificar el firewall.

Instalar cloudflared en Ubuntu o Debian

Cloudflare adjunta un paquete .deb a cada versión cloudflared, por lo que la instalación requiere una descarga y una llamada a dpkg.

curl -fsSL -o /tmp/cloudflared.deb \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i /tmp/cloudflared.deb
cloudflared --version

Ejecute primero dpkg --print-architecture si no está seguro de la arquitectura del sistema. En ARM de 64 bits, el nombre de archivo termina en arm64 en lugar de amd64 y no cambia nada más. cloudflared --version muestra una cadena de versión; esa es la única confirmación que necesita antes de continuar.

Un paquete instalado de esta forma queda fuera de la ruta de actualización de apt, por lo que apt-get upgrade nunca lo actualizará y usted deberá encargarse de sus actualizaciones. sudo cloudflared update descarga la versión más reciente y reemplaza el binario en el mismo lugar. Cuando el servicio ya exista, ejecute después sudo systemctl restart cloudflared para que el proceso en ejecución use el binario nuevo. Incluya este paso en el mismo calendario que el resto de sus actualizaciones, porque un daemon de túnel es software expuesto a Internet aunque no abra ningún puerto.

Inicie sesión y cree un túnel con nombre

cloudflared tunnel login

En un VPS sin interfaz gráfica no se abre ningún navegador. Copie la URL mostrada en el navegador de su equipo portátil y seleccione la zona. Cuando termine, ~/.cloudflared/cert.pem existirá.

cert.pem es la credencial de su cuenta. Autoriza la creación de túneles, la escritura de registros DNS en esa zona y la eliminación de túneles. El túnel en ejecución nunca la utiliza. Trátela como una contraseña, porque una copia de ese único archivo basta para que alguien publique nuevos nombres de host en su dominio.

cloudflared tunnel create homelab

Una ejecución correcta muestra las dos líneas siguientes. El UUID incluido en ellas es el valor que pegará en el archivo de configuración.

Tunnel credentials written to /home/you/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.
Created tunnel homelab with id 6ff42ae2-765d-4adf-8112-31c55c1551ef

Ese archivo JSON es la identidad del túnel y es la única credencial que necesita el servicio en ejecución. Cualquiera que lo tenga puede registrarse como su túnel y recibir su tráfico. No se puede rotar por separado: revocarlo significa cloudflared tunnel delete homelab y crear un túnel nuevo.

Mantenga el archivo de credenciales en una ubicación adecuada

El servicio se ejecuta como root, así que coloque el archivo en un directorio propiedad de root. No lo deje en un directorio personal al que pueda acceder un trabajo de copia de seguridad o una cuenta de inicio de sesión compartida.

sudo install -d -m 700 -o root -g root /etc/cloudflared
sudo install -m 600 -o root -g root \
  ~/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json \
  /etc/cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
rm ~/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
sudo ls -l /etc/cloudflared
cloudflared tunnel list

ls -l debería mostrar -rw------- root root en el archivo JSON. cloudflared tunnel list lee cert.pem, así que seguirá funcionando. También debería mostrar el nombre del túnel, su UUID y cuántas conexiones mantiene actualmente.

Escriba config.yml con reglas de ingress reales

Escriba la configuración en /etc/cloudflared/config.yml, no en su directorio personal. Esta es la razón. cloudflared service install copia cualquier configuración que encuentre en /etc/cloudflared/config.yml y después fija --config /etc/cloudflared/config.yml en la unidad de systemd. Si crea el archivo en ~/.cloudflared/config.yml, esa copia es una instantánea única. Las ediciones posteriores de la copia del directorio personal no cambian nada, el servicio sigue sirviendo las reglas antiguas y no se muestra ningún aviso. Crear el archivo directamente en su ubicación elimina todo el problema.

tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef
credentials-file: /etc/cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
loglevel: info

ingress:
  - hostname: app.example.com
    service: http://127.0.0.1:8080
  - hostname: files.example.com
    service: http://127.0.0.1:8081
  - hostname: grafana.example.com
    path: ^/api/
    service: http://127.0.0.1:3000
  - service: http_status:404

Las reglas se leen de arriba abajo y se aplica la primera coincidencia. Una regla sin hostname coincide con cualquier nombre de host, por lo que la regla general debe quedar al final. Si la omite, se rechaza la configuración con The last ingress rule must match all URLs (i.e. it should not have a hostname or path filter). http_status:404 es un servicio integrado que responde con 404 y no hace nada más. Es necesario: sin él, una petición para un nombre de host que nunca quiso publicar termina en la última regla real que haya quedado definida.

Use 127.0.0.1 en la URL de service: en lugar de localhost. En Ubuntu, localhost se resuelve primero en ::1 y una aplicación que sólo escucha en el loopback IPv4 rechaza esa conexión. La línea del registro es dial tcp [::1]:8080: connect: connection refused y el visitante recibe un 502.

El http:// simple es correcto aquí porque el salto no sale de la máquina. Use https:// sólo cuando la aplicación local requiera TLS (seguridad de la capa de transporte) y espere x509: certificate is valid for example.com, not localhost cuando su certificado no coincida con el nombre al que se conectó. Corríjalo con originServerName en originRequest o acepte el riesgo con noTLSVerify: true.

Compruebe las reglas antes de iniciar nada:

sudo cloudflared --config /etc/cloudflared/config.yml tunnel ingress validate
sudo cloudflared --config /etc/cloudflared/config.yml tunnel ingress rule https://app.example.com/login

ingress validate indica si la configuración es válida o identifica la regla que la invalida. ingress rule recibe una URL y muestra la primera regla que coincide con ella. Es la forma más rápida de comprobar que una expresión regular de path no coincide con lo que esperaba.

Apunte DNS al túnel

cloudflared tunnel route dns homelab app.example.com
cloudflared tunnel route dns homelab files.example.com
cloudflared tunnel route dns homelab grafana.example.com

Cada llamada escribe un registro CNAME con proxy que apunta a 6ff42ae2-765d-4adf-8112-31c55c1551ef.cfargotunnel.com. Ese destino sólo se resuelve dentro de la red de Cloudflare, por lo que la respuesta DNS pública para su nombre de host es una dirección de Cloudflare y la IP de su VPS nunca aparece en ella. Un comodín hostname en config.yml aún necesita un registro DNS coincidente para cada nombre que utilice realmente.

Cuando ya existe un registro, el comando falla de esta forma:

Failed to add route: code: 1003, reason: Failed to create record app.example.com with err An A, AAAA, or CNAME record with that host already exists.

Ese registro existente casi siempre es el antiguo registro A que apunta a la IP pública de su VPS. Ese es precisamente el registro que debe eliminar. Bórrelo en el panel de Cloudflare y vuelva a ejecutar el comando. Si lo deja, DNS seguirá publicando la IP de origen y el túnel no ocultará nada.

Instálelo como un servicio para que siga funcionando después de reiniciar

Ejecútelo una vez en primer plano, porque es mucho más fácil leer un error en su propia terminal que en el journal.

sudo cloudflared --config /etc/cloudflared/config.yml tunnel run homelab

Un inicio correcto registra varias líneas Registered tunnel connection, una por cada ubicación perimetral, cada una con su propio connIndex. Cargue uno de sus nombres de host en un navegador y confirme que las reglas de ingress le dirigen al destino esperado. Después, deténgalo con Ctrl-C.

sudo cloudflared --config /etc/cloudflared/config.yml service install
systemctl status cloudflared

Eso escribe /etc/systemd/system/cloudflared.service junto con cloudflared-update.service y cloudflared-update.timer. Después ejecuta systemctl enable cloudflared.service y systemctl start cloudflared.service automáticamente. enable es la parte importante aquí, porque es la que vuelve a iniciar el túnel después de un reinicio. El ExecStart de la unidad es cloudflared --no-autoupdate --config /etc/cloudflared/config.yml tunnel run. Por eso esa ruta de configuración no se puede cambiar.

Tres errores de este paso muestran mensajes exactos. possible conflicting configuration in /home/you/.cloudflared/config.yml and /etc/cloudflared/config.yml significa que existen ambos archivos y que cloudflared se niega a elegir: elimine el que no quiera usar. configuration file ... must contain entries for the tunnel to run and its associated credentials (tunnel: TUNNEL-UUID, credentials-file: CREDENTIALS-FILE) significa que la configuración usa la abreviatura quick url: en lugar de las claves del túnel con nombre. Esa abreviatura no se puede ejecutar como servicio. cloudflared service is already installed significa que todavía existe una unidad antigua. Ejecute primero sudo cloudflared service uninstall.

No existe ninguna recarga. Después de editar /etc/cloudflared/config.yml, ejecute sudo systemctl restart cloudflared. Después compruebe el reinicio en lugar de darlo por supuesto:

sudo reboot
# once it is back
systemctl is-enabled cloudflared
systemctl is-active cloudflared
journalctl -u cloudflared -n 50 --no-pager
curl -sI https://app.example.com

Que is-enabled muestre enabled y que is-active muestre active es el objetivo de toda esta sección. Cuando las rutas existan y el servicio esté en ejecución, cert.pem ya no tiene ninguna tarea adicional en el servidor: rm ~/.cloudflared/cert.pem. Si después añade un nombre de host, sólo tiene que ejecutar cloudflared tunnel login de nuevo.

Cierre 80 y 443, o el túnel será sólo una ruta adicional

Debe aplicar los dos cambios. Si aplica sólo uno, el origen seguirá siendo accesible.

Primero, vincule la aplicación a la dirección de loopback. En nginx, esto significa usar listen 127.0.0.1:8080; en lugar de listen 80;, como se explica en esta guía sobre la configuración de un reverse proxy con nginx. En Docker Compose, significa usar ports: - "127.0.0.1:8080:80". La forma simple "8080:80" publica en todas las interfaces. Docker crea sus propias reglas de NAT (traducción de direcciones de red), que los paquetes atraviesan antes de que ufw pueda verlos. Por eso, una regla de denegación de ufw no lo detendrá. Este problema se explica en por qué los puertos publicados por Docker ignoran ufw.

sudo ss -lntp

Cada servicio que haya movido debería mostrar ahora 127.0.0.1:8080 en la columna Local Address. Una línea que muestre 0.0.0.0:8080 o *:8080 todavía está escuchando conexiones desde cualquier origen.

Segundo, cierre los puertos.

sudo ufw status numbered
sudo ufw delete allow 'Nginx Full'
sudo ufw status

Elimine las reglas que permiten 80 y 443 en lugar de añadir reglas de denegación encima. ufw se detiene en la primera regla coincidente, por lo que una regla allow antigua situada más arriba tiene prioridad. Mantenga la regla de SSH. La guía básica del firewall ufw explica el resto de ese conjunto de reglas. La mayoría de los proveedores de VPS también ejecutan un firewall de red independiente en su panel de control. Ese firewall no es ufw, por lo que también debe cerrar allí 80 y 443.

Verifique ahora desde otro lugar, porque curl http://127.0.0.1:8080 en el propio servidor no demuestra nada sobre el acceso desde Internet.

# run these from a different machine
nc -vz 203.0.113.10 443
curl -sI https://app.example.com

El resultado esperado es un nc rechazado o agotado contra la IP directa, junto con un 200 mediante el nombre de host. Cómo comprobar si un puerto está realmente abierto explica otras formas de realizar la prueba.

El túnel proporciona transporte, no autenticación. Todo lo que publique mediante él será accesible públicamente si no coloca un inicio de sesión delante. Puede usar Cloudflare Access en el extremo o un proxy OAuth2 delante de la aplicación en el servidor. SSH también necesita su propia protección, porque el túnel no lo cubre: mantenga abierto el puerto 22, pero restrínjalo a sus propias direcciones de origen.

Qué ofrece Cloudflare Tunnel y cuáles son sus costes

Las ventajas son reales. La IP de origen deja de estar publicada, no se expone ningún puerto entrante, la configuración funciona incluso desde una máquina sin IP pública, el certificado público pasa a ser responsabilidad de Cloudflare, por lo que no se ejecuta ningún cliente ACME (entorno de gestión automática de certificados) en el servidor, y los ataques volumétricos se absorben en el perímetro en lugar de consumir el ancho de banda disponible.

Los costes también son reales. Cloudflare termina TLS en su perímetro: la petición del visitante se descifra allí y se vuelve a cifrar dentro del túnel, por lo que Cloudflare puede leer el tráfico. Esto permite usar su firewall, la caché y las reglas de Access. No hay ninguna configuración que lo desactive mientras siga utilizando su proxy. Si no acepta que un tercero tenga acceso al texto sin cifrar, deténgase aquí y elija otra opción.

Cloudflare también se convierte en una dependencia crítica para la accesibilidad. Cuando cloudflared no está conectado, los visitantes reciben la página de error 1033 de Cloudflare en lugar de su aplicación, y usted ha eliminado deliberadamente la ruta directa que podrían haber utilizado como alternativa.

Sólo HTTP, HTTPS y WebSocket pueden llegar a un nombre de host público desde un navegador común. Cualquier otro protocolo TCP, como SSH, RDP (protocolo de escritorio remoto) o un servidor de juegos, también necesita software en el lado del cliente: cloudflared access tcp para reenviar un puerto local o el cliente WARP. No existe una ruta para esos protocolos sin instalar un cliente.

El tamaño de los cuerpos de las peticiones está limitado en el perímetro, y una carga que supere el límite se rechaza con HTTP 413 antes de llegar a la aplicación. En agosto de 2026, el límite es de 100 MB en los planes Free y Pro, y superior en los niveles de pago. Consulte la página de límites actual de Cloudflare antes de diseñar una solución basada en un valor concreto. Las condiciones de autoservicio de Cloudflare también restringen el uso del proxy principalmente para servir vídeo y otros archivos grandes que no sean HTML. Conviene leerlas antes de dirigir una biblioteca multimedia a un túnel gratuito.

Cloudflare Tunnel, un túnel SSH inverso o Tailscale Funnel

Los tres funcionan sólo con conexiones salientes, por lo que pueden usarse desde un equipo sin puertos entrantes ni IP pública. Se diferencian en quién tiene acceso al texto sin cifrar y en el nombre de host que ve el público.

Un túnel SSH inverso necesita una segunda máquina con IP pública. Esa máquina se convierte en la puerta de entrada: usted se encarga de ejecutar allí el certificado, el proxy inverso y el firewall. Ningún tercero descifra el tráfico. Hay más componentes que administrar y necesita autossh o una unidad de systemd con Restart=always para sobrevivir a una interrupción breve de la red. El tutorial del túnel SSH inverso para CGNAT explica cómo configurarlo.

Tailscale Funnel es la comparación más cercana. También funciona sólo con conexiones salientes y TLS termina en su propia máquina, por lo que los relés de Tailscale nunca ven el texto sin cifrar. La limitación está en los nombres y los puertos: Funnel sólo sirve nombres bajo el dominio ts.net de su tailnet, y únicamente en 443, 8443 y 10000. La diferencia entre Tailscale Serve y Funnel explica ambos aspectos.

Por tanto, elija según la restricción que realmente le afecte. Elija Cloudflare Tunnel cuando el público deba acceder a su propio dominio y acepte que Cloudflare lea el tráfico. Elija Tailscale Funnel cuando un nombre de host ts.net sea aceptable y no quiera entregar el texto sin cifrar a un proxy. Elija un túnel SSH inverso cuando ya tenga un equipo público y no quiera que ningún tercero intervenga en la ruta.

FAQ

¿Necesito mantener abierto el puerto 443 con Cloudflare Tunnel?

No. cloudflared se conecta de salida a Cloudflare por el puerto 7844 y todas las peticiones regresan por esa conexión, por lo que no se usa ningún puerto de entrada. Sin embargo, la instalación del túnel no cierra nada automáticamente. Elimine las reglas de permiso para 80 y 443 en ufw, ciérrelos en el firewall de red independiente de su proveedor, vincule la aplicación a 127.0.0.1 y elimine cualquier registro A restante que siga publicando la IP de su VPS. Confirme el resultado con sudo ss -lntp en el servidor y con nc -vz <your-ip> 443 desde otra máquina.

¿Por qué mi nombre de host muestra el error 1033 de Cloudflare?

El error 1033 significa que Cloudflare conserva el registro DNS de ese nombre de host, pero no encuentra un cloudflared saludable conectado para recibir la petición. El proceso puede estar detenido, o puede estar en ejecución sin poder comunicarse con Cloudflare. Compruebe systemctl status cloudflared y journalctl -u cloudflared -n 50. Después, confirme que el puerto de salida 7844 esté permitido para UDP y TCP, ya que un firewall que bloquea UDP y QUIC sin permitir la alternativa TCP produce exactamente este error. cloudflared tunnel info homelab muestra las conexiones que Cloudflare detecta actualmente. Si la lista está vacía, el problema está en su lado.

¿Por qué obtengo un 502 Bad Gateway a través del túnel?

Un 502 significa que se alcanzó cloudflared, pero no se pudo alcanzar el servicio local. Por tanto, el fallo está entre esos dos componentes y no en Cloudflare. Lea el registro. dial tcp [::1]:8080: connect: connection refused significa que no hay nada escuchando donde indicó. El [::1] de ese mensaje suele indicar que escribió localhost en la URL service:, mientras la aplicación sólo está vinculada a IPv4. En ese caso, escriba http://127.0.0.1:8080. HTTP/1.x transport connection broken: malformed HTTP response indica la incompatibilidad opuesta: escribió https:// en un origen que utiliza HTTP sin cifrar.

¿Puedo ejecutar SSH, RDP o un servidor de juegos mediante Cloudflare Tunnel?

No con un cliente básico. Un nombre de host público a través de un túnel transporta HTTP, HTTPS y WebSocket, que son los protocolos que utiliza un navegador. Cualquier otro protocolo TCP también necesita software en la máquina cliente: cloudflared access tcp para reenviar un puerto local o el cliente WARP. Si quiere conectarse por SSH desde cualquier máquina sin instalar nada, el túnel no es la herramienta adecuada. Mantenga abierto el puerto 22 y restrínjalo por dirección de origen.

¿Cloudflare ve mi tráfico a través del túnel?

Sí. Cloudflare termina TLS en su edge, descifra allí la petición y la vuelve a cifrar dentro del túnel hacia su servidor. Ese descifrado permite que funcionen su firewall, el almacenamiento en caché y las políticas de Access. También significa que sus máquinas contienen los datos en texto plano. No existe ninguna configuración que lo evite mientras utilice su proxy. Si esto no es aceptable, use Tailscale Funnel o ejecute su propio reverse proxy en un servidor público.

#cloudflare-tunnel#cloudflared#zero-trust#firewall#self-hosting