Como lidiar con CGNAT y exponer tus aplicaciones locales usando Cloudflare Tunnels
Muchas veces nos encontramos en la situación de ser clientes de un proveedor de internet (ISP) que debido a la escasez de IPv4 (guiño), tiene >1000 clientes detrás de una sola IP pública, es decir el ISP usa Carrier Grade NAT (CGNAT), por lo que abrir puertos de tu router resulta una tarea imposible.

Por suerte tenemos varias opciones para acceder a nuestros servicios locales si estamos detrás de una CGNAT, como usar un VPS (Servidor Virtual Privado) de un proveedor como AWS, Google Cloud, Linode, etc. Para redirigir tu trafico mediante esa IP publica o mediante una VPN. Sin embargo el servicio puede llegar a ser costoso a largo plazo, sin mencionar que no todos los planes básicos ofrecen tráfico ilimitado.
En esta ocasión vamos a utilizar una forma bastante práctica para los entusiastas que no quieren usar un VPS de los proveedores mas populares como Google Cloud, AWS, entre otros.
Estoy hablando de Clouflare Tunnels , un servicio que permite exponer nuestros servicios locales a través de internet sin necesidad de una IP publica.
Como funciona:

Cloudflared es un cliente que establece conexiones salientes entre los recursos de nuestro servidor local y la red global de Cloudflare. Dicho cliente esta disponible para macOS, Linux, imagen de Docker y windows.
Los requisitos para usar CT son:
- Dominio (Cualquier dominio, de preferencia adquirido en cloudflare)
- Cliente (Linux, Windows, macOS)
Utilizaremos CT para exponer nuestro servidor de VaultWarden, un servidor alternativo y de código abierto del gestor de contraseñas Bitwarden
Registro en Cloudflare

Vamos a registrarnos con Google, Apple o con correo electrónico.
Cloudflare Dashboard

Compra de dominio
Creación del tunnel
Hay dos formas de crear túneles, a través de la dashboard de cloudflare o mediante la API.
Dashboard
API
Paso 1: Crear un API TOKEN
Dirigirse a User API Tokens, en el dashoard de Cloudflare:

Crear API TOKEN con los siguientes permisos:
| Tipo | Item | Permiso |
|---|---|---|
| Account | Cloudflare Tunnel | Edit |
| Zone | DNS | Edit |
Seleccionamos “Custom token”:

Asignamos los permisos necesarios:

Continuar y crear:

Token creado:

Probando el token con CURL:
#!/bin/bash
# Petición para probar token generado con CURL
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer TU_TOKEN_AQUI" \
-H "Content-Type:application/json"
Response:
{
"result": { "id": "cd8b1ee8831fe5f17207d680301994a7", "status": "active" },
"success": true,
"errors": [],
"messages": [
{
"code": 10000,
"message": "This API Token is valid and active",
"type": null
}
]
}
Todo correcto. Una vez tengamos el token podemos empezar a crear los tuneles.
Paso 2: Crear un tunnel
Haremos una petición de tipo POST al endpoint de Cloudflare:
Parametros requeridos:
- $CLOUDFARE_API_TOKEN
- $ACCOUNT_ID -> Como ver account_id?
#!/bin/bash
# Petición para crear el tunnel
curl 'https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/cfd_tunnel' \
--header 'Content-Type: application/json' \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--data '{
"name": "api-tunnel",
"config_src": "cloudflare"
}'
Response:
{
"success": true,
"errors": [],
"messages": [],
"result": {
"id": "[REDACTED_TUNNEL_ID]",
"account_tag": "[REDACTED_ACCOUNT_TAG]",
"created_at": "2025-04-15T23:43:04.876882Z",
"deleted_at": null,
"name": "api-tunnel",
"connections": [],
"conns_active_at": null,
"conns_inactive_at": "2025-04-15T23:43:04.876882Z",
"tun_type": "cfd_tunnel",
"metadata": {},
"status": "inactive",
"remote_config": true,
"credentials_file": {
"AccountTag": "[REDACTED_ACCOUNT_TAG]",
"TunnelID": "[REDACTED_TUNNEL_ID]",
"TunnelName": "api-tunnel",
"TunnelSecret": "[REDACTED_SECRET]"
},
"token": "[REDACTED_TOKEN]"
}
}
Importante copiar el token y result->id. Son necesarios para configurar el tunnel.
Paso 3: Conectar nuestra red privada al tunnel
Creamos una ruta para el tunel:
Parámetros requeridos:
- $ACCOUNT_ID
- $CLOUDFLARE_API_TOKEN
- $TUNNEL_ID
curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/teamnet/routes \
--header 'Content-Type: application/json' \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--data '{
"network": "172.16.0.0/16", #La misma que nuestra red interna
"tunnel_id": '$TUNNEL_ID',
"comment": "Ruta de ejemplo a red privada"
}'
Response:
{
"result": null,
"success": false,
"errors": [
{
"code": 7003,
"message": "Could not route to /client/v4/accounts/df84a7ab8eec86cb474e9bc6d88c5d3/teamnet/routes, perhaps your object identifier is invalid?"
}
],
"messages": []
}
Posibles problemas y restricciones
- El ISP bloquea rangos de IP de Cloudflare: Últimamente algunos proveedores, debido a la piratería, sobre todo de retransmisión de partidos de fútbol. En su afán de combatir la piratería han tomado la desesperada acción de bloquear rangos de IP completos. Dejando fuera de linea no solo los sitios piratas sino todo tipo de servicio que esté detrás de Cloudflare.
- Cloudflare en su plan básico no acepta subidas de más de 100 MB, personalmente he tenido problemas al usar Immich