Publicar un nuevo servicio en *.savethemall.eu¶
Traducción automática del original francés.
Procedimiento completo para publicar un servicio en un nombre público, protegido por Authentik. Requiere aproximadamente treinta minutos, incluyendo el tiempo de propagación DNS.
En todo lo siguiente, sustituya monservice por el subdominio deseado y monservice:8080 por el nombre del servicio Compose y su puerto.
Lo que se asume que el procedimiento ya conoce
- El contenedor está en funcionamiento y responde a través de HTTP en
infrastructure_network. - Le contrôle : depuis vm-docker,
docker exec caddy wget -qO- http://monservice:8080/ | head -5. Si cette commande ne rend rien, s'arrêter ici : rien de ce qui suit ne compensera un upstream muet.
L'ordre, et pourquoi il n'est pas négociable¶
flowchart TB
A["1 · Record A chez OVH"]
B["2 · Certificat acme.sh<br/>validation DNS-01"]
C["3 · Provider + application<br/>Authentik"]
D["4 · Bloc Caddy vm-docker"]
E["5 · Bloc Caddy nas-caddy"]
F["6 · Secrets, s'il y en a"]
G["7 · decisions.md, commit"]
A -->|"sans le record,<br/>la validation DNS-01 échoue"| B
B -->|"sans le cert, `caddy validate`<br/>refuse et le reload COUPE<br/>les 76 autres sites"| D
C -->|"l'app doit exister,<br/>sinon 404 au lieu de 302"| D
D -->|"le cert doit être copié<br/>sur le NAS"| E
E --> G
F --> G
B -.->|"rsync quotidien<br/>ou déclenché à la main"| E
classDef risk stroke-width:3px
class D risk
La seule étape qui peut casser autre chose est la 4 : le Caddy de vm-docker porte
76 vhosts, et un rechargement sur une configuration invalide les couche tous. D'où
caddy validate avant tout restart, et le certificat avant le bloc.
1. Registro de DNS en OVH¶
Siempre primero. acme.sh valida en DNS-01: sin el registro, la emisión del certificado falla, y el fallo se interpreta como un problema con los identificadores.
ssh -p <port-ssh> <user>@vm-docker \
"sudo /docker-mounts/homelab-vault/00-infra/scripts/ovh-record.sh \
add savethemall.eu A monservice <IP publique> --apply"
Control
Especialmente no el resolutor local: el DNS interno ya responde para este nombre, mediante alias, y daría una confirmación falsa.
Y tampoco los servidores autoritativos de OVH —ns.ovh.net y dns1.ovh.net no responden a las solicitudes directas desde este parque (medido el 29-08-2026 desde vm-claude y desde el VPS: communications error … timed out). Un resolutor público ya ha realizado la tarea.
2. Certificado TLS¶
Añadir el dominio a la lista de emisión — esta es la que se leerá en el próximo despliegue completo — y luego emitir el certificado por separado.
# 1. inscrire le domaine dans la liste
ssh -p <port-ssh> <user>@vm-docker \
"grep -q 'monservice.savethemall.eu' /opt/docker/acme/issue-all.sh || \
sed -i 's|^)| monservice.savethemall.eu\n)|' /opt/docker/acme/issue-all.sh"
# 2. émettre ce seul certificat
ssh -p <port-ssh> <user>@vm-docker \
"docker exec acme acme.sh --issue --dns dns_ovh -d monservice.savethemall.eu \
--cert-file /certs/monservice.savethemall.eu/cert.pem \
--key-file /certs/monservice.savethemall.eu/privkey.pem \
--fullchain-file /certs/monservice.savethemall.eu/fullchain.pem \
--reloadcmd \"curl -sf -X POST http://127.0.0.1:2019/load \
-H 'Content-Type: text/caddyfile' \
--data-binary @/etc/caddy/Caddyfile\""
--dnssleep es obligatorio aquí, y la razón no es en OVH
Sin él, la emisión falla sistemáticamente en:
acme.sh verifica su registro TXT a través de DoH en cloudflare-dns.com, y AdGuard resuelve este nombre en 0.0.0.0: el filtrado anti-evasión de DNS de la casa bloquea su propia herramienta de emisión. Sin embargo, el TXT está correctamente configurado en OVH, y luego eliminado correctamente, lo que provoca un fallo que parece ser un problema de identificadores o de propagación.
El control que se divide en una instrucción:
docker exec acme sh -c 'nslookup cloudflare-dns.com | tail -3'
# Address: 0.0.0.0 → c'est AdGuard, pas OVH
--dnssleep reemplaza la verificación con una espera fija. Esto es la evasión; la solución es permitir cloudflare-dns.com en AdGuard.
Control
El NAS recibe su copia a las rsync diarias. Para no esperar, se puede activar manualmente antes del paso 5.
3. Aplicación y proveedor en Authentik¶
En la interfaz de administración:
- Aplicaciones → Proveedores → Crear → Proveedor Proxy
- Modo: Forward auth (para una sola aplicación) — no Proxy, ni Nivel de dominio.
- Host externo:
https://monservice.savethemall.eu - Flujo de autorización: el del parque (consentimiento implícito).
- Aplicaciones → Crear
- Slug:
monservice - Proveedor: el que se ha creado
- Icono: buscar el logotipo oficial antes de crear la aplicación. En orden: el repositorio de GitHub del proyecto, el
/favicon.svgdel sitio oficial,https://cdn.simpleicons.org/<nom>, y luego el catálogohttps://cdn.jsdelivr.net/gh/selfhst/icons/svg/<nom>.svg.
- Slug:
- Aplicaciones → Zonas →
authentik Embedded Outpost→ Editar → Aplicaciones- Añadir la aplicación manualmente.
El enclave integrado no recupera la aplicación por sí solo
Esta es la omisión más común de este procedimiento. Sin este añadido explícito, todo está correctamente configurado en Authentik, Caddy dirige correctamente al flujo de conexión, y la conexión falla de todos modos — sin mensaje que indique la causa.
4. Bloque Caddy en vm-docker¶
Editar 10-stacks/caddy/Caddyfile en el cofre, y luego sincronizar. El archivo del cofre no es un enlace simbólico: ambas copias son reales y son diferentes si se olvidan.
monservice.savethemall.eu {
import tls_cert monservice.savethemall.eu
# Endpoints de l'outpost embarqué (sign_out, start, callback) → Authentik
handle /outpost.goauthentik.io/* {
reverse_proxy authentik-server:9000
}
handle {
import authentik
reverse_proxy monservice:8080
}
}
El orden de los dos handle no es decorativo: ver forward_auth antes de handle.
Sincronización, obligatoria después de cualquier edición:
ssh -p <port-ssh> <user>@vm-docker \
"cp /docker-mounts/homelab-vault/10-stacks/caddy/Caddyfile /opt/docker/caddy/Caddyfile && \
docker compose -f /opt/docker/caddy/docker-compose.yml restart"
Control — en LAN, donde el DNS ya apunta a vm-docker
curl -s -o /dev/null -w '%{http_code}\n' https://monservice.savethemall.eu/
# 302 vers auth.savethemall.eu → le mur est en place
curl -s -o /dev/null -w '%{http_code}\n' \
https://monservice.savethemall.eu/outpost.goauthentik.io/zzz
# 404 → la route de l'outpost existe (302 ici = le handle est mal placé)
5. Bloque Caddy en nas-caddy — este es el que abre el WAN¶
Mientras no se complete este paso, el servicio responde en LAN y en tailnet, y permanece invisible desde Internet. El NAS es el punto de borde.
Archivo: /volume3/docker/nas-caddy/Caddyfile en el NAS.
Nada más: la autenticación y el enrutamiento siguen en la parte posterior, en vm-docker. El fragmento (to_vmdocker) ya incluye header_up Host {host} — sin él, la parte superior recibiría Host: vm-docker.
Variante: mantener el servicio fuera del WAN
Para un servicio que debe permanecer en la red interna, añadir import lan_only al bloque en lugar de no declararlo. Aquí, remote_ip es el cliente real: nas-caddy es el punto de borde, no hay ningún proxy en la parte superior para ocultar la fuente.
Control — la verdadera ruta pública
curl -s -o /dev/null -w '%{http_code}\n' \
--resolve monservice.savethemall.eu:443:<IP publique> \
https://monservice.savethemall.eu/
Sin --resolve, el comando pasa por el DNS interno y no prueba nada de la ruta WAN.
6. Secretos, si los hay¶
- Los valores viven en
/opt/docker/monservice/.enven el host, nunca en el cofre de forma explícita, nunca en el archivo Compose. - La versión cifrada va en
00-infra/secrets/vm-docker/monservice.enc.env(SOPS + edad). El árbol está indexado por host: existen tres nombres de pila en dos o más hosts, y sin esta cualificación el segundo sobrescribe al primero — sin problemas. - Solo la clave pública de edad es necesaria para cifrar. No se necesita ninguna clave privada en los otros hosts.
- Todos los tokens de API instalados se almacenan en Vaultwarden inmediatamente después, siguiendo la convención
<hôte>/<stack>·<NOM_DE_VARIABLE>.
El texto cifrado es permanente
Estos archivos también se suben a GitHub. El repositorio es privado, pero lo que se ha subido permanece allí: una rotación de claves no hace que el texto cifrado ya publicado sea ilegible. Rotar significa rotar en la dirección ascendente, no simplemente reescribir el archivo.
Nunca se deben incluir claves en una URL
El registro de errores registra la URL resuelta, incluyendo el token. De igual manera, Caddy solo elimina automáticamente tres encabezados: Authorization, Cookie, Set-Cookie. Un encabezado personalizado (X-Mon-Token) se envía en texto plano en access.log, que es leído por CrowdSec. Cualquier nuevo encabezado que contenga una clave debe añadirse al filtro del registro en el mismo momento en que se crea.
7. Documentar lo que se ha hecho¶
- Entrada en
10-stacks/monservice/decisions.md: motivo y cómo volver atrás. - Actualización de la tabla maestra de los stacks.
- Commit del vault y subida a los dos repositorios remotos.
Resumen¶
- Registro A en OVH, verificado en el servidor autoritativo
- Certificado emitido, dominio añadido a la lista de emisión
- Proveedor de proxy Authentik en modo forward auth (single application)
- Aplicación creada, con su logotipo
- Aplicación añadida manualmente al outpost integrado
- Bloque Caddy vm-docker, en el vault y sincronizado en el host
- Prueba
/outpost.goauthentik.io/zzz→ 404 - Bloque Caddy nas-caddy, certificado copiado en el NAS
- Control WAN con
--resolve - Claves cifradas en el vault, token guardado en el cofre
-
decisions.md, commit, doble subida
Dernière vérification de cette page : 2026-09-08