Vai al contenuto

Pubblicare un nuovo servizio su *.savethemall.eu

Traduzione automatica dell'originale francese.

Procedura completa per pubblicare un servizio su un nome pubblico, protetto da Authentik. Richiede circa 30 minuti, di cui la maggior parte è in attesa di propagazione DNS.

In tutto ciò che segue, sostituire monservice con il sottodominio desiderato e monservice:8080 con il nome del servizio Compose e la sua porta.

Cosa si presume sia già noto

  • Il container è in esecuzione e risponde su HTTP su infrastructure_network.
  • Controllo: da vm-docker, docker exec caddy wget -qO- http://monservice:8080/ | head -5. Se questo comando non restituisce nulla, interrompere qui: nulla di ciò che segue compenserà un upstream silenzioso.

L'ordine, e perché non è negoziabile

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

L'unica fase che può causare problemi è la 4: Caddy di vm-docker ha 76 host virtuali, e un ricaricamento su una configurazione non valida li imposta tutti. Di conseguenza, caddy validate prima di restart, e il certificato prima del blocco.


1. Registrazione DNS presso OVH

Sempre per primo. acme.sh valida il DNS-01: senza la registrazione, l'emissione del certificato fallisce, e l'errore sembra un problema di identificazione.

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"

Controllo

dig +short monservice.savethemall.eu @1.1.1.1
# attendu : <IP publique>

Assolutamente non il risolutore locale: il DNS interno risponde già per questo nome, tramite wildcard, e darebbe una falsa conferma.

E nemmeno i server autoritativi di OVH — ns.ovh.net e dns1.ovh.net non rispondono alle richieste dirette da questo parco (misurato il 2026-08-29 da vm-claude e dal VPS: communications error … timed out). Un risolutore pubblico ha già svolto il lavoro.


2. Certificato TLS

Aggiungere il dominio alla lista di emissione — è questa che verrà letta al prossimo deploy completo — e poi emettere il certificato.

# 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 è obbligatorio qui, e la ragione non è presso OVH

Senza di esso, l'emissione fallisce sistematicamente su:

Timed out waiting for DNS.
Error checking DNS.

acme.sh verifica il suo record TXT tramite DoH cloudflare-dns.com, e AdGuard risolve questo nome verso 0.0.0.0: il filtro anti-bypass DNS di AdGuard blocca il proprio strumento di emissione. Tuttavia, il record TXT è correttamente configurato presso OVH, per poi essere rimosso correttamente — da cui un fallimento che sembra un problema di identificatori o di propagazione.

Il controllo che si risolve in un comando:

docker exec acme sh -c 'nslookup cloudflare-dns.com | tail -3'
# Address: 0.0.0.0  → c'est AdGuard, pas OVH

--dnssleep sostituisce il controllo con un'attesa fissa. Questo è il bypass; la soluzione è consentire cloudflare-dns.com in AdGuard.

Controllo

ssh -p <port-ssh> <user>@vm-docker \
  "ls -l /opt/docker/acme/certs/monservice.savethemall.eu/fullchain.pem"

Il NAS riceve la sua copia al rsync ogni giorno. Per non dover aspettare, è possibile attivarlo manualmente prima del passaggio 5.


3. Applicazione e fornitore in Authentik

Nell'interfaccia di amministrazione:

  1. Applicazioni → Provider → Crea → Provider Proxy
    • Modalità: Forward auth (singola applicazione) — non Proxy, non Livello di dominio.
    • Host esterno: https://monservice.savethemall.eu
    • Flusso di autorizzazione: quello del parco (consenso implicito).
  2. Applicazioni → Crea
    • Slug: monservice
    • Provider: quello appena creato
    • Icona: cercare il logo ufficiale prima di creare l'applicazione. In ordine: il repository GitHub del progetto, il /favicon.svg del sito ufficiale, https://cdn.simpleicons.org/<nom>, quindi il catalogo https://cdn.jsdelivr.net/gh/selfhst/icons/svg/<nom>.svg.
  3. Applicazioni → Outposts → authentik Embedded Outpost → Modifica → Applicazioni
    • Aggiungere l'applicazione manualmente.

L'outpost integrato non recupera automaticamente l'applicazione

Questo è l'errore più comune di questa procedura. Senza questo aggiunta esplicita, tutto è correttamente configurato su Authentik, Caddy reindirizza correttamente al flusso di connessione, e la connessione fallisce comunque — senza un messaggio che indica la causa.


4. Blocco Caddy su vm-docker

Modificare 10-stacks/caddy/Caddyfile nel vault, quindi sincronizzare. Il file del vault non è un collegamento simbolico: le due copie sono reali e divergono se vengono dimenticate.

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
    }
}

L'ordine dei due handle non è puramente decorativo: vedere forward_auth prima di handle.

Sincronizzazione, obbligatoria dopo ogni modifica:

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"

Controllo — sulla rete locale, dove il DNS punta già su 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. Blocco Caddy sul nas-caddy — è questo che apre la WAN

Finché questa fase non è stata completata, il servizio risponde sulla rete locale e sulla tailnet, rimanendo invisibile da Internet. È il NAS che funge da edge.

File: /volume3/docker/nas-caddy/Caddyfile sul NAS.

monservice.savethemall.eu {
    import tls_cert monservice.savethemall.eu
    import to_vmdocker
}

Niente di più: l'autenticazione e il routing rimangono a valle, su vm-docker. Il frammento (to_vmdocker) contiene già header_up Host {host} — senza di esso, la parte superiore riceverebbe Host: vm-docker.

Variante: mantenere il servizio fuori dalla WAN

Per un servizio che deve rimanere interno, aggiungere import lan_only al blocco invece di non dichiararlo. In questo caso, remote_ip è effettivamente il client: nas-caddy è l'edge, non c'è un proxy a monte per oscurare la fonte.

Controllo — il vero percorso pubblico

curl -s -o /dev/null -w '%{http_code}\n' \
  --resolve monservice.savethemall.eu:443:<IP publique> \
  https://monservice.savethemall.eu/

Senza --resolve, il comando passa attraverso il DNS interno e non verifica nulla del percorso WAN.


6. Chiavi, se presenti

  • I valori risiedono in /opt/docker/monservice/.env sull'host, mai nel vault in chiaro, mai nel file Compose.
  • La versione crittografata va in 00-infra/secrets/vm-docker/monservice.enc.env (SOPS + age). L'albero è indicizzato per host: tre nomi di stack esistono su due o più host, e senza questa qualificazione il secondo sovrascrive il primo — senza problemi.
  • È necessaria solo la chiave pubblica age per la crittografia. Non è necessario che esista alcuna chiave privata sugli altri host.
  • Tutti i token API installati vengono memorizzati in Vaultwarden immediatamente dopo, seguendo la convenzione <hôte>/<stack>·<NOM_DE_VARIABLE>.

Il testo cifrato viene mantenuto permanentemente

Questi file vengono anche caricati su GitHub. Il repository è privato, ma ciò che è stato caricato rimane: una rotazione della chiave non rende il testo cifrato precedentemente pubblicato nuovamente leggibile. "Rotazione" significa rotazione in avanti, non semplicemente la riscrittura del file.

Mai inserire informazioni sensibili in un URL

Il log di errore registra l'URL risolta, compreso il token. Allo stesso modo, Caddy elimina automaticamente solo tre intestazioni: Authorization, Cookie, Set-Cookie. Un'intestazione personalizzata (X-Mon-Token) viene inviata in chiaro in access.log, che viene letta da CrowdSec. Ogni nuova intestazione contenente informazioni sensibili deve essere aggiunta al filtro del log nel momento in cui viene creata.


7. Documentare quanto fatto

  • Registrazione datata in 10-stacks/monservice/decisions.md: motivo e come tornare indietro.
  • Aggiornamento della tabella principale degli stack.
  • Commit del vault e push su entrambi i repository remoti.

Riepilogo

  • Registrazione A presso OVH, verificata sul server autorevole
  • Certificato emesso, dominio aggiunto alla lista di emissione
  • Fornitore di proxy Authentik in modalità forward auth (singola applicazione)
  • Applicazione creata, con il suo logo
  • Applicazione aggiunta manualmente all'outpost integrato
  • Blocco Caddy vm-docker, nel vault e sincronizzato sull'host
  • Sondaggio /outpost.goauthentik.io/zzz → 404
  • Blocco Caddy nas-caddy, certificato copiato sul NAS
  • Controllo WAN con --resolve
  • Chiavi cifrate nel vault, token salvato nel vault
  • decisions.md, commit, doppio push

Dernière vérification de cette page : 2026-09-08