Cloudflare Tunnel (cloudflared)
Conecta el servidor a Cloudflare sin abrir puertos. Todo el tráfico entra por la red de Cloudflare,
llega al contenedor cloudflared, y este lo reenvía a Traefik.
Internet → Cloudflare Edge → cloudflared → Traefik → servicios
Ventajas sobre exposición directa:
- Tu IP pública nunca es visible — CrowdSec solo ve IPs de Cloudflare (allowlisteadas)
- Funciona desde redes con CGNAT, CG-NAT corporativo o sin IPv4 fija
- Cloudflare absorbe DDoS y filtra bots antes de que lleguen al servidor
Estado actual: el tunnel está parado (
docker stop cloudflared). Los DNS apuntan directo a193.70.84.224(registros A, sin proxy Cloudflare). Ver sección Activar / desactivar el tunnel.
Configuración inicial (una sola vez)
1. Crear el tunnel en Cloudflare
- Ve a dash.cloudflare.com → Zero Trust → Networks → Conectores
- Create connector → nombre:
homeserver - Selecciona Docker → copia el token (cadena larga tras
--token)
2. Crear un API Token
En dash.cloudflare.com → My Profile → API Tokens → Create Token
Permisos mínimos necesarios:
| Scope | Recurso | Permiso |
|---|---|---|
| Account | Cloudflare Tunnel | Edit |
| Zone | DNS (sherlockhomeless.net) | Edit |
El API Token también lo usa
add-domain.shen modo directo (solo necesita Zone > DNS > Edit).
3. Configurar el .env
nano .env
Variables obligatorias para ambos modos:
CLOUDFLARE_API_TOKEN=<token del paso 2>
CLOUDFLARE_ZONE_ID=f7c4e16f9a434a947ad0f266b2e1f894
CLOUDFLARE_DOMAIN=sherlockhomeless.net
CLOUDFLARE_SERVER_IP=193.70.84.224 # IP para registros A directos
Variables adicionales solo necesarias con tunnel activo:
CLOUDFLARE_TUNNEL_TOKEN=<token del paso 1>
CLOUDFLARE_ACCOUNT_ID=328f4b942827169b11f7d1f11c640522
CLOUDFLARE_TUNNEL_ID=d405a2a2-69a1-40f1-b939-04cea5d60a50
Añadir un nuevo subdominio
Modo directo (sin tunnel, estado actual)
Crea un registro A apuntando a la IP del servidor, sin proxy de Cloudflare:
cd cloudflared
./add-domain.sh immich
./add-domain.sh immich recipes calibre # varios a la vez
El script:
- Detecta la IP del servidor desde
CLOUDFLARE_SERVER_IP(o la autodetecta viaapi.ipify.org) - Crea o actualiza el registro DNS
Acon proxy desactivado (nube gris)
Modo tunnel (cuando el tunnel esté activo)
Crea un registro CNAME al tunnel con proxy naranja y añade el hostname al ingress:
cd cloudflared
./add-domain.sh --tunnel immich
./add-domain.sh --tunnel immich recipes calibre
El script:
- Lee el ingress actual del tunnel desde la API de Cloudflare
- Añade el hostname apuntando a
https://traefik:443(noTLSVerify) - Guarda el ingress actualizado
- Crea o actualiza el registro DNS
CNAMEcon proxy naranja
Activar / desactivar el tunnel
Activar
# 1. Levantar el contenedor
cd cloudflared
docker compose --env-file .env up -d
# 2. Migrar los DNS al tunnel (convierte A records → CNAME proxied)
./add-domain.sh --tunnel auth traefik gitea n8n nextcloud paperless paperless-ai \
notas memos vikunja karakeep kasm remote beszel dozzle crowdsec grafana llm \
ocode adblock onlyoffice www cockpit coolify kopia notes portainer \
uptimekuma webtop wg
# 3. Verificar conexión
docker logs cloudflared | grep "Registered tunnel"
Desactivar
# 1. Parar el contenedor (no se levantará solo al reiniciar)
docker stop cloudflared
# 2. Revertir DNS a registros A directos
./add-domain.sh auth traefik gitea n8n nextcloud paperless paperless-ai \
notas memos vikunja karakeep kasm remote beszel dozzle crowdsec grafana llm \
ocode adblock onlyoffice www cockpit coolify kopia notes portainer \
uptimekuma webtop wg
Subdominios registrados
| Subdominio | Servicio |
|---|---|
auth |
Authentik SSO |
traefik |
Traefik Dashboard |
gitea |
Gitea |
n8n |
n8n |
nextcloud |
Nextcloud |
paperless |
Paperless-ngx |
paperless-ai |
Paperless AI |
notas |
Trilium |
memos |
Memos |
vikunja |
Vikunja |
karakeep |
Karakeep |
kasm |
Kasm Workspaces |
remote |
Guacamole |
beszel |
Beszel |
dozzle |
Dozzle |
crowdsec |
CrowdSec Grafana |
grafana |
Grafana |
llm |
LiteLLM |
ocode |
OpenCode |
adblock |
AdGuard |
onlyoffice |
OnlyOffice |
www |
Homepage |
cockpit |
Cockpit |
coolify |
Coolify |
kopia |
Kopia |
notes |
Notes |
portainer |
Portainer |
uptimekuma |
Uptime Kuma |
webtop |
Webtop |
wg |
WireGuard |
Comandos útiles
# Ver estado del tunnel
docker logs cloudflared
# Ver todos los subdominios en DNS de Cloudflare
curl -s "https://api.cloudflare.com/client/v4/zones/${CLOUDFLARE_ZONE_ID}/dns_records?per_page=100" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" | \
python3 -c "import sys,json; [print(r['type'].ljust(6), r['name']) for r in json.load(sys.stdin)['result']]"
# Ver ingress del tunnel configurado en Cloudflare
curl -s "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/cfd_tunnel/${CLOUDFLARE_TUNNEL_ID}/configurations" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" | \
python3 -c "import sys,json; [print(r.get('hostname','*'), '->', r['service']) for r in json.load(sys.stdin)['result']['config']['ingress']]"
Seguridad
- API Token: permisos mínimos (Tunnel Edit + DNS Edit). Rótalo periódicamente.
- Tunnel Token: si se compromete, regénéralo en el dashboard y reinicia el contenedor con el nuevo token en
.env. - CrowdSec con tunnel activo: las IPs de Cloudflare están en la allowlist
cloudflare. El bouncer usaforwardedHeadersTrustedIPscon los rangos de CF para ver la IP real del cliente. - CrowdSec sin tunnel: el bouncer ve la IP pública directa del cliente. El bot de Telegram (
/allow <ip>) puede desbanear y allowlistear en CrowdSec, fail2ban y firewalld simultáneamente.