
Introduction #
Le DNS, c’est l’annuaire téléphonique de notre réseau. Quand il tombe, tout tombe : plus de résolution de noms, plus d’accès aux services par leur nom de domaine, et souvent plus d’accès Internet du tout. Dans un homelab qui héberge une trentaine de services derrière des noms de domaine internes, un DNS qui flanche transforme une soirée détente en session de dépannage.
Avant d’en arriver là, j’ai testé à peu près tout ce que l’écosystème « tout-en-un » propose. Pi-hole d’abord, pour son blocage publicitaire réputé. AdGuard Home ensuite, plus moderne et plus complet côté filtrage. Puis dnsmasq, léger et efficace, mais dont la configuration se fait fichier par fichier. Je n’ai volontairement pas touché à Bind9 : il reste la référence, mais tout se configure à la main dans des fichiers de zone à la syntaxe… disons austère. Je voulais quelque chose de plus ergonomique.
J’ai même — histoire de rire — installé un Windows Server 2025 avec sa console de gestion DNS graphique, juste pour voir. Spoiler : ce n’était pas la réponse à mes prières pour un homelab Linux.
Dans cet article, nous allons déployer deux serveurs DNS Technitium redondants : ns1 sur un Raspberry Pi 3 Model B posé dans le réseau 010-SERVERS, et ns2 dans un conteneur LXC Debian 13 sur le nœud Proxmox Neo. Les deux nœuds se synchronisent automatiquement : nous configurons une zone une fois, elle apparaît sur les deux. Si l’un tombe, l’autre prend le relais sans que nos clients ne s’en aperçoivent.
Table des matières #
- 🌐 Architecture réseau
- 🔭 Vue d’ensemble de l’architecture
- 📋 Prérequis techniques
- 🖥️ Préparation de ns1 — Raspberry Pi 3B
- 📦 Préparation de ns2 — LXC Debian 13 sur Proxmox
- 🚀 Installation de Technitium DNS
- 🔗 Mise en cluster des deux instances
- ✅ Vérification et tests
- 🔧 Maintenance et monitoring
- 🔍 Troubleshooting
- ⚡ Optimisations et bonnes pratiques
- 🎯 Conclusion
Architecture réseau #
| Nœud | Réseau / VLAN | Adresse IP | Matériel | Rôle |
|---|---|---|---|---|
ns1 |
010-SERVERS (VLAN 10) |
10.10.10.53 |
Raspberry Pi 3B v1.2 | Nœud primaire |
ns2 |
020-VM-LXC (VLAN 20) |
10.10.20.53 |
LXC Debian 13 sur Neo | Nœud secondaire |
Le choix des adresses en .53 est un clin d’œil : 53 est le port historique du DNS. Cela rend l’inventaire réseau immédiatement lisible.
ns1 tourne sur du matériel physique dédié (RPi), alimenté indépendamment du cluster Proxmox. Même si le cluster Perfect-Homelab est entièrement à l’arrêt (maintenance, coupure), ns1 continue de résoudre les noms. C’est notre filet de sécurité DNS.
Flux réseau typique d’une requête cliente :
- Un client du homelab interroge son DNS primaire
10.10.10.53(ns1). ns1répond depuis sa zone localeallfabox.frou depuis son cache.- Si la réponse n’est pas locale,
ns1fait suivre (forward) vers un résolveur amont. - Si
ns1est injoignable, le client bascule sur son DNS secondaire10.10.20.53(ns2). ns2, synchronisé avecns1, répond de manière identique.
Vue d’ensemble de l’architecture #
graph TB
subgraph Clients["Clients du homelab"]
C1["Postes & serveurs
VLAN 10 / 20 / 30…"]
end
subgraph DNSCluster["Cluster DNS Technitium"]
NS1["ns1.dns.allfabox.fr
10.10.10.53
RPi 3B — Primary"]
NS2["ns2.dns.allfabox.fr
10.10.20.53
LXC Debian 13 — Secondary"]
end
UP["Résolveurs amont
DoH / DoT"]
C1 -->|"DNS primaire :53"| NS1
C1 -.->|"Fallback :53"| NS2
NS1 <-->|"Synchro cluster
zones + config"| NS2
NS1 -->|Forward| UP
NS2 -->|Forward| UP
style NS1 fill:#065f46,stroke:#34d399,stroke-width:2px,color:#fff
style NS2 fill:#1e3a8a,stroke:#60a5fa,stroke-width:2px,color:#fff
style C1 fill:#4c1d95,stroke:#a78bfa,stroke-width:2px,color:#fff
style UP fill:#4b5563,stroke:#9ca3af,stroke-width:2px,color:#fff
| Service | Rôle | Port(s) | Plateforme |
|---|---|---|---|
Technitium ns1 |
Serveur DNS primaire + interface d’admin | 53 (DNS), 5380 (web) | Raspberry Pi OS |
Technitium ns2 |
Serveur DNS secondaire (cluster) | 53 (DNS), 5380 (web) | Debian 13 (LXC) |
Le flux de synchronisation entre les deux nœuds, une fois le cluster monté :
sequenceDiagram
participant Admin
participant NS1 as ns1 (Primary)
participant NS2 as ns2 (Secondary)
Admin->>NS1: Crée / modifie une zone
NS1->>NS1: Enregistre la modification
NS1-->>NS2: Réplique la zone et la config
Note over NS2: ns2 est à jour automatiquement
Admin->>NS2: Ouvre l'interface web
NS2-->>Admin: Affiche la même zone
Prérequis techniques #
Nous aurons besoin de :
- Un Raspberry Pi 3 Model B (ou plus récent) sous Raspberry Pi OS 64 bits à jour
- Un nœud Proxmox VE capable de créer un conteneur LXC (ici : Neo)
- Un template Debian 13 disponible dans notre stockage Proxmox
- Un accès
root(ousudo) sur les deux machines - Deux adresses IP fixes réservées :
10.10.10.53et10.10.20.53
Compétences mobilisées :
Configuration minimale par nœud :
| Ressource | ns1 (RPi 3B) | ns2 (LXC) |
|---|---|---|
| CPU | 4 cœurs ARM (1,2 GHz) | 1 vCPU |
| RAM | 1 Go | 512 Mo |
| Disque | 16 Go (carte SD) | 8 Go |
| OS | Raspberry Pi OS 64 bits | Debian 13 |
Préparation de ns1 — Raspberry Pi 3B #
Nous nous connectons en SSH sur le Raspberry Pi, puis nous mettons le système à jour :
sudo apt update && sudo apt full-upgrade -y
Nous définissons le hostname ns1 et corrigeons le fichier /etc/hosts :
# Nomme la machine ns1
sudo hostnamectl set-hostname ns1
# Remplace l'ancien nom d'hôte dans /etc/hosts
sudo sed -i 's/raspberrypi/ns1/g' /etc/hosts
Nous nous assurons que l’adresse 10.10.10.53 est bien fixe. Le plus robuste est de la réserver côté DHCP (bail statique sur l’adresse MAC du RPi) : le Pi obtient toujours la même IP sans configuration locale fragile. Si nous préférons une IP statique locale, nous la configurons selon notre distribution (dhcpcd.conf ou NetworkManager selon la version de Raspberry Pi OS).
Nous vérifions enfin que le port 53 n’est pas déjà occupé par un résolveur local (systemd-resolved par exemple) :
sudo ss -tulpn | grep ':53'
Si systemd-resolved écoute sur le port 53, il faudra le désactiver ou le reconfigurer avant d’installer Technitium — nous y reviendrons dans le Troubleshooting.
ns1, et de l’image Debian 13 du template LXC Proxmox pour ns2, le port 53 n’est pas occupé par défaut. Ces distributions n’activent pas le résolveur stub de systemd-resolved sur le port 53, contrairement à Ubuntu où c’est le comportement par défaut. La vérification ss -tulpn | grep ':53' ci-dessus reste néanmoins le bon réflexe pour confirmer que le champ est libre avant l’installation.
Préparation de ns2 — LXC Debian 13 sur Proxmox #
Depuis le shell du nœud Proxmox Neo, nous créons le conteneur 253 :
pct create 253 iso-morpheus:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst \
--hostname ns2 \
--net0 name=eth0,bridge=vmbr0,ip=10.10.20.53/24,gw=10.10.20.1,tag=20 \
--storage datastore \
--rootfs datastore:8 \
--memory 512 \
--cores 1 \
--unprivileged 0 \
--onboot 1 \
--tags prod,ns2 \
--features nesting=1 \
--password
Décryptons les options clés :
| Option | Rôle |
|---|---|
--hostname ns2 |
Nom d’hôte du conteneur |
--net0 …,ip=10.10.20.53/24,gw=10.10.20.1,tag=20 |
IP fixe dans le VLAN 20 (tag 802.1Q) |
--rootfs datastore:8 |
Disque racine de 8 Go |
--memory 512 --cores 1 |
512 Mo de RAM, 1 vCPU |
--unprivileged 0 |
Conteneur privilégié |
--onboot 1 |
Démarre automatiquement avec le nœud |
--features nesting=1 |
Autorise l’imbrication (utile pour .NET / cgroups) |
--password |
Demande interactivement le mot de passe root |
--unprivileged 0 crée un conteneur privilégié : le root du conteneur correspond au root de l’hôte. C’est plus simple pour un service système comme un DNS, mais cela réduit l’isolation. Pour un serveur exposé, préférons un conteneur non-privilégié avec mapping UID/GID. Ici, ns2 n’est joignable que sur le réseau interne.
tag=20 place l’interface directement dans le VLAN 20 au niveau du bridge Proxmox. Assurons-nous que vmbr0 est bien configuré en VLAN-aware et que le VLAN 20 est trunké jusqu’au nœud Neo.
Nous démarrons le conteneur et ouvrons une console :
pct start 253
pct enter 253
Une fois dans le conteneur, nous le mettons à jour et installons curl :
apt update && apt full-upgrade -y
apt install -y curl
Installation de Technitium DNS #
Sur ns1 (Raspberry Pi) et sur ns2 (LXC), nous lançons la même commande :
curl -sSL https://download.technitium.com/dns/install.sh | sudo bash
Le script télécharge Technitium DNS Server 15.2, installe .NET si besoin, crée un service systemd et le démarre. En fin d’exécution, il affiche l’URL d’administration.
À la fin de l’installation, nous vérifions que le service tourne :
systemctl status dns
Nous devons voir le service active (running).
graph TD
A["curl … install.sh | sudo bash"] --> B{Détection
architecture}
B -->|ARM64| C["Installe .NET ARM"]
B -->|x86-64| D["Installe .NET x64"]
C --> E["Télécharge Technitium 15.2"]
D --> E
E --> F["Crée le service systemd 'dns'"]
F --> G["Démarre et écoute :53 + :5380"]
style A fill:#1e3a8a,stroke:#60a5fa,stroke-width:2px,color:#fff
style G fill:#14532d,stroke:#4ade80,stroke-width:2px,color:#fff
Nous ouvrons maintenant l’interface web de chaque nœud dans notre navigateur :
ns1:http://10.10.10.53:5380ns2:http://10.10.20.53:5380
Au premier lancement, Technitium nous invite à créer le compte administrateur (admin) et à définir son mot de passe.
Nommer chaque serveur #
Avant de créer le cluster, nous donnons à chaque nœud son nom de domaine complet. Sur ns1, nous allons dans Settings → General :
DNS Server Domain Name : ns1.dns.allfabox.fr
Et sur ns2 :
DNS Server Domain Name : ns2.dns.allfabox.fr
Mise en cluster des deux instances #
Le principe : ns1 est le primaire, ns2 le secondaire. Nous déclarons le cluster sur le primaire, puis nous y rattachons le secondaire.
Sur ns1 (http://10.10.10.53:5380), nous nous rendons dans Settings → Cluster (ou Administration → Cluster selon la disposition de la version 15.2) et renseignons :
Cluster Domain : dns.allfabox.fr
Primary Node : ns1.dns.allfabox.fr (10.10.10.53)
Nous générons ensuite le jeton de cluster (cluster token) sur le primaire — c’est le secret qui autorise un secondaire à rejoindre le groupe.
Sur ns2 (http://10.10.20.53:5380), nous rejoignons le cluster en pointant vers le primaire :
Cluster Domain : dns.allfabox.fr
Primary Node IP : 10.10.10.53
Cluster Token : <jeton copié depuis ns1>
Nous validons. ns2 contacte ns1, s’authentifie avec le jeton, et récupère la configuration et les zones existantes.
Le déroulé complet de la mise en cluster :
sequenceDiagram
participant Admin
participant NS1 as ns1 (Primary · 10.10.10.53)
participant NS2 as ns2 (Secondary · 10.10.20.53)
Admin->>NS1: Déclare le cluster dns.allfabox.fr
NS1-->>Admin: Génère le cluster token
Admin->>NS2: Rejoint le cluster (IP primaire + token)
NS2->>NS1: Authentification via token
NS1-->>NS2: Réplique config + zones
Note over NS1,NS2: Cluster actif — synchronisation continue
ns1. Elle doit apparaître sur ns2 en quelques secondes, sans intervention. C’est la preuve que la réplication fonctionne.
Créer la zone locale allfabox.fr #
Sur ns1, nous allons dans Zones → Add Zone, créons une zone Primary nommée allfabox.fr, et ajoutons nos enregistrements internes (par exemple les A des services du homelab). Grâce au cluster, ces enregistrements se propagent immédiatement sur ns2.
ns1 et ns2 eux-mêmes dans la zone dns.allfabox.fr (A → 10.10.10.53 et A → 10.10.20.53) pour que les FQDN des serveurs se résolvent correctement.
Vérification et tests #
Test de résolution sur chaque nœud (depuis n’importe quelle machine du réseau) :
# Résolution d'un nom public via ns1
dig @10.10.10.53 google.fr +short
# Même requête via ns2
dig @10.10.20.53 google.fr +short
# Résolution d'un enregistrement local (zone allfabox.fr)
dig @10.10.10.53 ns1.dns.allfabox.fr +short
dig @10.10.20.53 ns1.dns.allfabox.fr +short
Les deux nœuds doivent renvoyer des réponses cohérentes. La résolution du nom local ns1.dns.allfabox.fr doit fonctionner identiquement sur les deux serveurs — c’est la validation concrète du cluster.
Test de synchronisation : nous ajoutons un enregistrement A test.allfabox.fr → 10.10.10.99 sur ns1, puis nous interrogeons ns2 :
dig @10.10.20.53 test.allfabox.fr +short
# Doit renvoyer 10.10.10.99 sans l'avoir créé sur ns2
Test de bascule : nous arrêtons le service DNS sur ns1 et vérifions que ns2 répond toujours :
# Sur ns1
sudo systemctl stop dns
# Depuis un client — ns2 doit continuer à répondre
dig @10.10.20.53 google.fr +short
# Puis on relance ns1
sudo systemctl start dns
ns2 répond alors que ns1 est arrêté, notre redondance est opérationnelle. N’oublions pas de distribuer les deux adresses (10.10.10.53 primaire, 10.10.20.53 secondaire) à nos clients via le DHCP.
Maintenance et monitoring #
Mise à jour de Technitium — la même commande qu’à l’installation met à jour vers la dernière version, sur chaque nœud :
curl -sSL https://download.technitium.com/dns/install.sh | sudo bash
ns2 redémarre pour sa mise à jour, ns1 continue de résoudre. Nous obtenons des mises à jour sans coupure de service.
Surveiller le service :
systemctl status dns
journalctl -u dns -f
Sauvegarde — Technitium permet d’exporter toute sa configuration (zones, réglages, listes) depuis Settings → Backup/Restore. Planifions un export régulier du primaire ns1.
Le tableau de bord web offre déjà un excellent monitoring visuel : requêtes totales, taux de cache, clients, requêtes bloquées. Nous pouvons d’ailleurs remonter ces métriques dans un dashboard homelab — voir l’article dédié au widget Homepage pour Technitium.
Troubleshooting #
dns ne démarre pas, ou l’installation échoue avec une erreur « address already in use » sur le port 53.
Cause : Un résolveur local (systemd-resolved) occupe déjà le port 53. C’est le comportement par défaut sur Ubuntu. En revanche, avec les images officielles Raspberry Pi OS et le template Debian 13 utilisés ici, le port 53 est normalement libre — si nous rencontrons ce symptôme, c’est probablement qu’un systemd-resolved a été activé manuellement ou hérité d’une configuration antérieure.
Solution :
# Vérifier qui écoute sur le port 53
sudo ss -tulpn | grep ':53'
# Si systemd-resolved est en cause, le désactiver
sudo systemctl disable --now systemd-resolved
# Restaurer un /etc/resolv.conf classique
sudo rm /etc/resolv.conf
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf
# Relancer Technitium
sudo systemctl restart dns
ss -tulpn | grep ':53') avant de lancer l’installation. Cela nous évite de chercher pendant vingt minutes pourquoi le service refuse de démarrer.
Arbre de décision pour un DNS qui ne répond pas :
flowchart TD
A["Le DNS ne répond pas"] --> B{"systemctl status dns
= running ?"}
B -->|Non| C{"Port 53 occupé ?"}
C -->|Oui| D["Désactiver systemd-resolved"]
C -->|Non| E["Lire journalctl -u dns"]
B -->|Oui| F{"dig @IP local
répond ?"}
F -->|Non| G["Vérifier pare-feu / VLAN"]
F -->|Oui| H["Vérifier la route
client → serveur"]
style A fill:#7f1d1d,stroke:#f87171,stroke-width:2px,color:#fff
style D fill:#14532d,stroke:#4ade80,stroke-width:2px,color:#fff
style H fill:#14532d,stroke:#4ade80,stroke-width:2px,color:#fff
FAQ
ns2 peut joindre ns1 sur le réseau (ping 10.10.10.53 depuis ns2). La communication inter-VLAN 20 → 10 doit être autorisée par notre pare-feu. Vérifions aussi que le jeton de cluster est correct.
ns2 et ns1 est autorisé par les règles de pare-feu inter-zones.
Optimisations et bonnes pratiques #
- Chiffrer les requêtes amont : configurons les forwarders de Technitium en DNS-over-HTTPS (DoH) ou DNS-over-TLS (DoT). Nos résolutions sortantes ne transitent plus en clair.
- Restreindre l’interface d’admin : limitons l’accès au port
5380aux VLANs d’administration via le pare-feu. L’interface web ne devrait pas être joignable depuis les VLANs clients ou IoT. - Blocage publicitaire : Technitium intègre un système de listes de blocage (comme Pi-hole). Activons quelques listes réputées dans Settings → Blocking — configurées une fois sur le primaire, elles se répliquent sur le secondaire.
- Cache prefetch : activons le rafraîchissement anticipé du cache pour servir des réponses fraîches sans latence sur les domaines les plus demandés.
- Sauvegarde régulière : automatisons l’export de configuration du primaire et stockons-le hors de la carte SD du RPi.
ns1. L’intérêt du cluster est perdu si le secondaire n’est pas distribué. Configurons notre DHCP pour annoncer 10.10.10.53 et 10.10.20.53.
Conclusion #
Ce que nous avons accompli :
- Déployé
ns1sur Raspberry Pi 3B dans le VLAN SERVERS (10.10.10.53) - Déployé
ns2dans un LXC Debian 13 sur Proxmox Neo (10.10.20.53) - Installé Technitium DNS 15.2 en une commande sur les deux nœuds
- Mis les deux instances en cluster avec réplication automatique des zones
- Validé la redondance en simulant la panne du primaire
Ressources utiles :