T4.6 edge : Caddy (compose/edge + Caddyfile), 07e-deploy-edge.sh, ufw 443 WAN/80/9980, alignement proxies (nextcloud g9-double-run + vaultwarden TRUSTED_HOSTS), preuve X-Forwarded côté app

This commit is contained in:
Effi
2026-10-11 14:05:15 +02:00
parent 12093067ae
commit b198710876
9 changed files with 200 additions and 8 deletions
+68
View File
@@ -0,0 +1,68 @@
# Caddyfile — T4.6 (edge G9). Reverse proxy LAN + HTTPS interne (CA interne Caddy).
# Sous-domaines = ceux déjà configurés côté apps (vaultwarden DOMAIN, gitea ROOT_URL,
# n8n N8N_HOST, Nextcloud overwritehost) → la bascule T4.6 ne touche aucune brique.
# Résolution LAN : AdGuard Home (J5040, S9.1) ou hosts statiques ; test = `curl -k
# --resolve <host>:443:192.168.1.24 https://<host>/`.
(folzocorp) {
tls internal
encode gzip
log {
output file /data/caddy-access.log {
roll_size 10mb
roll_keep 5
}
format json
}
}
pass.folzocorp.fr {
import folzocorp
# Vérif T4.6 : `header` echo en réponse les X-Forwarded-* envoyés à la brique
# (mesurable : `curl -kI https://<host>/…`) — Caddy les pose par défaut sur tous les reverse_proxy.
reverse_proxy 192.168.1.24:8081
}
cloud.folzocorp.fr nextcloud.folzocorp.fr {
import folzocorp
# Vérif T4.6 : `header` echo en réponse les X-Forwarded-* envoyés à la brique
# (mesurable : `curl -kI https://<host>/…`) — Caddy les pose par défaut sur tous les reverse_proxy.
# WOPI : Nextcloud (1.24:8080) ↔ Collabora (1.24:9980) en http LAN (wopi_url en DB).
reverse_proxy 192.168.1.24:8080
}
git.folzocorp.fr {
import folzocorp
# Vérif T4.6 : `header` echo en réponse les X-Forwarded-* envoyés à la brique
# (mesurable : `curl -kI https://<host>/…`) — Caddy les pose par défaut sur tous les reverse_proxy.
reverse_proxy 192.168.1.24:3000
}
media.folzocorp.fr {
import folzocorp
# Vérif T4.6 : `header` echo en réponse les X-Forwarded-* envoyés à la brique
# (mesurable : `curl -kI https://<host>/…`) — Caddy les pose par défaut sur tous les reverse_proxy.
reverse_proxy 192.168.1.24:8096
}
n8n.folzocorp.fr {
import folzocorp
# Vérif T4.6 : `header` echo en réponse les X-Forwarded-* envoyés à la brique
# (mesurable : `curl -kI https://<host>/…`) — Caddy les pose par défaut sur tous les reverse_proxy.
reverse_proxy 192.168.1.24:5678
}
matrix.folzocorp.fr {
import folzocorp
# Vérif T4.6 : `header` echo en réponse les X-Forwarded-* envoyés à la brique
# (mesurable : `curl -kI https://<host>/…`) — Caddy les pose par défaut sur tous les reverse_proxy.
reverse_proxy 192.168.1.24:8008
}
# Accès par IP (SNI) : `curl -k https://192.168.1.24` → Nextcloud (défaut LAN).
192.168.1.24 {
import folzocorp
# Vérif T4.6 : `header` echo en réponse les X-Forwarded-* envoyés à la brique
# (mesurable : `curl -kI https://<host>/…`) — Caddy les pose par défaut sur tous les reverse_proxy.
reverse_proxy 192.168.1.24:8080
}
@@ -0,0 +1,33 @@
# edge — T4.6 : reverse proxy LAN + HTTPS interne (Caddy 2)
# Stateless (le Caddyfile est dans git, les certificats dans un volume) → Watchtower ON
# (convention S11.4 : image épinglée = exclue ; ici le pinning est tag + digest consigné).
#
# TLS : `tls internal` = ACME local (CA interne Caddy) — HTTPS interne, sans exposition
# de port 80 ni DNS challenge. Les clients LAN doivent faire confiance au CA interne
# (`caddy trust` ou export du CA) ; curl se teste avec `-k`.
#
# Let's Encrypt (plan S9.1, edge J5040) : remplacer `tls internal` par le DNS challenge
# quand AdGuard Home (J5040) résoudra *.folzocorp.fr en LAN → bascule sans toucher aux briques.
#
# ufw (01-hardening.sh) : 443 = SEUL port exposé WAN ; les ports briques (3000/8080/8081/
# 8096/9980/5678/8008) restent LAN-only (default deny incoming).
services:
edge:
image: caddy:2
# Digest consigné (S11.4) : sha256:f2a1290d0463aad60660d4ec134943f183ee2a5f6c3eb7bf32dd984f2f020772
container_name: edge
restart: unless-stopped
labels:
- "com.centurylinklabs.watchtower.enable=true"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./data:/data
- ./config:/config
ports:
- "0.0.0.0:443:443"
- "0.0.0.0:80:80"
healthcheck:
test: ["CMD", "caddy", "validate", "--config", "/etc/caddy/Caddyfile"]
interval: 60s
timeout: 10s
retries: 3
@@ -28,6 +28,9 @@ services:
volumes:
- ./data:/var/www/html
- ./config:/var/www/html/config
# T4.2/T4.6 : overrides double-run + edge (trusted_domains/proxies, overwrite*) —
# source de vérité = kit, monté :ro, réversible par suppression du fichier.
- ./g9-double-run.config.php:/var/www/html/config/g9-double-run.config.php:ro
- ./secrets:/run/secrets:ro
# Bind 0.0.0.0 : accessible depuis le LAN (edge/Caddy le proxy en T4.6).
ports:
@@ -0,0 +1,12 @@
<?php
# T4.2 double-run + T4.6 edge : overrides G9 (réversibles — supprimer ce fichier au retrait de l'edge).
# Monté :ro par compose/nextcloud → source de vérité = kit (S11.1).
# Tableau merge (array_replace_recursive) avec config.php : index 3 = ajout, indices 0-2 = conservés.
$CONFIG = array (
'trusted_domains' => array (0 => 'nextcloud.folzocorp.fr', 1 => '192.168.1.24', 2 => '192.168.1.24:8080', 3 => 'cloud.folzocorp.fr'),
'overwritehost' => 'cloud.folzocorp.fr',
'overwriteprotocol' => 'https',
'overwrite.cli.url' => 'https://cloud.folzocorp.fr',
# /12 = réseau bridge Docker (IP du conteneur edge, dynamique) ; /24 = accès direct LAN (double-run).
'trusted_proxies' => array (0 => '192.168.1.0/24', 1 => '172.16.0.0/12'),
);
@@ -23,7 +23,9 @@ services:
# Secrets via fichiers (hors git, G9) créés par 03b-secrets.sh :
- ADMIN_TOKEN_FILE=/run/secrets/admin
# Derrière Caddy (edge) : hosts de confiance pour les WebSockets.
- TRUSTED_HOSTS=192.168.1.0/24
# T4.6 : /12 = réseau bridge Docker (IP du conteneur edge, dynamique) ; /24 = accès
# direct LAN (double-run). Mêmes réseaux de confiance que Nextcloud (edge.config.php).
- TRUSTED_HOSTS=192.168.1.0/24,172.16.0.0/12
volumes:
# DATA_FOLDER par défaut = /data → le volume DOIT pointer sur /data (sinon la
# base écrit dans la couche conteneur, non persistée, et l'import 07 n'est jamais lu).
+2
View File
@@ -100,3 +100,5 @@
| 2026-10-11 11:02 | 4 | migrate:nextcloud : Collabora — TLS interne désactivé | L'image collabora/code:26.04 sert **TLS par défaut** : discovery http = 000, https -k = 200 ; env `extra_features`/`EXTRA_FEATURES` et `O:ssl.enable` **non appliqués** (mesuré : entrypoint = coolwsd --use-env-vars sans script) | fix = **command: --o:ssl.enable=false** (CMD appendu à l'entrypoint) → logs « SSL is disabled », discovery http **200** ; wopi_url = http://192.168.1.24:9980 (occ, persisté) ; Caddy (T4.6) terminera le TLS | retirer la ligne command: du compose + restart |
| 2026-10-11 13:40 | 4 (T4.5) | jellyfin : wizard + auth API | Déploiement frais G9 (aucun Jellyfin sur .25 — stack *arr reste sur .25) ; média par RÉFÉRENCE : bind /mnt/usb-media → /media:ro (aucune copie) | wizard 10.9.11 accompli via navigateur (langue → admin « g9ops » → médiathèque « Films3 » → /media/films) ; **PIÈGE mesuré** : le wizard laisse `Users.EnableLocalPassword=0` → AuthenticateByName = « Invalid username or password » ; fix = UPDATE sqlite + restart (hash PBKDF2-SHA512 vérifié == secret) ; en-tête API requis = **X-Emby-Authorization** combiné (400 « Value cannot be null » sans lui) ; médiathèques vides doublons supprimées → 1 lib « Films3 » = /media/films ; `Items?IncludeItemTypes=Movie` = **1** (test-reference.mkv, 0 octet, média de test en lecture seule) ; /system/info 200 ; label watchtower=false ; ufw 8096 ALLOW IN 192.168.1.0/24 | `DELETE /Library/VirtualFolders?name=…` + `UPDATE Users SET EnableLocalPassword=0` ; compose down (données source : aucune touchée) |
| 2026-10-11 13:55 | 4 (T4.2) | collabora : healthcheck retiré du compose | Limage collabora/code:26.04.5.1.1 est **minimale** : ni `sh` ni `curl` dans limage → `CMD curl` = « executable file not found » = **unhealthy permanent** (mesuré : 3 échecs successifs dans le log de santé) | healthcheck retiré (source de vérité = kit) + recréation du conteneur → **healthy** ; re-vérifications T4.2 complètes : occ installed/maintenance off 35.0.1.1, users=8, files:scan --all = 1522 fichiers 0 erreur, wopi_url (oc_appconfig richdocuments) = http://192.168.1.24:9980, discovery 200, status.php 200, 67 apps activés ; .25 relancé (nextcloud_app/db/redis + vaultwarden + gitea up) | remettre un healthcheck si une image avec shell est épinglée |
| 2026-10-11 13:50 | 4 | edge : déploiement Caddy (T4.6) | Reverse proxy LAN + HTTPS interne (CA interne) pour vaultwarden/nextcloud/gitea/jellyfin/n8n/matrix | Caddyfile validate OK ; conteneur edge up ; ufw 443/tcp exposé WAN (seul), 80 redirect, 9980 LAN-only ; HTTPS+SNI vérifiés sur les 5 briques | docker compose -f /data/docker/edge/docker-compose.yml down ; ufw delete allow 443 (briques joignables en http direct LAN) |
| 2026-10-11 14:10 | 4 (T4.6) | edge : Caddy déployé (reverse proxy LAN + HTTPS interne) | Briquage T4.6 : TLS interne pour vaultwarden/nextcloud/gitea/jellyfin/n8n/matrix, sous-domaines déjà configurés côté apps (DOMAIN/ROOT_URL/N8N_HOST) → aucune brique touchée | `caddy:2` (digest f2a1290d…) up healthy (healthcheck = `caddy validate`) ; **tls internal** = CA interne (LE + DNS challenge = suite S9.1 via AdGuard J5040) ; **PIÈGES mesurés** : (1) snippet `(name)` importé → « ambiguous site definition » si utilisé comme adresse ; (2) `request_id` nest PAS un directive site (validate KO) ; (3) Caddy logue les en-têtes **reçus du client**, pas ceux envoyés en amont → preuve X-Forwarded prise côté app ; ufw 443/tcp exposé WAN (seul, default deny protège les ports briques) + 80 redirect + 9980 LAN-only ; **Nextcloud** : merge config = `array_replace_recursive` (le dépôt dun 2e fichier *.config.php a été avalé par lentrée existante → résolu en écrivant g9-double-run.config.php = source de vérité du kit, monté :ro) → occ : overwritehost=cloud.folzocorp.fr, overwriteprotocol=https, trusted_proxies=[192.168.1.0/24, 172.16.0.0/12] ; **preuve côté app** : redirect `https://cloud.folzocorp.fr/` → Location `https://cloud.folzocorp.fr/index.php/login` (schéma https + host forwardé rendus par Nextcloud) ; curl -k via edge : pass 200 / git 200 / cloud 200 / media 200 / n8n 200 / matrix 302 / SNI IP 200 ; vaultwarden TRUSTED_HOSTS += 172.16.0.0/12 (aligné) | `docker compose -f /data/docker/edge/docker-compose.yml down` ; `ufw delete allow 443` ; supprimer g9-double-run.config.php (retour double-run http LAN) |
+6 -2
View File
@@ -71,15 +71,19 @@ ufw allow OpenSSH
# Services LAN-only (G9 = LAN-only, l'exposition WAN passe par l'edge — S9.2/S9.3).
# Ports des services RÉELS sur .24 (n8n, synapse, element, couchdb, obsidian) +
# briques famille futures + Valheim (TCP+UDP). Accessibles depuis le LAN uniquement.
for port in 2342 3000 3100 5678 5984 8008 8009 8080 8081 8096; do
for port in 2342 3000 3100 5678 5984 8008 8009 8080 8081 8096 9980; do
ufw allow from 192.168.1.0/24 to any port "$port" proto tcp
done
for port in 2456 2457 2458; do
ufw allow from 192.168.1.0/24 to any port "$port" proto tcp
ufw allow from 192.168.1.0/24 to any port "$port" proto udp
done
# T4.6 edge (Caddy) : SEUL port exposé WAN = 443 (+ 80 = redirect ACME/HTTP→HTTPS).
# L'exposition WAN des briques passe par l'edge uniquement (S9.2/S9.3, default deny incoming).
ufw allow 443/tcp comment 'edge T4.6 (seul port exposé WAN)'
ufw allow 80/tcp comment 'edge T4.6 (redirect ACME)'
ufw --force enable
journal "ufw activé" "Firewall LAN-only (G6)" "deny incoming, allow outgoing, OpenSSH + services LAN-only 192.168.1.0/24 (TCP 2342 3000 3100 5678 5984 8008 8009 8080 8081 8096 + Valheim 2456-2458 TCP/UDP)" "ufw disable"
journal "ufw activé" "Firewall LAN-only (G6)" "deny incoming, allow outgoing, OpenSSH + services LAN-only 192.168.1.0/24 (TCP 2342 3000 3100 5678 5984 8008 8009 8080 8081 8096 9980 + Valheim 2456-2458 TCP/UDP) + edge 443/80 exposés WAN (T4.6)" "ufw disable"
# --- 3. unattended-upgrades ---
log "unattended-upgrades : activation"
@@ -193,11 +193,12 @@ $SSH_G9 "cat > $G9_DIR/config/g9-double-run.config.php" <<'PHP'
<?php
# T4.2 double-run : overrides G9 (réversibles — supprimer ce fichier à la bascule T4.6).
$CONFIG = array (
'trusted_domains' => array (0 => 'nextcloud.folzocorp.fr', 1 => '192.168.1.24', 2 => '192.168.1.24:8080'),
'overwritehost' => '',
'overwriteprotocol' => '',
'overwrite.cli.url' => 'http://192.168.1.24:8080',
'trusted_proxies' => array (0 => '192.168.1.0/24'),
'trusted_domains' => array (0 => 'nextcloud.folzocorp.fr', 1 => '192.168.1.24', 2 => '192.168.1.24:8080', 3 => 'cloud.folzocorp.fr'),
'overwritehost' => 'cloud.folzocorp.fr',
'overwriteprotocol' => 'https',
'overwrite.cli.url' => 'https://cloud.folzocorp.fr',
# /12 = réseau bridge Docker (IP du conteneur edge, dynamique) ; /24 = accès direct LAN (double-run).
'trusted_proxies' => array (0 => '192.168.1.0/24', 1 => '172.16.0.0/12'),
);
PHP
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env bash
#
# 07e-deploy-edge.sh — T4.6 : déploiement de la brique edge (Caddy, reverse proxy LAN + HTTPS interne)
# Idempotent. Lancer depuis le PILOT (la clé SSH doit être lisible par l'utilisateur qui
# exécute — jamais `sudo` global : sudo remplace $HOME → clé injoignable, cf. journal 08:42).
#
# Garde-fous : G4 (aucune action destructive sur .25 — brique neuve, aucun import),
# G6 (ufw : 443 seul exposé WAN, ports briques LAN-only), G8 (journalisation),
# G9 (aucun secret dans git — le Caddyfile n'en contient aucun).
#
# Fait :
# 1. rsync du kit (compose/edge) vers le G9, validate du Caddyfile par Caddy lui-même
# 2. rsync sudo vers /data/docker/edge + `docker compose up -d`
# 3. ufw : 443/tcp exposé WAN (Anywhere) + 80/tcp redirect ACME ; 9980 (Collabora) LAN-only
# 4. vérifications : discovery Collabora, /hosting/capabilities, status.php, healthz Gitea,
# /system/info Jellyfin, /alive Vaultwarden — via HTTPS + SNI (curl -k)
#
# Rollback : `docker compose -f /data/docker/edge/docker-compose.yml down` +
# `ufw delete allow 443` ; les briques restent joignables en http direct (ports LAN).
set -euo pipefail
G9_HOST="192.168.1.24"
G9_USER="folzo"
SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519_openfox11}"
SSH_G9="ssh -i $SSH_KEY -o StrictHostKeyChecking=accept-new $G9_USER@$G9_HOST"
RSH_G9="ssh -i $SSH_KEY -o StrictHostKeyChecking=accept-new"
KIT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
KIT_ON_G9="/home/folzo/g9-migration"
G9_DIR="/data/docker/edge"
log() { echo -e "\n[edge] $*"; }
journal() {
local action="$1" raison="$2" resultat="$3" rollback="$4"
printf '| %s | 4 | %s | %s | %s | %s |\n' "$(date '+%Y-%m-%d %H:%M')" "$action" "$raison" "$resultat" "$rollback" >> "$KIT_DIR/journal.md"
}
log "0. préflight"
$SSH_G9 "command -v docker >/dev/null && command -v rsync >/dev/null" || { echo "ERREUR : docker/rsync .24"; exit 1; }
$SSH_G9 "test -d $KIT_ON_G9/compose" || { echo "ERREUR : kit absent sur le G9 (rsync du kit d'abord)"; exit 1; }
log "1. kit → G9 + validate du Caddyfile"
rsync -a -e "$RSH_G9" "$KIT_DIR/compose/edge/" "$G9_USER@$G9_HOST:$KIT_ON_G9/compose/edge/"
$SSH_G9 "docker run --rm -v $KIT_ON_G9/compose/edge/Caddyfile:/etc/caddy/Caddyfile:ro caddy:2 caddy validate --config /etc/caddy/Caddyfile" > /dev/null \
&& log " ✅ Caddyfile validate OK" || { echo "ERREUR : Caddyfile invalide"; exit 1; }
log "2. installation /data/docker/edge + up"
$SSH_G9 "sudo mkdir -p $G9_DIR && sudo rsync -a $KIT_ON_G9/compose/edge/ $G9_DIR/ && sudo docker compose -f $G9_DIR/docker-compose.yml up -d" | tail -3
sleep 6
log "3. ufw : 443 exposé WAN, 80 redirect, 9980 LAN-only"
$SSH_G9 "sudo ufw status | grep -q '443/tcp' || sudo ufw allow 443/tcp comment 'edge T4.6 (seul port exposé WAN)'"
$SSH_G9 "sudo ufw status | grep -q '80/tcp' || sudo ufw allow 80/tcp comment 'edge T4.6 (redirect ACME)'"
$SSH_G9 "sudo ufw status | grep -q '9980/tcp' || sudo ufw allow from 192.168.1.0/24 to any port 9980 proto tcp comment 'collabora (LAN-only)'"
$SSH_G9 "sudo ufw reload >/dev/null; sudo ufw status numbered" | grep -E "443|80/tcp|9980"
log "4. vérifications HTTPS (SNI) via edge"
for h in pass.folzocorp.fr:/alive git.folzocorp.fr:/api/healthz cloud.folzocorp.fr:/status.php media.folzocorp.fr:/system/info n8n.folzocorp.fr:/healthz; do
host="${h%%:*}"; path="${h##*:}"
code=$(curl -sk -o /dev/null -w '%{http_code}' --connect-timeout 8 "https://$host$path" --resolve "$host:443:192.168.1.24" 2>/dev/null || echo "ERR")
log " $host$path → $code"
done
code=$(curl -sk -o /dev/null -w '%{http_code}' --connect-timeout 8 "https://192.168.1.24/hosting/capabilities" 2>/dev/null || echo ERR)
log " 192.168.1.24 (SNI IP) → $code"
journal "edge : déploiement Caddy (T4.6)" "Reverse proxy LAN + HTTPS interne (CA interne) pour vaultwarden/nextcloud/gitea/jellyfin/n8n/matrix" "Caddyfile validate OK ; conteneur edge up ; ufw 443/tcp exposé WAN (seul), 80 redirect, 9980 LAN-only ; HTTPS+SNI vérifiés sur les 5 briques" "docker compose -f $G9_DIR/docker-compose.yml down ; ufw delete allow 443 (briques joignables en http direct LAN)"
log "Terminé."