Migrer ses DNS de CloudFlare vers son infra en moins de deux heures.

Si vous me suivez régulièrement, vous savez que je suis une grande adepte de l'auto-hébergement et de l'Open Source. Pour preuve, j'héberge dans mon propre quart de baie un maximum de services que j'utilise au quotidien, et je permets aussi aux personnes de ma communauté d'utiliser certains services hébergées (BBB, GitLab, Etherpad...).

Il y a quelques jours, j'ai effectué le transfert d'un de mes domaines (parmi mes 10+ domaines que je possède !), d'un registrar à un autre. La migration s'étant un peu faite à l'arrache (le transfert s'étant effectué le jour où le domaine devait tomber), je n'ai pas réussi à migrer correctement mes zones DNS d'un registrar à un autre. Et, au lieu de refaire la zone sur Cloudflare, comme j'aurais fait habituellement, je me suis dit "ne serais-ce pas le moment de passer sur mes propres serveurs DNS ?"
Eh bah voila, c'est l'histoire que je vais vous raconter maintenant !

État des lieux

Actuellement, sur la dizaine de domaines que je possède, la plupart des NS (Name Server) étaient chez Cloudflare. Pourquoi ? C'était le moyen le plus simple que j'avais trouvé à l'époque (genre 2017-2018, quand je n'étais qu'un bébé dans le monde de la tech) de centraliser en un endroit la gestion de mes domaines. Le temps est passé, et c'est resté comme ça, malgré que l'idée d'héberger mes propres NS trottait dans ma tête.

Lorsque j'ai eu mes IPv4 et IPv6, j'ai dû monter mon propre serveur DNS, pour pouvoir héberger les reverses DNS de mes IPs.
Le reverse DNS, est, comme son nom l'indique, le contraire d'une requête DNS classique. Au lieu de demander au serveur DNS de nous traduire un domaine en une adresse IP, nous allons lui demander de traduire une IP en un domaine. Ce système est beaucoup utilisé pour les serveurs mail, afin de vérifier l'expéditeur du mail.

# Une résolution classique
cecile@Grille-Pain:~$ dig +noall +answer mail.cecilemorange.fr
mail.cecilemorange.fr.	300	IN	A	185.119.254.150
# Et son "inverse"
cecile@Grille-Pain:~$ dig +noall +answer -x 185.119.254.150
150.254.119.185.in-addr.arpa. 86400 IN	PTR	mail.cecilemorange.fr.

Pour ce serveur DNS, j'avais installé bind9, qui a l'avantage d'être simple d'installation et de configuration. Un fichier de zone ressemble à ceci :

$TTL 86400
254.119.185.in-addr.arpa.       IN      SOA     ns1.as208069.net.  contact.ataxya.net. (
                             43         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
;
254.119.185.in-addr.arpa.       IN      NS      ns1.as208069.net.
254.119.185.in-addr.arpa.       IN      NS      ns2.as208069.net.

1       IN      PTR     routeur.as208069.net.
66      IN	PTR	le-super-serveur-irc.as208069.net.
[...]

Jusqu'à là, cela me convenait. Mais, j'avais envie de tester autre chose. J'avais repéré PowerDNS, qui me semblait fort sympathique, avec en plus une possibilité d'avoir une interface web (https://pdnsmanager.org/), qui se connecte directement à la base de donnée SQL de PowerDNS.
PowerDNS possède également une API et un provider Terraform, ce qui est intéressant pour l'automatisation.

Allez, créons une nouvelle VM dans mon infra, et installons tout ça !

Installation du nouveau serveur DNS

Prérequis :

  • Une VM sur Debian
  • Une IP publique

Nous allons commencer par installer les packages dont nous avons besoin pour la partie web manager

apt install mariadb-server apache2 php php-apcu php-json php-mysql

Une fois les packages installés, nous allons télécharger le web manager et l'installer

wget https://dl.pdnsmanager.org/pdnsmanager-2.1.0.tar.gz
tar xzvf pdnsmanager-2.1.0.tar.gz
cp -r pdnsmanager-2.1.0/* /var/www/html/
chown -R www-data /var/www/html/
# Il faut également activer le module rewrite
a2enmod rewrite

Ensuite, la configuration apache :

<VirtualHost _default_:80>
    ServerAdmin noc@example.net

    ServerName pdns.example.com

    DocumentRoot /var/www/html/frontend

    RewriteEngine On
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
    RewriteRule !^/api/\.* /index.html [L]

    Alias /api /var/www/html/backend/public
    <Directory /var/www/html/backend/public>
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^ index.php [QSA,L]
    </Directory>

</VirtualHost>

Vous pouvez ensuite redémarrer Apache, puis passer à la configuration du MySQL :

MariaDB [(none)]> CREATE DATABASE `powerdnsadmin` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON `powerdnsadmin`.* TO 'pdnsadminuser'@'localhost' IDENTIFIED BY 'VotreSuperMotDePasse';
FLUSH PRIVILEGES;

Ensuite, allez sur http://votre.ip/setup, et remplissez les champs avec les données entrés précédemment :

Si tout est bon, vous allez être redirigé sur la page de login, et nous pouvons passer à l'installation de PowerDNS !

apt-get install pdns-server pdns-backend-mysql

Ensuite, éditez la conf dans /etc/powerdns/pdns.conf

allow-axfr-ips=127.0.0.0/8,::1,ipslave #nous verrons par la suite l'installation d'un slave
config-dir=/etc/powerdns
daemon=yes
disable-axfr=no
guardian=yes
local-address=0.0.0.0
local-port=53
master=yes
slave=no
module-dir=/usr/lib/x86_64-linux-gnu/pdns
setgid=pdns
setuid=pdns
socket-dir=/var/run/pdns
version-string=powerdns
include-dir=/etc/powerdns/pdns.d
launch=
#N'oubliez pas le retour à la ligne

Il faut également supprimer quelques fichiers par défaut :

rm /etc/powerdns/named.conf /etc/powerdns/pdns.d/bind.conf

(Cette conf par défaut utilise le backend bind, et pour éviter les confits avec notre backend MySQL, il faut supprimer les fichiers)

Ensuite, éditer le fichier /etc/powerdns/pdns.d/pdns.local.gmysql.conf et mettez-y les mêmes informations que précédemment :

launch=gmysql

gmysql-host=localhost
gmysql-port=3306
gmysql-dbname=powerdnsadmin
gmysql-user=pdnsadminuser
gmysql-password=VotreSuperMotDePasse
gmysql-dnssec=no

Vous pouvez alors redémarrer le service pdns

Vous allez pouvoir créer votre première zone ! Retournez sur votre manager web, cliquer sur "Master" et remplissez les informations demandées :

Création d'un deuxième serveur DNS slave

L'installation est sensiblement la même, avec quelques subtilités :

Dans le fichier  /etc/powerdns/pdns.conf, remplacez ces lignes :

allow-axfr-ips=127.0.0.0/8,::1,ipdevotremaster
master=no
slave=yes

Et pour la partie web, au lieu de créer une zone master, vous allez créer une zone slave, et renseigner l'IP de votre master :

La synchronisation devrait alors se faire automatiquement.

Conclusion

Et voilà, vous avez vos propres serveurs de nom ! N'oubliez pas d'indiquer vos nouveaux NS sur le panel de gestion de votre domaine. Par exemple chez OVH :

Notez que la propagation DNS peut prendre un peu de temps, donc ne paniquez pas si vos changements ne se voient pas instantanément !

Et ensuite ?

Il me reste quelques petites choses à faire pour que mes serveurs DNS soient parfaits. Actuellement, sur mes 3 NS, il n'y en a qu'un qui supporte et répond en IPv6, les deux autres NS étant chez d'autres providers qui ne propose pas d'IPv6 (pour l'instant, j'espère !). Il va me falloir pousser ces deux providers à me fournir de l'IPv6, ou en trouver d'autre qui peuvent me proposer une dual stack.
Il me reste également à migrer tous mes noms de domaine que je possède sur mes propres NS !

Bonus : Autorisez l'accès au service web seulement depuis votre IP

Je vous recommande de limiter l'accès à la page web de votre serveur à seulement certaines IPs (les vôtres ou votre bastion par exemple). Dans mon cas, je suis allée au plus simple, avec iptables:

#En IPv4
iptables --append INPUT --protocol tcp --src 198.51.100.0//24 --dport 80 --jump ACCEPT
iptables --append INPUT --protocol tcp --dport 80 --jump REJECT
iptables --append INPUT --protocol tcp --src 198.51.100.0//24 --dport 443 --jump ACCEPT
iptables --append INPUT --protocol tcp --dport 443 --jump REJECT

#Et en IPv6
ip6tables --append INPUT --protocol tcp --src 2001:db8::/32 --dport 80 --jump ACCEPT
ip6tables --append INPUT --protocol tcp --dport 80 --jump REJECT
ip6tables --append INPUT --protocol tcp --src 2001:db8::/32 --dport 443 --jump ACCEPT
ip6tables --append INPUT --protocol tcp --dport 443 --jump REJECT
#N'oubliez pas de remplacer les IPs de documentation par les vôtres :)

Vous pouvez vérifier votre configuration avec iptables -nvL, puis rendez votre config iptables persistante :

iptables-save 
ip6tables-save
Afficher les commentaires