Ceci est une ancienne révision du document !
Table des matières
Migration proxy HTTP : Raspi → NUC
Migration du reverse proxy depuis un Raspberry Pi (Arch/ARM + Apache2 + Certbot) vers un NUC (Debian 13 + Docker + Caddy).
Objectifs : maintenabilité, robustesse, open-source, surveillance.
1. Système
Distribution
- Debian 13 “Trixie” (stable depuis le 09/08/2025, support jusqu'en 2030)
- Installation minimale : serveur SSH + utilitaires usuels, pas de GUI
- Noyau :
linux-image-amd64(méta-paquet, suit les MAJ de sécurité) - Bootloader : GRUB (défaut Debian, robuste avec LVM)
Partitionnement
Disque NVMe 250 Go, LVM + ext4, pas de chiffrement.
| Partition | Taille | FS | Montage |
|---|---|---|---|
| nvme0n1p1 | 1 Go | FAT32 | /boot/efi |
| nvme0n1p2 | 1 Go | ext4 | /boot |
| nvme0n1p3 | ~248 Go | LVM (PV) | — |
VG volumes :
| LV | Taille | FS | Montage |
|---|---|---|---|
| lv-swap | 8 Go | swap | [SWAP] |
| lv-root | 25 Go | ext4 | / |
| lv-var | 35 Go | ext4 | /var |
| lv-opt | 60 Go | ext4 | /opt |
| (libre) | ~93 Go | — | réserve pour extension |
lvextend -L +20G /dev/volumes/lv-var resize2fs /dev/volumes/lv-var
2. Réseau
Adressage
- Routeur : OpenWrt (
192.168.1.90, fait aussi office de DNS local) - NUC : IP fixe 192.168.1.25 via réservation DHCP (MAC
cc:28:aa:47:ea:ab) - Cette IP était celle de l'ancien proxy → bascule transparente (redirections de ports et noms internes inchangés)
Gestion réseau
- Interface
enp1s0gérée par ifupdown (/etc/network/interfaces,iface enp1s0 inet dhcp) - Renouvellement bail DHCP :
sudo sh -c 'ifdown enp1s0; ifup enp1s0'
# Sur OpenWrt sed -i '/cc:28:aa:47:ea:ab/d; /192.168.1.25/d' /tmp/dhcp.leases /etc/init.d/dnsmasq restart
3. Sécurité
Pare-feu (UFW)
ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp # SSH ufw allow 80/tcp # HTTP (ACME challenge) ufw allow 443/tcp # HTTPS ufw allow 443/udp # HTTP/3 ufw enable
Fail2ban
/etc/fail2ban/jail.local :
[DEFAULT] bantime = 1h findtime = 10m maxretry = 5 [sshd] enabled = true
SSH durci
- Clé SSH (ed25519) poussée via
ssh-copy-idavant durcissement PermitRootLogin noPasswordAuthentication no
Mises à jour automatiques
unattended-upgradesactivé (sécurité)
4. Stack proxy
Docker
- Docker 29 + Compose v5 (install via
get.docker.com) - Projet dans
/opt/proxy/
Caddy
Reverse proxy + TLS automatique (Let's Encrypt), remplace Apache2 + Certbot.
/opt/proxy/docker-compose.yml :
services: caddy: image: caddy:alpine restart: unless-stopped dns: - 192.168.1.90 # DNS local OpenWrt (résout les noms internes : cahute, etc.) - 1.1.1.1 # secours public ports: - "80:80" - "443:443" - "443:443/udp" volumes: - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config volumes: caddy_data: caddy_config:
- Le résolveur interne Docker (
127.0.0.11) n'avait aucun nameserver amont → SERVFAIL sur les serveurs ACME. Résolu en forçantdns:dans le compose. - En forçant un DNS public uniquement, les backends internes (
cahute.beafrancois.fr) ne résolvaient plus → 502. Résolu en mettant le DNS OpenWrt en premier.
Caddyfile
/opt/proxy/caddy/Caddyfile
Modèle d'un vhost (cas proxy HTTPS→HTTPS vers cahute) :
blog.beafrancois.fr {
redir / /blog/ 301
reverse_proxy https://cahute.beafrancois.fr {
header_up Host blog.beafrancois.fr
transport http {
tls_insecure_skip_verify
}
}
header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload"
}
header_up Host <nom-public> est essentiel : équivalent du ProxyPreserveHost On d'Apache. Sans lui, Caddy transmet le Host de l'upstream (cahute) et le backend renvoie des URLs/redirections vers cahute, cassant la navigation depuis l'extérieur.
tls_insecure_skip_verify : équivalent de SSLProxyVerify none (backend en cert auto-signé/non vérifié).
Vhosts migrés
| Domaine | Backend | Particularité |
|---|---|---|
| blog | cahute/blog | redir → /blog/ |
| dav | cahute/dav/html/ | redir → /dav/html/ |
| git | cahute:3000 | — |
| musique | cahute/musique/ | redir → /musique/ |
| nuage | cahute/nextcloud | redirects .well-known (carddav/caldav/webfinger/nodeinfo) |
| wiki | cahute/dokuwiki/ | redir → /dokuwiki/ |
| service | homeassistant:8123 (HTTP) | WebSocket natif Caddy |
shell.beafrancois.fr retiré : pas d'enregistrement DNS (NXDOMAIN).
Limite de taille des logs
/etc/docker/daemon.json :
{
"log-driver": "json-file",
"log-opts": { "max-size": "50m", "max-file": "5" }
}
/etc/systemd/journald.conf :
SystemMaxUse=2G
5. Mise à jour de l'image Caddy
Opération manuelle, faite sur le proxy. Aucune mise à jour automatique de conteneur (pas de Watchtower) : une régression ne doit jamais arriver sans avoir été déclenchée.
cd /opt/proxy # 1. Sauvegarder la config avant toute manip sudo cp -a /opt/proxy /root/proxy-$(date +%F) # 2. Noter la version en cours (pour le rollback) docker compose exec caddy caddy version # 3. Télécharger la nouvelle image docker compose pull # 4. Recréer le conteneur docker compose up -d # 5. Contrôler docker compose logs --tail 40 caddy | grep -Ei "obtained|error|panic" for h in blog dav git musique nuage wiki service; do echo -n "$h : "; curl -sI -o /dev/null -w '%{http_code}\n' https://$h.beafrancois.fr done
Rollback : remettre le tag de version précis de l'ancienne version dans le compose (image: caddy:2.x.y-alpine), puis docker compose up -d. Les certificats sont dans le volume caddy_data et ne sont pas perdus : le retour arrière est immédiat.
docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile
alpine suit la dernière version : un docker compose pull peut donc ramener une version majeure sans prévenir. Le rollback exige de connaître la version qui tournait — d'où l'étape 2.
6. Procédure de bascule (rollback-friendly)
- Baisser le TTL DNS à 60s (J-24h)
- Démarrer Caddy sur le NUC (échecs ACME normaux tant que le trafic n'arrive pas)
- Basculer la réservation DHCP / redirection routeur vers le NUC
- Vérifier l'obtention des certificats :
docker compose logs -f caddy | grep -E "obtained|error"
- Tester chaque service (
curl -sI) - Rollback : remettre l'ancienne IP/redirection sur OpenWrt → retour immédiat au Raspi
- Après 48 h de stabilité : éteindre le Raspi
7. Commandes utiles
# Recharger la config après modif du Caddyfile docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile # Recharger la config après modif du Caddyfile (avec coupure des connexions) docker compose restart caddy # Vérifier la syntaxe du Caddyfile sans l'appliquer docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile # Suivre les logs docker compose logs -f caddy # État des conteneurs docker compose ps # Espace disque / LVM df -h && vgs && lvs
TODO / pistes
- Épingler le tag Caddy sur une version exacte plutôt que
alpine - Surveillance : Grafana + Prometheus + Loki + cAdvisor (prévu, non encore déployé)
- Sauvegarde du volume
caddy_data(certificats) — ex. restic - Optionnel : logwatch, rkhunter
- Créer l'enregistrement DNS
shellsi ce service doit revenir
