TL;DRHéberger soi-même les DNS de son domaine avec BIND 9, c'est garder la main sur chaque enregistrement. Voici la méthode complète sur Debian, du premier apt install à la délégation chez le registrar, avec les configurations testées et les contrôles que nous appliquons à nos propres serveurs ns1 et ns2.

BIND 9, qu'est-ce que c'est ?#

BIND (Berkeley Internet Name Domain) est l'un des logiciels de serveur DNS les plus anciens et les plus répandus, publié en open source par l'ISC (Internet Systems Consortium). Son démon s'appelle named. Il sait jouer deux rôles très différents : résolveur (il cherche des réponses sur Internet pour le compte de vos postes) et serveur faisant autorité (il publie les enregistrements de vos propres domaines, ceux que le monde entier vient interroger).

Ce tutoriel couvre le second cas : héberger vous-même les zones DNS de example.com sur deux serveurs Debian, un primaire (ns1) où vous éditez la zone et un secondaire (ns2) qui en reçoit une copie automatiquement. Si vous cherchez d'abord à comprendre le rôle d'un serveur DNS, commencez par notre article d'introduction aux serveurs DNS.

Les exemples utilisent les plages réservées à la documentation : le domaine example.com, les adresses IPv4 192.0.2.x (RFC 5737) et IPv6 2001:db8:: (RFC 3849). Remplacez-les par les vôtres.

L'architecture : un primaire, un secondaire, une délégation#

Un domaine doit être servi par au moins deux serveurs de noms, de préférence sur des réseaux différents, pour qu'une panne ne le rende pas introuvable. Le schéma suivant montre qui parle à qui.

Schéma : le registrar publie NS et glue dans la zone .com ; ns1 envoie un NOTIFY à ns2 qui récupère la zone par AXFR/IXFR signé TSIG ; le résolveur du visiteur interroge la zone parente puis ns1 ou ns2
Primaire, secondaire et délégation chez le registrar. Schéma simplifié.
  1. Vous modifiez la zone sur ns1 et incrémentez son serial.
  2. ns1 envoie un NOTIFY à ns2, qui compare les serials et demande un transfert de zone (AXFR complet ou IXFR incrémental), authentifié par une clé TSIG.
  3. Chez le registrar, vous déclarez ns1 et ns2 comme serveurs du domaine, avec leurs adresses (glue records) puisqu'ils sont eux-mêmes dans example.com.
  4. Le résolveur d'un visiteur apprend de la zone .com qui gère example.com, puis interroge ns1 ou ns2 indifféremment.
ÉlémentRôleOù le configurer
Primaire (ns1)Détient le fichier de zone de référencenamed.conf.local + fichier db.example.com
Secondaire (ns2)Copie la zone, répond à égalité avec ns1named.conf.local de ns2 (aucun fichier à écrire)
Clé TSIGAuthentifie NOTIFY et transferts entre les deuxFichier de clé identique sur ns1 et ns2
NS + glueDélègue le domaine à vos serveursInterface du registrar
Pare-feuLaisse passer les requêtesPort 53 en UDP et en TCP sur les deux serveurs

Étape 1 : installer BIND 9 sur Debian#

Sur chacun des deux serveurs, installez le serveur, les outils de vérification (named-checkconf, named-checkzone, tsig-keygen) et dig :

sudo apt update
sudo apt install bind9 bind9-utils bind9-dnsutils

named -v                       # BIND 9.20.x sur Debian 13
sudo systemctl status named    # « bind9 » n'est plus qu'un alias de named.service

Debian range la configuration dans /etc/bind/ : named.conf inclut named.conf.options (réglages globaux) et named.conf.local (vos zones). Le répertoire de travail est /var/cache/bind. La documentation du paquet conseille de placer les fichiers des zones primaires sous /etc/bind avec un chemin complet, et de laisser les zones secondaires dans le répertoire de travail avec un nom de fichier relatif.

Étape 2 : named.conf.options pour un serveur faisant autorité#

La configuration livrée par Debian est celle d'un résolveur. Pour un serveur qui publie vos zones, remplacez le contenu de /etc/bind/named.conf.options sur ns1 par ceci (la clé xfr-example est créée à l'étape 5 ; ajoutez la ligne include correspondante en tête du fichier à ce moment-là) :

// /etc/bind/named.conf.options : serveur faisant autorité uniquement
acl secondaires { 192.0.2.54; 2001:db8::54; };   // adresses de ns2

options {
	directory "/var/cache/bind";

	// N'écouter que sur les adresses utiles (et la boucle locale pour rndc et les tests)
	listen-on { 127.0.0.1; 192.0.2.53; };
	listen-on-v6 { ::1; 2001:db8::53; };

	// Pas de récursion : ce serveur ne répond que pour ses propres zones
	recursion no;
	allow-recursion { none; };
	allow-query-cache { none; };
	allow-query { any; };

	// Transferts de zone réservés aux détenteurs de la clé TSIG (voir plus bas)
	allow-transfer { key xfr-example; };
	allow-update { none; };

	// Prévenir ns2 à chaque changement de serial
	notify explicit;
	also-notify { 192.0.2.54 key xfr-example; };

	// Ne rien révéler sur le logiciel ni la machine
	version none;
	hostname none;
	server-id none;
	minimal-responses yes;

	// Limiter le débit de réponses identiques (atténue l'amplification)
	rate-limit {
		responses-per-second 20;
		window 5;
		exempt-clients { 127.0.0.1; ::1; secondaires; };
	};
};

// Signer avec la clé tout échange avec ns2
server 192.0.2.54 { keys { xfr-example; }; };

Trois lignes comptent plus que les autres :

  • recursion no; : un serveur faisant autorité n'a aucune raison de résoudre des noms pour des inconnus. Ouverte, la récursion en fait un relais pour les attaques par amplification (voir les erreurs fréquentes).
  • allow-transfer : sans restriction, n'importe qui peut télécharger votre zone complète avec dig AXFR et y découvrir tous vos sous-domaines.
  • listen-on : limitez l'écoute aux adresses publiques du serveur et à la boucle locale.

Les versions actuelles de BIND emploient les mots-clés primary, secondary et primaries à la place de master, slave et masters, encore acceptés mais à éviter dans une nouvelle configuration.

Étape 3 : déclarer la zone primaire et écrire le fichier de zone#

Déclarez la zone dans /etc/bind/named.conf.local :

// /etc/bind/named.conf.local
zone "example.com" {
	type primary;
	file "/etc/bind/zones/db.example.com";
};

Créez le dossier avec sudo mkdir /etc/bind/zones, puis le fichier de zone. Chaque ligne est commentée :

; /etc/bind/zones/db.example.com
$TTL 3600                     ; durée de cache par défaut : 1 heure
@	IN	SOA	ns1.example.com. hostmaster.example.com. (
		2026102101	; serial : AAAAMMJJnn, à incrémenter à CHAQUE modification
		7200		; refresh : le secondaire vérifie le serial toutes les 2 h
		1800		; retry : nouvel essai 30 min après un échec
		1209600		; expire : le secondaire cesse de répondre après 14 jours sans contact
		3600 )		; minimum : durée de cache des réponses négatives (NXDOMAIN)

; Serveurs de noms faisant autorité (point final obligatoire)
@	IN	NS	ns1.example.com.
@	IN	NS	ns2.example.com.

; Adresses des serveurs de noms (à déclarer aussi en glue chez le registrar)
ns1	IN	A	192.0.2.53
ns1	IN	AAAA	2001:db8::53
ns2	IN	A	192.0.2.54
ns2	IN	AAAA	2001:db8::54

; Site web
@	IN	A	192.0.2.10
@	IN	AAAA	2001:db8::10
www	IN	CNAME	example.com.

; Messagerie
@	IN	MX	10 mail.example.com.
mail	IN	A	192.0.2.25
mail	IN	AAAA	2001:db8::25
@	IN	TXT	"v=spf1 mx -all"
_dmarc	IN	TXT	"v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"

Quelques règles de syntaxe à garder en tête :

  • @ désigne le domaine lui-même (l'« origine » de la zone).
  • Un nom qui se termine par un point est complet (mail.example.com.) ; sans point, BIND lui ajoute l'origine (mail devient mail.example.com.).
  • Dans le SOA, l'adresse e-mail du responsable s'écrit avec un point à la place de l'arobase : hostmaster.example.com. correspond à hostmaster@example.com.
  • Un CNAME ne peut pas coexister avec un autre enregistrement sur le même nom : c'est pour cela que l'apex (@) porte des A/AAAA, et www un CNAME.
Champ du SOAValeur de l'exempleCe qu'il règle
serial2026102101Numéro de version de la zone ; le secondaire ne recopie que s'il augmente. Convention recommandée par la RFC 1912 : AAAAMMJJnn.
refresh7200 (2 h)Fréquence à laquelle le secondaire vérifie le serial, en plus des NOTIFY.
retry1800 (30 min)Délai avant un nouvel essai si le primaire n'a pas répondu.
expire1209600 (14 jours)Au-delà, sans contact avec le primaire, le secondaire cesse de servir la zone. La RFC 1912 suggère 2 à 4 semaines.
minimum3600 (1 h)Durée de cache des réponses négatives (« ce nom n'existe pas »), selon la RFC 2308.

Les enregistrements TXT de l'exemple (SPF et DMARC) servent à la délivrabilité des e-mails ; ils sont expliqués dans notre guide SPF, DKIM et DMARC.

Étape 4 (optionnelle) : la zone inverse#

La zone inverse associe une adresse IP à un nom (enregistrement PTR), ce que vérifient notamment les serveurs de messagerie. Elle n'est utile que si le bloc d'adresses vous a été délégué : pour une IP louée chez un hébergeur ou un fournisseur cloud, le PTR se règle presque toujours dans son interface, pas dans votre BIND. Si le bloc 192.0.2.0/24 vous appartient :

// à ajouter dans /etc/bind/named.conf.local
zone "2.0.192.in-addr.arpa" {
	type primary;
	file "/etc/bind/zones/db.192.0.2";
};

; /etc/bind/zones/db.192.0.2 : on n'écrit que le dernier octet de l'adresse
$TTL 3600
@	IN	SOA	ns1.example.com. hostmaster.example.com. ( 2026102101 7200 1800 1209600 3600 )
@	IN	NS	ns1.example.com.
@	IN	NS	ns2.example.com.
10	IN	PTR	example.com.
25	IN	PTR	mail.example.com.
53	IN	PTR	ns1.example.com.

Étape 5 : le secondaire, avec une clé TSIG#

Une clé TSIG (RFC 8945) est un secret partagé qui signe les NOTIFY et les transferts : ns1 ne livre la zone qu'à qui présente la clé, et ns2 n'accepte de NOTIFY que signé. C'est plus robuste qu'un filtrage par adresse IP seule.

# Sur ns1 : générer la clé partagée (HMAC-SHA256)
tsig-keygen -a hmac-sha256 xfr-example | sudo tee /etc/bind/xfr-example.key
sudo chown root:bind /etc/bind/xfr-example.key
sudo chmod 640 /etc/bind/xfr-example.key

# Contenu obtenu (le secret réel est une chaîne base64 aléatoire) :
# key "xfr-example" {
# 	algorithm hmac-sha256;
# 	secret "REMPLACEZ-PAR-VOTRE-SECRET";
# };

# Copier ce fichier à l'identique sur ns2 (scp, puis mêmes droits),
# et l'inclure en tête de /etc/bind/named.conf.options sur les DEUX serveurs :
# include "/etc/bind/xfr-example.key";

Sur ns2, la configuration est courte : le secondaire n'a pas de fichier de zone à écrire, named le crée lui-même dans /var/cache/bind après le premier transfert.

// ns2 : /etc/bind/named.conf.options (extrait)
include "/etc/bind/xfr-example.key";

options {
	directory "/var/cache/bind";
	listen-on { 127.0.0.1; 192.0.2.54; };
	listen-on-v6 { ::1; 2001:db8::54; };
	recursion no;
	allow-recursion { none; };
	allow-query-cache { none; };
	allow-transfer { none; };      // ns2 ne redistribue la zone à personne
	version none;
};

server 192.0.2.53 { keys { xfr-example; }; };

// ns2 : /etc/bind/named.conf.local
zone "example.com" {
	type secondary;
	primaries { 192.0.2.53 key xfr-example; };
	file "db.example.com";         // relatif à /var/cache/bind, écrit par named
};

Bon à savoir. Avec beaucoup de domaines, déclarer chaque zone à la main sur le secondaire devient fastidieux. Les catalog zones (RFC 9432), prises en charge par BIND, règlent le problème : le primaire publie une zone spéciale qui liste les autres, et le secondaire crée ou supprime automatiquement les zones correspondantes. C'est ce que nous utilisons chez Websource : nos zones clientes sont ajoutées sur ns1 avec rndc addzone, et ns2 les reprend tout seul, transferts signés par TSIG.

Étape 6 : vérifier avant de recharger#

Ne rechargez jamais BIND sans avoir contrôlé la configuration : une erreur de syntaxe peut empêcher une zone, voire le service entier, de démarrer.

# 1. Syntaxe de la configuration (aucune sortie = aucune erreur)
sudo named-checkconf

# 2. Syntaxe et cohérence de chaque zone
sudo named-checkzone example.com /etc/bind/zones/db.example.com
# zone example.com/IN: loaded serial 2026102101
# OK

# 3. Configuration ET zones d'un coup
sudo named-checkconf -z

Puis chargez la configuration et suivez le journal :

sudo systemctl restart named        # premier démarrage après la configuration
sudo rndc reload example.com        # une zone modifiée (serial incrémenté !)
sudo rndc reconfig                  # nouvelle zone ajoutée dans named.conf.local
sudo journalctl -u named -n 30      # journal : erreurs de chargement, transferts

Sur ns2, le journal doit mentionner le transfert de la zone example.com depuis 192.0.2.53, terminé avec succès (« Transfer completed »). Ensuite, interrogez directement chaque serveur avec dig :

# Le primaire répond-il avec autorité ? (drapeau « aa » attendu)
dig @192.0.2.53 example.com SOA +norec

# Le secondaire a-t-il le même serial ?
dig @192.0.2.54 example.com SOA +short

# Les enregistrements publiés
dig @192.0.2.53 example.com MX +short
dig @192.0.2.53 www.example.com +short

# La récursion doit être refusée (status: REFUSED)
dig @192.0.2.53 wikipedia.org A

# Un transfert sans clé doit échouer (« Transfer failed. »)
dig @192.0.2.53 example.com AXFR

# Avec la clé, depuis ns2 : il doit réussir
dig -k /etc/bind/xfr-example.key @192.0.2.53 example.com AXFR

# Une fois la délégation faite chez le registrar : le chemin complet
dig +trace example.com

Ce que nous avons mesuré sur nos propres serveurs#

Websource exploite BIND 9.20 sur Debian 13 pour ses serveurs ns1.websource.fr et ns2.websource.fr, en autorité seule. Voici les contrôles faits le 17 octobre 2026 sur ns1, ceux que nous vous recommandons de refaire sur votre propre serveur :

$ dig @ns1.websource.fr example.org A +rec
;; ->>HEADER<<- opcode: QUERY, status: REFUSED
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

$ dig @ns1.websource.fr version.bind chaos txt +norec
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
(aucune réponse TXT : la version n'est pas divulguée)

$ dig @ns1.websource.fr websource.fr AXFR
; Transfer failed.

Les trois réponses sont celles attendues : récursion refusée (et pas de drapeau ra), version masquée par version none;, transfert refusé à qui n'a pas la clé.

Étape 7 : ouvrir le port 53 en UDP et en TCP#

Le DNS utilise le port 53 en UDP pour la plupart des requêtes, mais aussi en TCP : pour les transferts de zone, et pour toute réponse trop grosse pour UDP (fréquent avec DNSSEC ou de longs TXT). Bloquer TCP produit des pannes intermittentes difficiles à diagnostiquer. Sur les deux serveurs :

# Avec ufw : « 53 » sans protocole ouvre UDP ET TCP
sudo ufw allow 53

# Avec nftables, dans la chaîne input de /etc/nftables.conf :
udp dport 53 accept
tcp dport 53 accept

Les ports et protocoles sont détaillés dans notre article sur le port 443, dont la logique d'ouverture vaut aussi pour le port 53.

Étape 8 : déléguer le domaine et déclarer les glue records#

Vos serveurs répondent, mais personne ne le sait encore. Chez le registrar de example.com :

  1. Déclarez les glue records (parfois appelés « hôtes » ou « GLUE ») : ns1.example.com → 192.0.2.53 et 2001:db8::53, ns2.example.com → 192.0.2.54 et 2001:db8::54. Ils sont indispensables ici, car les serveurs sont dans le domaine qu'ils servent : sans adresse publiée dans la zone parente, un résolveur ne pourrait pas les trouver.
  2. Remplacez les serveurs DNS du domaine par ns1.example.com et ns2.example.com.
  3. Vérifiez avec dig +trace example.com que la délégation aboutit bien à vos serveurs. Le changement peut prendre jusqu'à la durée de cache (TTL) des anciens NS publiés dans la zone parente : 48 heures pour un .com.

Si vos serveurs portent un nom dans un autre domaine (par exemple ns1.mon-hebergeur.net), aucune glue n'est nécessaire pour example.com : seule la déclaration des NS l'est. Avant de changer les serveurs DNS d'un domaine signé avec DNSSEC, désactivez d'abord DNSSEC chez le registrar (ou republiez la signature sur vos serveurs), sinon les résolveurs qui valident rejetteront le domaine. La procédure côté hébergement est décrite dans notre guide pour relier un nom de domaine à son hébergement.

Les erreurs les plus fréquentes#

Le serial n'a pas été incrémenté#

Vous modifiez la zone, rechargez ns1 : il sert bien la nouvelle version. Mais ns2 compare les serials, voit le même numéro et garde l'ancienne copie. Les deux serveurs répondent alors différemment, et le problème semble aléatoire selon celui que le résolveur interroge. Remède : incrémentez le serial à chaque modification, puis rndc reload example.com, et comparez dig @ns1 example.com SOA +short et dig @ns2 example.com SOA +short.

Le point final oublié#

C'est l'erreur la plus traîtresse, car la zone reste valide : sans point, BIND ajoute l'origine au nom. Nous l'avons reproduite volontairement sur la zone d'exemple :

; Erreur : point final oublié
@	IN	MX	10 mail.example.com

$ named-checkzone example.com db.example.com
zone example.com/IN: example.com/MX 'mail.example.com.example.com' has no address records (A or AAAA)
zone example.com/IN: loaded serial 2026102101
OK

named-checkzone répond « OK » : ce n'est qu'un avertissement. Le MX pointe pourtant vers mail.example.com.example.com, qui n'existe pas, et vos e-mails ne sont plus distribués. Lisez toujours les avertissements, pas seulement le verdict final.

La récursion laissée ouverte#

Un serveur qui accepte de résoudre n'importe quel nom pour n'importe qui est un résolveur ouvert. Des attaquants lui envoient de petites requêtes avec l'adresse IP de leur victime comme expéditeur falsifiée ; votre serveur renvoie des réponses bien plus volumineuses vers cette victime. C'est l'attaque par amplification DNS, que décrit la RFC 5358. recursion no; la ferme ; rate-limit (RRL) limite en plus l'amplification possible avec vos propres zones.

Autres pièges#

  • Port 53 TCP fermé : transferts impossibles, grosses réponses perdues.
  • Un seul serveur de noms, ou deux sur la même machine : la moindre panne rend le domaine introuvable.
  • Droits sur les fichiers : named tourne sous l'utilisateur bind ; il doit pouvoir lire les zones et la clé (groupe bind).
  • Transferts ouverts (allow-transfer { any; }) : votre zone entière est publique.
  • Modifier les fichiers d'une zone secondaire : ils sont écrasés au prochain transfert. On ne modifie que le primaire.

Et si vous ne voulez pas gérer BIND vous-même ?#

Monter ses propres serveurs DNS est formateur et donne un contrôle total, mais cela implique de les surveiller, de les mettre à jour et de les garder disponibles en permanence. Chez Websource, nous exploitons nos propres serveurs ns1 et ns2 pour les sites que nous hébergeons, et nos clients modifient leurs zones depuis leur espace client, avec vérification de la syntaxe avant publication. Nos offres d'hébergement web démarrent dès 4,99 € HT/mois, et le connecteur MCP permet même de gérer ses zones DNS depuis Claude. Besoin d'un serveur DNS dédié ou d'une infogérance ? Parlons-en.

Questions fréquentes#

Quelle différence entre un serveur DNS faisant autorité et un résolveur ?#

Le serveur faisant autorité publie les enregistrements des domaines qu'il gère et ne répond que pour eux. Le résolveur (récursif) interroge les serveurs faisant autorité pour le compte des utilisateurs et met les réponses en cache. Mieux vaut ne pas mélanger les deux rôles sur un même serveur exposé à Internet.

Faut-il obligatoirement deux serveurs DNS ?#

La RFC 1034 recommande qu'une zone soit servie par au moins deux serveurs, et de nombreux registres l'exigent. C'est surtout indispensable pour la disponibilité : si l'unique serveur tombe, le domaine devient introuvable. Idéalement, les deux sont sur des réseaux différents.

Comment recharger une seule zone après modification ?#

Incrémentez le serial du SOA, vérifiez le fichier avec named-checkzone, puis lancez rndc reload suivi du nom de la zone. Pour une zone nouvellement déclarée dans named.conf.local, utilisez rndc reconfig.

Pourquoi le secondaire ne prend-il pas mes modifications ?#

Le plus souvent, le serial n'a pas été incrémenté. Sinon, vérifiez que le port 53 TCP est ouvert entre les deux serveurs, que la même clé TSIG est configurée des deux côtés, et lisez le journal de named sur le secondaire.

Qu'est-ce qu'un glue record ?#

C'est l'adresse IP d'un serveur de noms, publiée dans la zone parente (par exemple .com) par le registrar. Elle est nécessaire quand le serveur porte un nom situé dans le domaine qu'il sert, comme ns1.example.com pour example.com.

Article publié le 21/10/2026 sous la signature de Jonathan Gutierrez, rédigé à partir des sources citées ci-dessus, puis relu avant publication. Une information vous semble inexacte ou datée ? Signalez-le nous, nous corrigeons.