Skip to content

tunnel-sync — declarative routing (cloudflared + Caddyfile)

⚠️ Histórico: tunnel-sync.py fue reemplazado por homelab-ctl.py (ver services-routing). Se conserva como referencia.

/home/monxas/scripts/tunnel-sync.py

Reconcilia las labels tunnel.* de containers Docker con: - cloudflared tunnel ingress — siempre formato unificado https://192.168.0.208:443 + noTLSVerify + originServerName - Caddyfile — bloques dentro de # BEGIN tunnel-sync managed ... # END (no toca lo de fuera) - Sablier middleware opcional con tunnel.lazy=true

Bloques manuales fuera de la sección managed se respetan (e.g., los hostnames lazy añadidos a mano).

Comandos

python3 ~/scripts/tunnel-sync.py status       # ver desired vs estado actual + colisiones
python3 ~/scripts/tunnel-sync.py sync         # aplicar (pregunta confirmación)
python3 ~/scripts/tunnel-sync.py sync --yes   # aplicar sin confirmación
python3 ~/scripts/tunnel-sync.py remove HOST  # quitar HOST de tunnel + Caddyfile managed

Labels

Label Required Default Notas
tunnel.hostname FQDN. Comma-sep para varios hostnames apuntando al mismo container (e.g., krawl).
tunnel.port no primer puerto host publicado Puerto host del container.
tunnel.lazy no false Si true, mete sablier middleware.
tunnel.lazy.names no nombre del container Comma-sep, containers que sablier debe arrancar juntos.
tunnel.lazy.theme no shuffle ghost / hacker-terminal / matrix / shuffle.
tunnel.lazy.session_duration no 30m Tiempo idle antes de parar.
tunnel.lazy.display_name no nombre del container Texto en la waiting page.

Ejemplos

Servicio simple

services:
  miapp:
    image: example/app
    ports:
      - 8080:80
    labels:
      - tunnel.hostname=miapp.monxas.casa

Servicio lazy (Sablier)

services:
  paperless:
    image: paperlessngx/paperless-ngx
    ports:
      - 8000:8000
    labels:
      - tunnel.hostname=paperless.monxas.casa
      - tunnel.lazy=true
      - tunnel.lazy.names=paperless,paperless-db,paperless-redis
      - tunnel.lazy.display_name=Paperless
  paperless-db:
    image: postgres:16
  paperless-redis:
    image: redis:7

Multi-hostname (krawl honeypot)

services:
  krawl:
    labels:
      - tunnel.hostname=admin.monxas.casa,panel.monxas.casa,login.monxas.casa
      - tunnel.port=5050

Workflow nuevo servicio

  1. Añadir labels al compose.yaml del stack.
  2. docker compose up -d para que el container arranque con las labels.
  3. python3 ~/scripts/tunnel-sync.py status para ver el cambio detectado.
  4. python3 ~/scripts/tunnel-sync.py sync para aplicar (tunnel + Caddyfile + reload).

Garantías

  • Idempotente: sync con mismas labels no hace cambios.
  • Caddyfile validate tras escribir: si falla, revierte automáticamente al backup.
  • Backup Caddyfile en Caddyfile.bak-<timestamp> antes de cada cambio.
  • Tunnel API: PUT solo si hay drift detectado.
  • Restart vs reload Caddy: si el sync introduce sablier middleware nuevo, hace compose down + up (el plugin Sablier cachea estado y caddy reload no lo recoge). Resto de cambios usan caddy reload.

Colisiones

status reporta hostnames que tienen bloque manual fuera de la sección managed. sync los elimina y los regenera dentro (migración one-time, idempotente desde entonces).

Troubleshooting

Problema Solución
❌ Caddyfile validation failed; reverted Revisa la última edición + label malformada. Backup en Caddyfile.bak-*.
Status muestra container con no published port Añade tunnel.port=<host_port> o publica el puerto en compose.
Tunnel drift no se aplica Verifica CF_API_TOKEN en .env y permisos Account:Cloudflare Tunnel:Edit.
Cambios sablier no surten efecto Sablier plugin cachea: cd ~/stacks/reverse-proxy && docker compose down && up -d.

Anteriormente

tunnel-sync.sh (bash, 428 líneas, 2026-01) — emitía ingress directo http://208:port, contradice arquitectura unificada. Movido a .deprecated-20260425 el día del replace. Si necesitas referencia: /home/monxas/scripts/archive-20260428/tunnel-sync.sh.deprecated-20260425.

Reference