Journal complet
· 5 min de lecture

Configurer un Dynamic DNS Cloudflare sous Debian avec systemd

Un DDNS maison sous Debian : script Bash, API Cloudflare et timer systemd pour garder un enregistrement A à jour malgré une IP publique dynamique.

Aussi disponible en English

Lorsqu’on utilise un ordinateur portable ou un serveur derrière une connexion Internet avec une adresse IP publique dynamique, l’adresse peut changer à tout moment.

L’objectif est donc simple :

arthur-perrot.example.com
        ↓
Adresse IPv4 publique actuelle

Le PC vérifie régulièrement son IP publique et, lorsqu’elle change, met automatiquement à jour l’enregistrement DNS correspondant chez Cloudflare.

Dans ce guide, nous allons réaliser ce DDNS avec un simple script Bash, l’API Cloudflare et un timer systemd sous Debian.

Prérequis

Il faut :

  • un domaine dont le DNS est géré par Cloudflare ;
  • Debian ou une distribution utilisant systemd ;
  • curl ;
  • jq ;
  • un token API Cloudflare.

Installation des dépendances :

sudo apt update
sudo apt install curl jq

Dans les exemples, nous utiliserons :

Zone DNS : example.com
Record   : arthur-perrot.example.com

1. Créer le token API Cloudflare

Depuis Cloudflare, créer un API Token ayant uniquement les permissions nécessaires sur la zone concernée.

Permissions recommandées :

Zone → DNS → Edit
Zone → Zone → Read

Il est préférable de limiter le token à une seule zone DNS plutôt que de lui donner accès à l’ensemble du compte.

On peut vérifier que le token fonctionne :

export CF_API_TOKEN='cfat_xxxxxxxxxxxxxxxxx'

curl -s \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  "https://api.cloudflare.com/client/v4/zones?name=example.com" | jq

Cloudflare doit retourner notamment :

{
  "success": true
}

La réponse contient également l’identifiant de la zone :

"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Conservez ce Zone ID, nous allons l’utiliser directement dans le script.

2. Créer l’enregistrement DNS

Créer dans Cloudflare un enregistrement A, par exemple :

Type : A
Name : arthur-perrot
IPv4 : 1.2.3.4
TTL  : Auto

L’adresse initiale importe peu : le script la remplacera lors de sa première exécution.

On pourra vérifier la résolution avec :

dig +short arthur-perrot.example.com @1.1.1.1

Par exemple :

1.2.3.4

3. Créer le script DDNS

Créons notre script :

sudo nano /usr/local/bin/cloudflare-ddns

Contenu :

#!/bin/bash

set -e

TOKEN="$CF_API_TOKEN"
ZONE_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
RECORD="arthur-perrot.example.com"

# Récupération de l'IPv4 publique
IP=$(curl -fsS -4 https://api.ipify.org)

# Recherche de l'identifiant du record DNS
RECORD_ID=$(curl -fsS \
  -H "Authorization: Bearer $TOKEN" \
  "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=A&name=$RECORD" \
  | jq -r '.result[0].id')

if [ "$RECORD_ID" = "null" ] || [ -z "$RECORD_ID" ]; then
    echo "Record $RECORD introuvable"
    exit 1
fi

# Récupération de l'adresse actuellement publiée
CURRENT=$(curl -fsS \
  -H "Authorization: Bearer $TOKEN" \
  "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
  | jq -r '.result.content')

# Rien à faire si l'adresse n'a pas changé
if [ "$CURRENT" = "$IP" ]; then
    echo "IP inchangée : $IP"
    exit 0
fi

# Mise à jour du record Cloudflare
curl -fsS -X PATCH \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
  --data "{\"content\":\"$IP\"}" \
  | jq -e '.success' >/dev/null

echo "$RECORD : $CURRENT -> $IP"

Rendre le script exécutable :

sudo chmod 700 /usr/local/bin/cloudflare-ddns

Le fonctionnement est volontairement simple :

Récupération de l'IP publique
              ↓
Lecture du record Cloudflare
              ↓
      IP identique ?
        ↙           ↘
      Oui           Non
       ↓             ↓
   Ne rien       Mise à jour
    faire        Cloudflare

4. Stocker le token séparément

Il est préférable de ne pas mettre le token Cloudflare directement dans le script.

Créer :

sudo nano /etc/cloudflare-ddns.env

Avec :

CF_API_TOKEN=cfat_xxxxxxxxxxxxxxxxx

Restreindre ensuite les permissions :

sudo chown root:root /etc/cloudflare-ddns.env
sudo chmod 600 /etc/cloudflare-ddns.env

Ainsi, seul root peut lire le token.

5. Créer le service systemd

Créer :

sudo nano /etc/systemd/system/cloudflare-ddns.service

Avec :

[Unit]
Description=Cloudflare DDNS updater
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
EnvironmentFile=/etc/cloudflare-ddns.env
ExecStart=/usr/local/bin/cloudflare-ddns

Puis recharger systemd :

sudo systemctl daemon-reload

Testons le service manuellement :

sudo systemctl start cloudflare-ddns

Puis :

systemctl status cloudflare-ddns

Un résultat comme celui-ci indique que tout fonctionne :

Starting cloudflare-ddns.service - Cloudflare DDNS updater...
arthur-perrot.example.com : 1.2.3.4 -> 203.0.113.42
Deactivated successfully.
Finished cloudflare-ddns.service - Cloudflare DDNS updater.

Lors des exécutions suivantes, si l’IP n’a pas changé :

IP inchangée : 203.0.113.42

Il est normal que le service apparaisse ensuite comme :

inactive (dead)

Il s’agit d’un service oneshot : il effectue son travail puis se termine.

6. Exécuter automatiquement le DDNS toutes les 5 minutes

Nous pouvons maintenant utiliser un timer systemd.

Créer :

sudo nano /etc/systemd/system/cloudflare-ddns.timer

Avec :

[Unit]
Description=Update Cloudflare DDNS every 5 minutes

[Timer]
OnBootSec=30s
OnUnitActiveSec=5min
Persistent=true

[Install]
WantedBy=timers.target

Activer le timer :

sudo systemctl daemon-reload
sudo systemctl enable --now cloudflare-ddns.timer

Vérifier son état :

systemctl status cloudflare-ddns.timer

On doit obtenir :

Active: active (waiting)

Pour connaître la prochaine exécution :

systemctl list-timers cloudflare-ddns.timer

Par exemple :

NEXT                        LEFT     UNIT
Tue 17:43:20 EDT            4min     cloudflare-ddns.timer

7. Vérifier les logs

Les exécutions du script sont enregistrées dans le journal systemd.

Afficher les dernières exécutions :

journalctl -u cloudflare-ddns.service -n 20

Suivre les prochaines exécutions en direct :

journalctl -fu cloudflare-ddns.service

Pour afficher uniquement les événements depuis le dernier démarrage :

journalctl -b -u cloudflare-ddns.service

8. Vérifier après un reboot

Le timer étant activé avec :

sudo systemctl enable --now cloudflare-ddns.timer

il redémarrera automatiquement avec Debian.

On peut vérifier :

systemctl is-enabled cloudflare-ddns.timer
systemctl is-active cloudflare-ddns.timer

Résultat attendu :

enabled
active

Environ 30 secondes après le démarrage, une première vérification sera effectuée. Ensuite, le script sera exécuté toutes les cinq minutes.

9. Vérifier le résultat

Afficher l’IPv4 publique :

curl -4 -s https://api.ipify.org
echo

Puis vérifier le DNS :

dig +short arthur-perrot.example.com @1.1.1.1

Les deux valeurs doivent correspondre :

203.0.113.42
203.0.113.42

Le fonctionnement final est donc :

                    ┌─────────────────┐
                    │   PC Debian     │
                    └────────┬────────┘
                             │
                     toutes les 5 min
                             │
                             ▼
                    IP publique actuelle
                             │
                             ▼
                   Comparaison Cloudflare
                             │
                    ┌────────┴────────┐
                    │                 │
               identique          différente
                    │                 │
                    ▼                 ▼
                 rien          Cloudflare API
                                      │
                                      ▼
                         arthur-perrot.example.com
                                      │
                                      ▼
                            nouvelle IPv4 publique

Cette solution a l’avantage de n’utiliser aucun daemon DDNS supplémentaire : seulement curl, jq, quelques lignes de Bash et les mécanismes natifs de systemd.

Elle convient notamment à un laptop qui change régulièrement de réseau : domicile, partage de connexion, Wi-Fi extérieur, etc.

Il faut cependant garder à l’esprit que le DDNS ne contourne pas le NAT ou les restrictions du réseau. Le nom DNS pointera bien vers l’adresse IP publique utilisée par le laptop, mais cela ne garantit pas que les connexions entrantes vers celui-ci soient possibles, notamment derrière un CGNAT ou un réseau qui bloque les connexions entrantes.

S'abonner en RSS

DESSINÉ PAR A. PERROTRSS · © 2026 — RÉV. 11/2026