Outils pour utilisateurs

Outils du site


commun:proxy_http

Ceci est une ancienne révision du document !


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
Extension à chaud d'un volume si besoin :
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 enp1s0 gérée par ifupdown (/etc/network/interfaces, iface enp1s0 inet dhcp)
  • Renouvellement bail DHCP :
    sudo sh -c 'ifdown enp1s0; ifup enp1s0'
Piège rencontré : pour qu'une réservation DHCP prenne effet quand l'IP est encore occupée par une autre machine, il faut libérer l'IP (éteindre l'ancienne machine), purger les baux côté OpenWrt puis renouveler :
# 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-id avant durcissement
  • PermitRootLogin no
  • PasswordAuthentication no

Mises à jour automatiques

  • unattended-upgrades activé (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:
Deux pièges DNS rencontrés :
  1. Le résolveur interne Docker (127.0.0.11) n'avait aucun nameserver amont → SERVFAIL sur les serveurs ACME. Résolu en forçant dns: dans le compose.
  2. 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.

Consulter le changelog Caddy avant une mise à jour de version mineure : des directives du Caddyfile peuvent changer. En cas de doute, valider la config avant de recréer le conteneur :
docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile
Le tag 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)

  1. Baisser le TTL DNS à 60s (J-24h)
  2. Démarrer Caddy sur le NUC (échecs ACME normaux tant que le trafic n'arrive pas)
  3. Basculer la réservation DHCP / redirection routeur vers le NUC
  4. Vérifier l'obtention des certificats :
    docker compose logs -f caddy | grep -E "obtained|error"
  5. Tester chaque service (curl -sI)
  6. Rollback : remettre l'ancienne IP/redirection sur OpenWrt → retour immédiat au Raspi
  7. 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 shell si ce service doit revenir
commun/proxy_http.1785594794.txt.gz · Dernière modification : de francois

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki