6.6 KiB
Checklist: Añadir una nueva app
Cada vez que levantes un nuevo servicio que deba ser accesible desde internet, sigue estos pasos.
1. Registrar el dominio (DNS + Tunnel)
cd cloudflared
./add-domain.sh <subdominio>
Esto hace en un solo comando:
- Crea el registro DNS
<subdominio>.sherlockhomeless.net→ Cloudflare Tunnel (CNAME con proxy naranja) - Añade el hostname al ingress del tunnel →
http://traefik:80
Espera ~30 segundos para que Cloudflare propague el DNS.
2. Labels de Traefik en el docker-compose.yml
Añade estas labels al servicio que quieres exponer. Sustituye miapp por el nombre corto del servicio
y ${MI_DOMINIO} por la variable de entorno del dominio (ej. ${MIAPP_DOMAIN}).
Caso A — App pública con CrowdSec y sin login (APIs, webhooks)
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
traefik.http.routers.miapp.rule: "Host(`${MI_DOMINIO}`)"
traefik.http.routers.miapp.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.miapp.tls: "true"
traefik.http.routers.miapp.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.miapp.middlewares: "crowdsec-bouncer@file"
traefik.http.services.miapp.loadbalancer.server.port: "XXXX"
Caso B — App privada con CrowdSec + Authentik SSO (panel de admin, dashboards)
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
traefik.http.routers.miapp.rule: "Host(`${MI_DOMINIO}`)"
traefik.http.routers.miapp.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.miapp.tls: "true"
traefik.http.routers.miapp.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.miapp.middlewares: "crowdsec-bouncer@file,${TRAEFIK_AUTH_MIDDLEWARE}"
traefik.http.services.miapp.loadbalancer.server.port: "XXXX"
El orden importa: CrowdSec bloquea primero, luego Authentik autentica.
${TRAEFIK_AUTH_MIDDLEWARE}se resuelve aths-authentik@docker.
Caso C — App con su propio login (no necesita Authentik)
labels:
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
traefik.http.routers.miapp.rule: "Host(`${MI_DOMINIO}`)"
traefik.http.routers.miapp.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.miapp.tls: "true"
traefik.http.routers.miapp.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.miapp.middlewares: "crowdsec-bouncer@file"
traefik.http.services.miapp.loadbalancer.server.port: "XXXX"
Igual que el Caso A — CrowdSec siempre, Authentik solo cuando la app no tiene auth propia.
3. Variables de entorno obligatorias en .env
Incluye siempre estas variables en el .env local de la nueva app para que Docker Compose resuelva las labels:
##### Traefik / dominios #####
TRAEFIK_DOCKER_NETWORK=proxy
MIAPP_DOMAIN=miapp.sherlockhomeless.net
TRAEFIK_ENTRYPOINT_SECURE=websecure
TRAEFIK_CERTRESOLVER=letsencrypt
TRAEFIK_AUTH_MIDDLEWARE=ths-authentik@docker # solo si usas Caso B
Gotcha conocido: Traefik NO expande variables de entorno dentro de labels. Los valores como puertos y dominios que van dentro de
Host(...)deben estar ya resueltos cuando docker compose procesa el archivo. Usa variables de entorno solo donde docker compose las expande (fuera de las comillas de las labels si es un valor directo).
4. Configurar Authentik (solo Caso B)
Si usas ths-authentik@docker, Authentik debe conocer la app para que el outpost la sirva correctamente.
En el panel de Authentik (https://auth.sherlockhomeless.net):
-
Crear Provider → Applications → Providers → Create
- Tipo: Proxy Provider
- Name:
Mi App - External host:
https://miapp.sherlockhomeless.net - Authentication flow:
default-authentication-flow - Authorization flow:
default-provider-authorization-implicit-consent - Mode: Forward auth (single application)
-
Crear Application → Applications → Create
- Name:
Mi App - Slug:
miapp - Provider: el creado en el paso anterior
- Name:
-
Asociar al Embedded Outpost → Outposts →
authentik Embedded Outpost→ Edit- Añade la nueva aplicación a la lista de aplicaciones seleccionadas
- Guarda
Si no completas el paso 3, Authentik redirige al login pero luego da error 404.
5. Red Docker
El contenedor debe estar en la red proxy para que Traefik lo pueda alcanzar:
networks:
proxy:
external: true
# red interna opcional para bases de datos, etc.
miapp_internal:
driver: bridge
Y el servicio que expone la app debe tener:
services:
miapp:
networks:
- proxy
- miapp_internal # si tiene db
Los contenedores de base de datos u otros servicios internos solo necesitan la red interna,
no la red proxy.
6. Desplegar
cd miapp
docker compose --env-file .env up -d
Resumen visual
Nueva app
│
├── 1. ./cloudflared/add-domain.sh <sub> → DNS + Tunnel
│
├── 2. Labels en docker-compose.yml
│ ├── Caso A (pública) → crowdsec-bouncer@file
│ ├── Caso B (privada) → crowdsec-bouncer@file + ths-authentik@docker
│ └── Caso C (auth propia)→ crowdsec-bouncer@file
│
├── 3. Variables en .env
│
├── 4. Authentik Provider + App + Outpost (solo Caso B)
│
├── 5. Red proxy en docker-compose.yml
│
└── 6. docker compose --env-file .env up -d
Middlewares de referencia
| Middleware | Definido en | Qué hace |
|---|---|---|
crowdsec-bouncer@file |
/opt/traefik/dynamic/crowdsec-bouncer.yml |
Bloquea IPs baneadas por CrowdSec y filtra con AppSec WAF |
ths-authentik@docker |
Labels del stack authentik |
ForwardAuth hacia Authentik — requiere login SSO |
Gotchas conocidos
| # | Problema | Causa | Solución |
|---|---|---|---|
| 1 | Traefik no enruta la app | traefik.enable: "true" falta |
Añadir el label |
| 2 | Traefik no encuentra el contenedor | Contenedor no está en la red proxy |
Añadir red proxy al servicio |
| 3 | SSL no funciona | tls.certresolver mal escrito o dominio no existe en DNS |
Verificar DNS con dig miapp.sherlockhomeless.net |
| 4 | Authentik redirige pero da 404 | App no añadida al Embedded Outpost | Paso 4.3 |
| 5 | CrowdSec da 403 | IP baneada | docker exec crowdsec cscli decisions list — si apareces, cscli decisions delete --ip <tu-ip> |
| 6 | Variable no expandida en label | Traefik no expande vars en labels de docker; Docker Compose debe resolverlas antes | Definirla en .env y validar con docker compose --env-file .env config |