Dernière mise à jour : septembre 2026
Cette page décrit l'infrastructure du général au particulier : les segments réseau, les machines, les services et les flux, puis le détail du filtrage et les particularités connues. Le détail du reverse proxy se trouve sur la page « Migration proxy HTTP : Raspi → NUC ».
Le LAN1 filaire porte l'infrastructure, deux PC tour et un Raspberry Pi 5. Les portables sont exclusivement en WiFi, sur un segment séparé.
Internet
|
v
+----------------------------------------------+
| ROUTEUR OpenWrt 192.168.1.90 |
| NAT · pare-feu · DNS local (dnsmasq) |
| serveur WireGuard · admin LuCI :8443 |
+----------------------------------------------+
| | |
LAN1 filaire WiFi VPN WireGuard
192.168.1.0/24 192.168.115.0/24 10.1.100.0/24
(infra + fixes) (portables) (accès distant)
| | |
| +----------+----------+
| |
+-------+--------+-----------+ |
| | | | |
| [2 PC tour] [RPi5 « homeassistant »]
| |
v |
+------------------+ |
| PROXY Caddy .25 | <--------------+ (web des 3 segments)
| TLS · reverse |
| proxy · filtre | [Docker]
| sortie cloisonnée|
+--------+---------+
| backends autorisés uniquement
v
+------------------------------------------+
| SERVEUR « cahute » 192.168.1.9 |
| Debian 13 · RAID 2 To |
| UFW : accès restreint à 192.168.1.0/26 |
| (proxy .25 exclu par un deny) |
| DOCKER-USER : ports des conteneurs |
| - Auth : LLDAP [Docker] |
| - Surveillance : Uptime-Kuma, Dozzle, |
| Homepage, Diun [Docker] |
| - Services : Nextcloud, Wiki, Blog, |
| Ampache, Gitea, MariaDB, Cockpit |
| [bare-metal] |
| - Partages : NFS 4.2 [bare-metal] |
+------------------------------------------+
^
| WiFi : sssd (LDAPS 6360) · web via proxy
| VPN : partages NFS
+------------------------------------------+
| PORTABLES (Debian GNOME, CachyOS…) |
| WiFi uniquement · home local |
| cache offline sssd · WireGuard pour les |
| partages |
+------------------------------------------+
| Segment | Plage | Rôle |
|---|---|---|
| LAN1 filaire | 192.168.1.0/24 | Infrastructure + postes fixes + domotique |
| WiFi | 192.168.115.0/24 | Tous les portables |
| VPN WireGuard | 10.1.100.0/24 | Accès distant (partages NFS, services) |
Le LAN est bien un /24. Le 192.168.1.0/26 que l'on retrouve dans plusieurs règles n'est pas un masque réseau : c'est une plage d'autorisation UFW sur le serveur, qui limite l'accès aux adresses .1 à .62.
Le segment WiFi est déclaré comme zone invite côté OpenWrt. Les règles de redirection et les autorisations du serveur couvrent cette zone, ce qui donne aux portables l'accès au web et à LDAPS.
| Hôte | IP | Nom court | Fonction |
|---|---|---|---|
| Routeur | 192.168.1.90 | aiguilleur | OpenWrt : NAT, DNS, pare-feu, WG |
| Proxy | 192.168.1.25 | proxyhttp | Caddy : TLS + reverse proxy |
| Serveur | 192.168.1.9 | cahute | Docker, données, partages |
| PC tour ×2 | 192.168.1.x | — | Postes fixes filaires |
| Raspberry Pi 5 | 192.168.1.67 | homeassistant | Domotique — hors plage UFW (voir §8) |
Client (LAN / wifi invité / VPN / Internet)
| résolution DNS : sous-domaine -> 192.168.1.25
v
[ Routeur .90 ] DNAT 443 -> .25 (règle par zone : wan, lan, invite)
v
[ Caddy .25 ] terminaison TLS (Let's Encrypt ou tls internal)
filtre @denied par remote_ip
sortie limitée aux backends (DOCKER-USER)
v
[ Serveur .9 ] port applicatif interne (ex. 3001, 3002, 8888, 17170)
accepté depuis .25 uniquement (DOCKER-USER)
Portable (online) --> sssd --> ldaps://auth.beafrancois.fr:6360 --> LLDAP (.9) Portable (offline) --> sssd --> cache local chiffré (sans expiration) Navigateur --> ldap.beafrancois.fr / auth.beafrancois.fr --> UI LLDAP Serveur (NSS-only) --> sssd --> LLDAP (résolution UID/GID pour NFS)
Portable en WiFi --X-- pas d'accès direct aux partages Portable (WiFi ou 5G) --> tunnel WireGuard --> NFS 4.2 --> /mnt/stockage (.9) PC tour (LAN1 /26) --> NFS 4.2 --> /mnt/stockage (.9)
Les partages ne sont jamais montés directement depuis le segment WiFi. Pour un portable, le tunnel WireGuard est le seul chemin, à la maison comme à l'extérieur.
Le routeur est le point d'entrée unique. Il assure le NAT, le pare-feu de zones, le DNS local et la terminaison du VPN.
L'interface d'administration LuCI répond sur https://aiguilleur.beafrancois.fr:8443 ou https://192.168.1.90:8443, car uhttpd a été déplacé du 443 vers le 8443. Le port est obligatoire : aiguilleur.beafrancois.fr résout directement vers le routeur (.90) et non vers le proxy. Sans le :8443, la requête arrive sur le 443 du routeur, qui est justement redirigé vers Caddy (.25), lequel n'a pas de bloc pour ce nom.
Le routeur s'appelle aiguilleur. Son ancien nom, router, ne résout plus. Le DNS est assuré par dnsmasq, avec une entrée par sous-domaine et sans wildcard. Le serveur WireGuard utilise l'interface wg1 (et wg0).
| Port | Destination | Zones sources | Usage |
|---|---|---|---|
| 443 | 192.168.1.25:443 | wan + lan + invite | Web via Caddy |
| 6360 | 192.168.1.9:6360 | lan + invite | LDAPS (sssd) |
| 9090 | 192.168.1.9:9090 | lan | Cockpit |
| 8329 | 192.168.1.9 | lan | Gitea SSH |
uci add_list dhcp.@dnsmasq[0].address='/nuage.beafrancois.fr/192.168.1.25' uci add_list dhcp.@dnsmasq[0].address='/wiki.beafrancois.fr/192.168.1.25' uci add_list dhcp.@dnsmasq[0].address='/blog.beafrancois.fr/192.168.1.25' uci add_list dhcp.@dnsmasq[0].address='/musique.beafrancois.fr/192.168.1.25' uci add_list dhcp.@dnsmasq[0].address='/surveillance.beafrancois.fr/192.168.1.25' uci add_list dhcp.@dnsmasq[0].address='/status.beafrancois.fr/192.168.1.25' uci add_list dhcp.@dnsmasq[0].address='/logs.beafrancois.fr/192.168.1.25' uci commit dhcp /etc/init.d/dnsmasq restart
dnsmasq écoute aussi sur l'interface du tunnel (wg1), ce qui permet la résolution des noms internes depuis le VPN.
Le proxy est une machine physique dédiée, un NUC de hostname proxyhttp, distincte du serveur principal. C'est la seule machine exposée au trafic entrant sur le 443. Caddy y tourne en conteneur, et le projet se trouve dans /opt/proxy.
Caddy termine le TLS avec des certificats Let's Encrypt pour les noms publics, et avec tls internal pour les noms internes. Ces derniers n'ont donc pas de certificat public et n'apparaissent pas dans les journaux de transparence des certificats. Il relaie ensuite les requêtes vers les ports applicatifs du serveur.
Les vhosts d'administration sont restreints par IP source. Le filtre utilise remote_ip, c'est-à-dire l'adresse réelle de la connexion TCP et non un en-tête : il n'est pas falsifiable depuis l'extérieur. Aucun de ces noms n'a d'enregistrement AAAA, Caddy n'est donc joignable de l'extérieur qu'en IPv4.
surveillance.beafrancois.fr {
@denied not remote_ip 192.168.1.0/24 192.168.115.0/24 10.1.100.0/24
respond @denied 403
tls internal
reverse_proxy 192.168.1.9:3002
}
Le proxy est traité comme une machine non fiable, parce qu'il est le premier exposé en cas de faille dans Caddy. Trois mesures en découlent :
DOCKER-USER (bloc CADDY EGRESS de /etc/ufw/after.rules). Sur les réseaux privés, il ne peut joindre que cahute sur ses six ports de backend, homeassistant sur le 8123 et le DNS du routeur.172.18.0.0/16 dans le compose, parce que ces règles s'appuient dessus.
Le rechargement de la configuration se fait par docker compose exec caddy caddy reload –config /etc/caddy/Caddyfile.
enp3s0, sans adresse IPv6 globale/mnt/stockage (multimedia, famille, partage, homes, system, docker)
La conteneurisation est partielle. LLDAP et la stack de surveillance (Dozzle, Uptime-Kuma, Homepage, Diun) tournent sous Docker, ainsi qu'imaginary, le service d'aperçus de Nextcloud, qui n'écoute que sur 127.0.0.1:9000. Apache (vhosts web sur le 443), Nextcloud, DokuWiki, le blog, Ampache, Gitea, MariaDB, Cockpit et NFS sont encore en bare-metal.
Caddy ne tourne pas sur ce serveur : il est en conteneur sur la machine proxy dédiée (.25), voir §4.2.
Les dossiers compose/ et data/ des services restants sont déjà créés, mais les stacks ne sont pas déployées.
/mnt/stockage/docker/ ├── compose/ ← un dossier par stack (lldap, surveillance, + à venir) └── data/ ← données persistantes (bind mounts vers le RAID)
Les portables sont des Linux (Debian/GNOME, CachyOS/Arch) connectés exclusivement en WiFi (192.168.115.0/24).
L'authentification système passe par sssd sur LLDAP, avec cache_credentials = True et un cache offline sans expiration (offline_credentials_expiration = 0). Le home est local sur chaque poste, sans NFS : c'est la condition du fonctionnement hors ligne.
WireGuard est obligatoire pour les partages. Les montages NFS ne passent que par le tunnel (10.1.100.0/24), y compris depuis le WiFi de la maison, parce que les exports n'autorisent pas le segment WiFi. Le client WireGuard pousse DNS = 192.168.1.90.
Les deux postes fixes sont raccordés en filaire sur le LAN1. Leurs adresses sont dans la plage .1–.62, donc couvertes par les règles UFW du serveur : ils accèdent directement aux services et aux partages, sans VPN. Ils montent les partages en NFS 4.2 sur TCP, depuis un port source privilégié.
Le Raspberry Pi 5 porte la domotique et est raccordé en filaire sur le LAN1.
Son adresse (.67) est hors de la plage .1–.62 couverte par les règles UFW en /26. Le serveur lui refuse donc SSH (22), HTTPS (443), NFS (2049), Gitea (3000) et Cockpit (9090). Depuis cette machine, le serveur répond au ping mais refuse la connexion sur ces ports.
Il lui reste les services publiés par le proxy Caddy (.25), dont le filtre autorise tout le 192.168.1.0/24, et LDAPS sur le 6360, autorisé en /24.
Les règles de cloisonnement du proxy désignent homeassistant par son adresse IP : le relais de Caddy vers le 8123 dépend du maintien de l'adresse .67.
| Service | Sous-domaine | Cible | Exécution |
|---|---|---|---|
| Nextcloud | nuage.beafrancois.fr | .9:443 (Apache) | bare-metal |
| DokuWiki | wiki.beafrancois.fr | .9:443 (Apache) | bare-metal |
| Blog | blog.beafrancois.fr/blog | .9:443 (Apache) | bare-metal |
| Ampache | musique.beafrancois.fr/musique/public | .9:443 (Apache) | bare-metal |
| Gitea | gitea.beafrancois.fr (+ SSH 8329) | .9:3000 | bare-metal |
| MariaDB | — | .9:3306 | bare-metal |
| LLDAP (UI) | auth… / ldap.beafrancois.fr | .9:17170 | Docker |
| LLDAP (LDAPS) | auth.beafrancois.fr:6360 | .9:6360 | Docker |
| Homepage | surveillance.beafrancois.fr | .9:3002 | Docker |
| Uptime-Kuma | status.beafrancois.fr | .9:3001 | Docker |
| Dozzle | logs.beafrancois.fr | .9:8888 | Docker |
| Cockpit | — | .9:9090 | bare-metal |
| NFS | — | filaire .1–.62 + VPN | bare-metal |
Le port 3000 est occupé par Gitea, d'où Homepage sur le 3002.
Le port 3890 (LDAP en clair) est publié par le conteneur LLDAP mais fermé au réseau par DOCKER-USER. Seuls les processus locaux de cahute peuvent l'atteindre.
Dozzle exige une authentification (l'API répond 401 sans session). Homepage n'a pas d'authentification propre.
L'annuaire est LLDAP, en conteneur Docker. Il remplace Kanidm, abandonné parce que son mode offline ne fonctionnait pas.
Les clients utilisent sssd (PAM et NSS) sur les portables et sur les PC tour. Le serveur l'utilise aussi, en mode NSS seul, pour que NFS applique les identités LLDAP. Un compte de bind en lecture seule est déclaré dans sssd.conf (permissions 600).
Les UID sont forcés de 1000 à 1003. Les groupes sont partage (GID 301), famille (GID 302) et multimedia. Il n'y a pas de Kerberos : la cohérence des UID et des GID entre les machines suffit à NFS.
Le filtrage de cahute repose sur deux mécanismes distincts. UFW filtre les services en bare-metal. La chaîne DOCKER-USER filtre les ports publiés par les conteneurs, qu'UFW ne voit pas.
MariaDB (3306) et le LDAP en clair (3890) ne sont pas ouverts au réseau. Le WiFi est autorisé sur LDAPS (6360) et sur Cockpit (9090), mais pas sur NFS : les partages ne sont joignables que depuis le filaire .1–.62 ou par le VPN.
| Port(s) | Service | Action | Sources |
|---|---|---|---|
| 22, 111, 2049, 9090/tcp | SSH, rpcbind, NFS, Cockpit | DENY, en tête | 192.168.1.25 (proxy) |
| 22/tcp | SSH | ALLOW | 192.168.1.0/26 |
| 443/tcp | Apache | ALLOW | 192.168.1.0/26 (dont le proxy .25) |
| 2049/tcp | NFSv4 | ALLOW | 192.168.1.0/26 + 10.1.100.0/24 (VPN) |
| 2048, 4045 (tcp + udp) | reliquat NFSv3 | ALLOW | 192.168.1.0/26 |
| 3000/tcp | Gitea (web) | ALLOW | 192.168.1.0/26 |
| 8329/tcp (v4 + v6) | Gitea (SSH) | ALLOW | Anywhere |
| 9090/tcp | Cockpit | ALLOW | 192.168.1.0/26 + 192.168.115.0/24 |
Lecture de ces règles :
/26, ce qui lui ouvrirait NFS, SSH et Cockpit. La règle deny placée en première position les lui ferme. UFW applique la première règle qui correspond, donc ce deny l'emporte sur les allow en /26. Le filtrage est fait sur cahute et non sur le proxy, parce que le pare-feu d'un proxy compromis ne protège plus rien. Le proxy garde l'accès au 443 et au 3000, dont Caddy a besoin.DISABLE_REGISTRATION = true) et la consultation exige une connexion (REQUIRE_SIGNIN_VIEW = true). cahute n'a pas d'adresse IPv6 globale, la règle « v6 » n'expose donc rien.
Docker publie ses ports par un DNAT, et le trafic correspondant traverse la chaîne FORWARD, en amont des chaînes d'UFW. Les règles ufw allow from 192.168.1.25 to any port … ne s'appliquaient donc pas aux conteneurs : avant la mise en place de ce filtrage, Dozzle (:8888) était joignable depuis le VPN, alors que Cockpit (:9090, bare-metal) était bien filtré. Le binding sur 192.168.1.9 plutôt que sur 0.0.0.0 évite l'exposition en IPv6, mais ne change rien à ce contournement.
Le filtrage se fait dans la chaîne DOCKER-USER, que Docker évalue avant ses propres règles. Le bloc est placé en fin de /etc/ufw/after.rules (sauvegarde de l'original : after.rules.bak), ce qui le rend persistant et rechargeable par ufw reload :
# BEGIN DOCKER INGRESS *filter :DOCKER-USER - [0:0] -A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN -A DOCKER-USER -i enp3s0 -s 192.168.1.25 -p tcp -m conntrack --ctorigdstport 3001:3002 -j RETURN -A DOCKER-USER -i enp3s0 -s 192.168.1.25 -p tcp -m conntrack --ctorigdstport 8888 -j RETURN -A DOCKER-USER -i enp3s0 -s 192.168.1.25 -p tcp -m conntrack --ctorigdstport 17170 -j RETURN -A DOCKER-USER -i enp3s0 -s 192.168.1.0/24 -p tcp -m conntrack --ctorigdstport 6360 -j RETURN -A DOCKER-USER -i enp3s0 -s 192.168.115.0/24 -p tcp -m conntrack --ctorigdstport 6360 -j RETURN -A DOCKER-USER -i enp3s0 -s 10.1.100.0/24 -p tcp -m conntrack --ctorigdstport 6360 -j RETURN -A DOCKER-USER -i enp3s0 -m conntrack --ctstate DNAT -j DROP COMMIT # END DOCKER INGRESS
| Port publié | Conteneur | Sources autorisées |
|---|---|---|
| 3001 | Uptime-Kuma | 192.168.1.25 (proxy) |
| 3002 | Homepage | 192.168.1.25 (proxy) |
| 8888 | Dozzle | 192.168.1.25 (proxy) |
| 17170 | LLDAP (UI) | 192.168.1.25 (proxy) |
| 6360 | LLDAP (LDAPS) | 192.168.1.0/24 + WiFi + VPN |
| 3890 | LLDAP (LDAP en clair) | aucune |
Quatre points expliquent la construction de ce bloc :
DOCKER-USER, le paquet a déjà subi le DNAT : son port de destination est celui du conteneur (3000 pour Homepage, 8080 pour Dozzle). Le critère –ctorigdstport filtre sur le port publié d'origine.DROP final ne vise que les connexions DNATées qui entrent par enp3s0, c'est-à-dire les ports publiés. Le trafic sortant des conteneurs (sondes d'Uptime-Kuma, Diun) n'est pas touché, et ses réponses passent par la première règle.cahute ne traversent pas la chaîne FORWARD. sssd et les applications locales atteignent donc LLDAP, y compris sur le 3890, sans règle particulière.
Le 6360 est autorisé en /24 et non en /26 : l'authentification reste possible depuis toute machine du LAN filaire, y compris au-delà de .62.
# Recharger après une modification du bloc sudo ufw reload # Afficher la chaîne telle qu'elle est chargée sudo iptables -S DOCKER-USER # Test depuis un poste du LAN : attendu bloqué, bloqué, ouvert for p in 3002 3890 6360; do echo -n "$p: "; timeout 3 bash -c "</dev/tcp/192.168.1.9/$p" 2>/dev/null && echo ouvert || echo bloqué; done
cahute exporte /export/famille, /export/multimedia, /export/partage, /export/home/beatrice et /export/home/francois. Chaque export est ouvert à 192.168.1.0/26 et à 10.1.100.0/24, avec les options rw,secure,root_squash,no_subtree_check (root_squash et secure sont les valeurs par défaut, exportfs -v les affiche).
L'authentification est en sec=sys : le serveur fait confiance à l'UID annoncé par le client. L'option secure impose un port source inférieur à 1024, ce qui réserve le dialogue NFS au root du client et empêche un processus utilisateur de forger un UID. L'option root_squash ramène le root distant à nobody. Un root sur un poste de la plage /26 ou du VPN peut en revanche se présenter sous n'importe quel UID ordinaire. Seul Kerberos fermerait cette possibilité, et il n'est pas déployé.
La version précédente du fichier, avec l'option insecure, est conservée dans /etc/exports.bak.
/26 n'est pas un sous-réseau. C'est une plage d'autorisation dans les règles UFW du serveur (ufw allow from 192.168.1.0/26 …), qui ne couvre que .1–.62. Toute machine du LAN adressée au-delà de .62 est silencieusement refusée par le serveur alors que le réseau, lui, fonctionne. C'est le cas de homeassistant en .67.src=wan casse l'accès web interne. Les zones lan et invite ont donc chacune leur règle./beafrancois.fr/…. Un wildcard casserait le SSH de Gitea, car un nom ne peut pas résoudre vers deux IP selon le protocole. Chaque service est donc déclaré individuellement.wg1 (et un localservice adapté), la résolution depuis le tunnel ne fonctionnait pas.Host non listé (« Host validation failed »). Les valeurs sont séparées par des virgules, sans espace.chmod -R a-s,a-t partage.router en aiguilleur. L'ancien nom ne résout plus du tout. La sonde Ping « Routeur » d'Uptime-Kuma, configurée sur l'hôte router, est cassée depuis. À l'époque, ce nom résolvait vers le proxy (.25), qui relayait vers le routeur (.90:8443). Le nouveau nom pointe directement vers .90, sans passer par Caddy, et le Caddyfile ne contient plus de bloc vers le routeur.CADDY EGRESS du proxy, ou un conteneur ajouté sur cahute sans règle dans le bloc DOCKER INGRESS, échoue par timeout sans message explicite.