commit e7e40439eb188dfb0feddfed697c633a58a2fa51 Author: Cristhian Ulloa Date: Wed Oct 14 13:39:33 2026 -0600 traefik standalone adoption kit: live config versioned + compose + komodo panel router - traefik.yml/dynamic/* copied from /etc/dokploy/traefik (acme.json gitignored — stays on host) - compose.yaml: same image/binds/ports as dokploy-traefik, joins dokploy-network + komodo - dynamic/komodo.yml: komodo.paginica.com router (inactive until cutover) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..686015f --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# acme.json contiene la clave privada de la cuenta LE + claves de certs — +# jamás en git. Vive en /etc/dokploy/traefik/dynamic/acme.json (600). +acme.json +dynamic/acme.json +dynamic-backups/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..4198ec1 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# traefik — reverse proxy de VPS2 (adopción standalone) + +Traefik v3.6.25 que hoy corre como `dokploy-traefik` (instalado por +Dokploy pero es infra compartida). Este repo versiona la config para +que el container pase a ser standalone/Komodo-managed. + +## Layout en el VPS (fuente de verdad hoy) + +``` +/etc/dokploy/traefik/traefik.yml → /etc/traefik/traefik.yml (bind ro) +/etc/dokploy/traefik/dynamic/ → file provider (watch: true) +/etc/dokploy/traefik/dynamic/acme.json ← NUNCA en git (LE keys) +/etc/dokploy/traefik/dynamic-backups/ ← backups del panel-gate +``` + +## Config versionada aquí + +- `traefik.yml` — providers swarm+docker (`exposedByDefault:false`, + network `dokploy-network`), file provider `dynamic/`, web :80, + websecure :443 + HTTP/3, `api.insecure` (dashboard solo interno), + ACME `letsencrypt` httpChallenge@web, storage `dynamic/acme.json`. +- `dynamic/middlewares.yml` — `redirect-to-https`. +- `dynamic/authentik-forwardauth.yml` — `ak-fw`/`ak-fw-errors` (ForwardAuth + contra el outpost embebido `authentik-server:9000`), bypass `/api` + + `/outpost.goauthentik.io` por host, services `ak-*`. +- `dynamic/dokploy.yml` — routers del panel Dokploy + (**reemplazar por `komodo.yml` al cutover del panel**). + +## Procedimiento de adopción (gate humano — toca puertos públicos) + +1. Este repo ya refleja la config viva (copiada del VPS). +2. `docker stop dokploy-traefik` → `docker compose up -d` con + `compose.yaml` (o stack Komodo git-sourced contra este repo). +3. Verificar: `curl` a cada dominio público + cert LE válido + TCP + passthrough de mail + ak-fw redirige a authentik. +4. Rollback: `docker stop` el standalone → `docker start dokploy-traefik`. + +Tras la adopción, Dokploy sigue gestionando compose/apps pero ya NO el +proxy — la propiedad del routing pasa a este repo antes del desmontaje. + +## Pendiente conocido + +- `dokploy-network` es una red creada por Dokploy — si el desmontaje la + borra, recrearla como `external`/`docker network create` antes (los + composes ya la referencian). Alternativa: renombrar a `proxy` en una + fase posterior (toca los 6 stacks — diferir). +- `api.insecure` expone el dashboard solo dentro del docker socket/net; + considerar `api.dashboard` detrás de ak-fw o desactivarlo post-migración. +- `panel.paginica.com` → Komodo: ver `backlog/01_komodo.md` Fase C. diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..59628bd --- /dev/null +++ b/compose.yaml @@ -0,0 +1,30 @@ +# Standalone Traefik — adopción del traefik que hoy maneja Dokploy. +# Misma imagen, mismos binds, mismos puertos. Desplegar SOLO al cortar: +# 1. docker stop dokploy-traefik +# 2. docker compose -f compose.yaml up -d (desde este repo, o vía Komodo stack) +# La config vive en /etc/dokploy/traefik (binds idénticos → cero churn de +# acme.json/certs). Post-decommission de Dokploy se puede mover a /etc/traefik +# (acme.json se copia con perms 600, nunca entra a git). +name: traefik + +services: + traefik: + image: traefik:v3.6.25 + restart: unless-stopped + ports: + - "80:80" + - "443:443" + - "443:443/udp" # HTTP/3 (websecure advertisedPort 443) + volumes: + - /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml:ro + - /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + - dokploy-network + - komodo # alcanza core:9120 para el router del panel Komodo + +networks: + dokploy-network: + external: true + komodo: + external: true # red del stack /opt/komodo diff --git a/dynamic/authentik-forwardauth.yml b/dynamic/authentik-forwardauth.yml new file mode 100644 index 0000000..bd154bb --- /dev/null +++ b/dynamic/authentik-forwardauth.yml @@ -0,0 +1,93 @@ +# Traefik dynamic config — forward auth via authentik embedded outpost. +# Deploy to: /etc/dokploy/traefik/dynamic/authentik-forwardauth.yml +# All objects carry the `ak-` prefix; this file is never managed by Dokploy. +# +# Bypass model: the gated Host router (managed by Dokploy domain middlewares) +# covers UI paths only. More-specific rules win automatically: +# Host + PathPrefix(`/outpost.goauthentik.io`) -> outpost (auth callbacks) +# Host + PathPrefix(`/api`) -> app API (CLI/SDK/agents/UI fetches) +http: + services: + ak-authentik: + loadBalancer: + servers: + - url: http://authentik-server:9000 + passHostHeader: true + ak-dokploy: + loadBalancer: + servers: + - url: http://dokploy:3000 + passHostHeader: true + ak-infisical: + loadBalancer: + servers: + - url: http://infisical:8080 + passHostHeader: true + + middlewares: + ak-fw: + forwardAuth: + # embedded outpost reachable internally — no Cloudflare roundtrip + address: http://authentik-server:9000/outpost.goauthentik.io/auth/traefik + trustForwardHeader: true + authResponseHeaders: + - X-authentik-username + - X-authentik-groups + - X-authentik-email + - X-authentik-name + - X-authentik-uid + - X-authentik-jwt + - X-authentik-meta-jwks + - X-authentik-meta-outpost + - X-authentik-meta-provider + - X-authentik-meta-app + - X-authentik-meta-version + ak-fw-errors: + # turns the outpost 401 into its login redirect for browsers; + # machine paths bypass via dedicated routers and never see this + errors: + status: ["401-403"] + service: ak-authentik + query: /outpost.goauthentik.io/start?rd={url} + + routers: + # Outpost endpoints on each gated host (forward_single mode needs these + # public: start/callback/sign_out live on the application domain). + ak-infisical-outpost: + rule: Host(`infisical.paginica.com`) && PathPrefix(`/outpost.goauthentik.io`) + service: ak-authentik + entryPoints: [websecure] + tls: + certResolver: letsencrypt + priority: 1000 + ak-panel-outpost: + rule: Host(`panel.paginica.com`) && PathPrefix(`/outpost.goauthentik.io`) + service: ak-authentik + entryPoints: [websecure] + tls: + certResolver: letsencrypt + priority: 1000 + + + + # Infisical API bypass — UI fetches, CLI, SDK, agentes y syncs usan /api + # con tokens propios de Infisical; gated /api romperia el propio web vault. + ak-infisical-api: + rule: Host(`infisical.paginica.com`) && PathPrefix(`/api`) + service: ak-infisical + entryPoints: [websecure] + tls: + certResolver: letsencrypt + priority: 900 + + # Panel API bypass — keeps /api (tRPC, better-auth, deploy webhooks) + # outside the auth gate. Higher priority than the gated root router. + ak-panel-api: + rule: Host(`panel.paginica.com`) && PathPrefix(`/api`) + service: ak-dokploy + entryPoints: [websecure] + tls: + certResolver: letsencrypt + priority: 900 + + diff --git a/dynamic/dokploy.yml b/dynamic/dokploy.yml new file mode 100644 index 0000000..797754c --- /dev/null +++ b/dynamic/dokploy.yml @@ -0,0 +1,30 @@ +http: + routers: + dokploy-router-app: + rule: Host(`dokploy.docker.localhost`) && PathPrefix(`/`) + service: dokploy-service-app + entryPoints: + - web + dokploy-router-app-web: + rule: Host(`panel.paginica.com`) && PathPrefix(`/`) + service: dokploy-service-app + entryPoints: + - web + middlewares: + - redirect-to-https + dokploy-router-app-secure: + rule: Host(`panel.paginica.com`) && PathPrefix(`/`) + service: dokploy-service-app + entryPoints: + - websecure + middlewares: + - ak-fw-errors + - ak-fw + tls: + certResolver: letsencrypt + services: + dokploy-service-app: + loadBalancer: + servers: + - url: http://dokploy:3000 + passHostHeader: true diff --git a/dynamic/komodo.yml b/dynamic/komodo.yml new file mode 100644 index 0000000..d7303c0 --- /dev/null +++ b/dynamic/komodo.yml @@ -0,0 +1,36 @@ +# Router del panel Komodo — REEMPLAZA a dokploy.yml en el cutover del +# panel (backlog/01 Fase C). No activar mientras dokploy.yml exista con +# el mismo Host (colisión de routers). +# +# komodo.paginica.com = dominio temporal del panel. +# panel.paginica.com se reasigna al retirar Dokploy (mismo Host menos +# churn): descomentar el segundo Host en ambas reglas entonces. +# +# Requiere: traefik adjunto a la red externa `komodo` (compose.yaml) — +# core:9120 se resuelve por DNS del compose project `komodo`. +http: + routers: + komodo-web: + rule: Host(`komodo.paginica.com`) && PathPrefix(`/`) + service: komodo-core + entryPoints: + - web + middlewares: + - redirect-to-https + komodo-websecure: + rule: Host(`komodo.paginica.com`) && PathPrefix(`/`) + service: komodo-core + entryPoints: + - websecure + # ak-fw NO se aplica: el panel usa OIDC nativo + local-auth de + # rescate (blueprint 22-komodo-oidc). Gatillar el panel del + # orquestador con ForwardAuth crearía una dependencia circular + # si authentik se migra en el stack 6 — se evalúa de nuevo entonces. + tls: + certResolver: letsencrypt + services: + komodo-core: + loadBalancer: + servers: + - url: http://core:9120 + passHostHeader: true diff --git a/dynamic/middlewares.yml b/dynamic/middlewares.yml new file mode 100644 index 0000000..d0e65b6 --- /dev/null +++ b/dynamic/middlewares.yml @@ -0,0 +1,6 @@ +http: + middlewares: + redirect-to-https: + redirectScheme: + scheme: https + permanent: true diff --git a/traefik.yml b/traefik.yml new file mode 100644 index 0000000..1576ed0 --- /dev/null +++ b/traefik.yml @@ -0,0 +1,32 @@ +global: + sendAnonymousUsage: false +providers: + swarm: + exposedByDefault: false + watch: true + docker: + exposedByDefault: false + watch: true + network: dokploy-network + file: + directory: /etc/dokploy/traefik/dynamic + watch: true +entryPoints: + web: + address: :80 + websecure: + address: :443 + http3: + advertisedPort: 443 + http: + tls: + certResolver: letsencrypt +api: + insecure: true +certificatesResolvers: + letsencrypt: + acme: + email: contact@cristhiannica.com + storage: /etc/dokploy/traefik/dynamic/acme.json + httpChallenge: + entryPoint: web