Table des matières

Architecture du réseau — beafrancois.fr

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 ».

1. Vue d'ensemble

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

2. Plan d'adressage

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)

3. Les flux principaux

3.1 Flux web (HTTPS)

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)

3.2 Flux d'authentification

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)

3.3 Flux fichiers

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.

4. Les machines

4.1 Routeur — OpenWrt (192.168.1.90)

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).

Redirections de port (DNAT)

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

DNS local (dnsmasq)

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.

4.2 Proxy HTTP — Caddy (192.168.1.25)

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 :

Le rechargement de la configuration se fait par docker compose exec caddy caddy reload –config /etc/caddy/Caddyfile.

4.3 Serveur principal — cahute (192.168.1.9)

État de la migration vers 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.

Arborescence Docker

/mnt/stockage/docker/
├── compose/          ← un dossier par stack (lldap, surveillance, + à venir)
└── data/             ← données persistantes (bind mounts vers le RAID)

4.4 Postes clients

Portables

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.

PC tour (×2)

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é.

Raspberry Pi 5 — ''homeassistant'' (192.168.1.67)

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.

5. Services et points d'accès

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.

6. Authentification et droits

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.

7. Sécurité

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.

7.1 Règles UFW du serveur (état réel)

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 :

7.2 Filtrage des ports Docker (DOCKER-USER)

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 :

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

7.3 Exports NFS

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.

8. Particularités et incidents connus