Aller au contenu
Configurer le réseau d'un serveur

Configurer le réseau d'un serveur

À la fin, vous saurez

  • Identifier la pile qui configure le réseau d'une machine (netplan et systemd-networkd, ifupdown, NetworkManager) et ce que cloud-init y écrit
  • Lire l'état du réseau avec ip -br addr, ip route, ip neigh, networkctl et resolvectl, et expliquer chaque champ
  • Écrire une configuration netplan pour l'interface du réseau privé, une route statique et des serveurs DNS, et l'appliquer à distance avec netplan try
  • Empêcher cloud-init d'écraser une configuration réseau ou un nom d'hôte posés à la main
  • Expliquer le trajet d'une résolution de nom : NSS, /etc/hosts, /etc/resolv.conf, stub de systemd-resolved, serveurs par lien
  • Diagnostiquer une panne réseau couche par couche : lien, adresse, route, voisin, résolution, port

Prérequis

Testé avec cloud-init 25.1.4 debian 13 ifupdown 0.8.44 (Debian) iproute2 6.1.0 (Ubuntu) / 6.15.0 (Debian) netplan 1.1.2 systemd 255 (Ubuntu) / 257 (Debian) ubuntu 24.04 , vérifié le 7 octobre 2026

Pourquoi

Dans la fiche que Camille a laissée, la ligne « réseau » tient en trois mots : « DHCP, rien à faire ». C'était vrai le jour de la création des instances. Depuis, quelqu'un a ajouté une entrée dans /etc/hosts de sig-app-1 pour joindre la base par un nom, une route a été posée à la main avec ip route add pour un test avec le réseau de la mairie, et sig-outils a reçu une adresse fixe sur le réseau privé dans un fichier dont personne ne se souvient. Rien de cela n'est documenté, et une partie disparaîtra au prochain redémarrage.

Le réseau d'un serveur a une particularité qui le rend redoutable : c'est la branche sur laquelle vous êtes assis. Une erreur dans un fichier de service casse un service ; une erreur dans la configuration réseau, appliquée par SSH, vous coupe de la machine, et la seule issue est la console de secours. Il faut donc savoir trois choses avant de toucher à quoi que ce soit : qui configure le réseau sur cette machine (il y a plusieurs outils, et ils se marchent dessus), ce qui est en place maintenant (et en quoi cela diffère de ce qui sera en place après redémarrage), et comment appliquer un changement avec un filet.

Deux distributions cohabitent (Ubuntu 24.04 sur sig-app-1 et sig-app-2, Debian 13 sur sig-outils), et cloud-init écrit lui aussi des fichiers réseau au démarrage. Cette leçon vous apprend à démêler tout cela, puis à configurer proprement l'interface du réseau privé, une route, la résolution de noms et le nom d'hôte. Le pare-feu de l'hôte fait l'objet de la leçon suivante.

Les notions d'adresse, de masque, de route, de MTU et de port sont supposées acquises : elles sont expliquées dans le cours Le modèle TCP/IP. Ici, on s'intéresse à la façon dont Linux les configure et les conserve.

Les concepts

Deux états : le noyau et les fichiers

Le réseau d'une machine Linux existe à deux endroits qu'il faut toujours distinguer :

  • Dans le noyau, maintenant. Les interfaces, leurs adresses, la table de routage, le cache des voisins (ARP et NDP) sont des structures en mémoire. La commande ip (paquet iproute2, voir l'outil iproute2) les lit et les modifie directement, par l'interface netlink (le canal de communication entre l'espace utilisateur et la pile réseau du noyau). Une modification faite avec ip addr add ou ip route add prend effet immédiatement et disparaît au redémarrage.
  • Dans des fichiers, pour le prochain démarrage. Un démon de configuration lit ces fichiers et pousse leur contenu dans le noyau, au démarrage puis à chaque changement (lien qui revient, bail DHCP renouvelé).

La route de test posée sur sig-app-1 n'existe que dans le noyau : elle disparaîtra au prochain redémarrage. D'où la règle : ip sert à lire et à tester ; ce qui doit durer s'écrit dans la configuration persistante.

Qui configure le réseau ?

Plusieurs outils savent lire des fichiers et configurer le noyau. Sur un serveur, un seul doit gérer une interface donnée.

OutilOù on le trouveFichiers
netplan + systemd-networkdUbuntu Server ; images cloud Debian récentes/etc/netplan/*.yaml, traduits en /run/systemd/network/
systemd-networkd seulDebian, Arch, conteneurs/etc/systemd/network/*.network
ifupdownDebian historique (et encore l'installateur Debian 13)/etc/network/interfaces, /etc/network/interfaces.d/
NetworkManagerpostes de travail ; RHEL, AlmaLinux, Rocky Linux/etc/NetworkManager/system-connections/

netplan n'est pas un démon mais un traducteur : vous décrivez le réseau en YAML, il génère la configuration du renderer (le moteur qui applique réellement la configuration), networkd par défaut sur un serveur, ou NetworkManager. Ubuntu l'utilise depuis 17.10, et les images cloud officielles de Debian l'ont adopté. Une Debian installée par l'installateur classique utilise encore ifupdown.

Et l'image Debian de Scaleway ? Ne le supposez pas. La documentation de Scaleway sur les réseaux privés cite, pour Debian, des fichiers ifupdown (/etc/network/interfaces.d/60-*-vpc) et, pour Ubuntu, des fichiers netplan (/etc/netplan/60-*-vpc.yaml) ; une image plus récente peut avoir changé. Sur sig-outils, on constate d'abord (section « En pratique »).

Sur Red Hat, NetworkManager gère aussi les serveurs ; on le pilote avec nmcli (nmcli connection show, modify, up), et ses profils sont des fichiers « keyfile » dans /etc/NetworkManager/system-connections/ (les ifcfg-* sont dépréciés depuis RHEL 9).

cloud-init, l'invité du premier démarrage

Une instance démarre d'une image générique. C'est cloud-init (voir l'outil cloud-init) qui interroge le service de métadonnées du fournisseur et écrit la configuration réseau : /etc/netplan/50-cloud-init.yaml avec netplan, /etc/network/interfaces.d/50-cloud-init avec ifupdown (ENI dans sa documentation).

Ce fichier prévient en commentaire que les modifications seront perdues : cloud-init peut le réécrire à un démarrage ultérieur. Ne le modifiez jamais ; ajoutez votre configuration dans un autre fichier, que netplan fusionnera. Pour que cloud-init cesse de gérer le réseau :

# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
network: {config: disabled}

Le même principe vaut pour le nom d'hôte (preserve_hostname) et pour /etc/hosts (manage_etc_hosts), que l'on retrouvera plus bas.

Sur Scaleway, le paquet scaleway-ecosystem des images Ubuntu et Debian intervient aussi : une règle udev (/lib/udev/rules.d/72-scw-vpc-iface.rules) et une unité scw-vpc-iface activent le DHCP sur chaque carte de réseau privé qui apparaît, en écrivant le fichier 60-...-vpc. C'est grâce à lui que « DHCP, rien à faire » était vrai.

Le réseau privé Scaleway : DHCP et IPAM

pn-signalements (172.16.8.0/22) est un réseau de niveau 2, comme un commutateur partagé, même entre fr-par-1 et fr-par-2. Chaque instance y reçoit une carte supplémentaire, de MAC 02:00:00:.... Le DHCP y est toujours actif. Les adresses distribuées sont gérées par l'IPAM (IP Address Management, l'outil de Scaleway qui attribue et réserve les adresses de ses produits). Deux façons d'obtenir une adresse stable :

  1. Garder le DHCP et réserver l'adresse dans l'IPAM : sig-app-1 reçoit toujours 172.16.8.11. Rien à écrire sur la machine, et cela survit à sa reconstruction. C'est ce que Scaleway recommande, et notre choix.
  2. Configurer l'adresse en statique : documenté pour les « utilisateurs avancés » mais non pris en charge. Il faut désactiver l'autoconfiguration et éviter tout conflit avec l'IPAM, qui ignore alors l'adresse.

Le DHCP du réseau privé fournit aussi un résolveur DNS interne, joignable en 169.254.169.254, qui résout les noms des ressources du réseau sous la forme <nom>.<réseau-privé>.internal. sig-app-2 peut ainsi joindre sig-outils.pn-signalements.internal sans aucune entrée dans /etc/hosts. Voilà la vraie réponse au bricolage de /etc/hosts trouvé sur sig-app-1.

Les noms d'interfaces

Les noms prévisibles (ens2, ens5) sont attribués par udev d'après la position PCI de la carte. Sur Scaleway, l'interface publique est souvent ens2 et la privée ens5, mais la documentation du fournisseur avertit que ces noms ne sont pas garantis stables, par exemple quand on attache plusieurs réseaux privés. Les notes de publication de Debian 13 préviennent aussi que les noms peuvent changer à la montée de version depuis Debian 12 (systemd 257 exploite l'objet ACPI _SUN). On désigne donc une carte par son adresse MAC, affichée par la console et l'API.

La résolution de noms

Quand Gunicorn ouvre une connexion vers la base, la bibliothèque libpq appelle getaddrinfo(), fonction de la glibc. Le trajet de cette demande traverse plusieurs étages, et chacun peut être en cause :

    flowchart TD
    A["Application : getaddrinfo('sig-outils.pn-signalements.internal')"] --> B["NSS : /etc/nsswitch.conf, ligne hosts"]
    B -->|files| C["/etc/hosts"]
    B -->|dns| D["/etc/resolv.conf : nameserver 127.0.0.53"]
    D --> E["systemd-resolved (stub local)"]
    E -->|"domaine .internal, lien ens5"| F["Résolveur Scaleway 169.254.169.254"]
    E -->|"autres domaines"| G["Résolveurs du lien public"]
  
  1. NSS (Name Service Switch, présenté dans la leçon Utilisateurs, groupes et sudo) lit la ligne hosts: de /etc/nsswitch.conf. La valeur courante sur un serveur Ubuntu ou Debian est hosts: files dns : d'abord /etc/hosts, puis le DNS. On rencontre aussi myhostname (qui résout toujours le nom de la machine) ou resolve (qui interroge systemd-resolved directement, si le paquet libnss-resolve est installé).
  2. /etc/hosts : une table statique, lue de haut en bas, première correspondance gagnante.
  3. /etc/resolv.conf : le fichier que lit le résolveur DNS de la glibc. Il contient les serveurs (nameserver), les domaines de recherche (search) et des options (options timeout:2 attempts:2, options edns0).
  4. systemd-resolved, quand il est actif, écoute sur 127.0.0.53 et sert de relais local : /etc/resolv.conf ne cite que lui, et c'est lui qui connaît les vrais serveurs, lien par lien. Un second relais, 127.0.0.54, transmet les requêtes vers l'amont presque sans traitement local.

Avec systemd-resolved, les serveurs DNS sont déclarés par interface, chacun avec ses domaines : domaine de recherche (pn-signalements.internal complète le nom court sig-outils) ou domaine de routage (préfixé par ~, comme ~internal : les requêtes pour ce domaine partent vers ce lien, sans complétion). Une requête qui ne correspond à aucun domaine part vers les liens marqués DefaultRoute. Ainsi, les noms .internal vont au résolveur du réseau privé, le reste aux résolveurs publics.

/etc/resolv.conf peut prendre quatre formes, et savoir laquelle est en place explique bien des surprises :

/etc/resolv.conf estContenuEffet
lien vers /run/systemd/resolve/stub-resolv.confnameserver 127.0.0.53 et les domaines de recherche, à jourmode recommandé, celui d'Ubuntu
lien vers /usr/lib/systemd/resolv.confnameserver 127.0.0.53, sans domaines de recherchestatique
lien vers /run/systemd/resolve/resolv.confles vrais serveurs DNS, contournant le relaisperd le routage par domaine
un fichier ordinairece qu'un autre outil (ou une personne) y a écritsystemd-resolved le lit au lieu de l'écrire

Sur Debian 13, systemd-resolved est un paquet séparé, absent de certaines installations : /etc/resolv.conf y est alors un fichier ordinaire, écrit par le client DHCP ou par resolvconf.

Le nom d'hôte

Le nom statique est dans /etc/hostname ; le nom transitoire est celui du noyau, qu'un client DHCP peut modifier. hostnamectl règle les deux. Un nom valide fait au plus 64 caractères ASCII minuscules : un label (sig-app-1) ou un FQDN.

Le FQDN (Fully Qualified Domain Name, le nom complet avec son domaine) n'est stocké nulle part : hostname -f le calcule en résolvant le nom court par NSS. D'où la convention Debian de la ligne 127.0.1.1 sig-app-1.signalements.lyneko.fr sig-app-1 dans /etc/hosts, qui fait résoudre le nom de la machine même sans DNS. Sur une instance cloud, cloud-init règle le nom d'après les métadonnées à chaque démarrage, sauf si preserve_hostname: true est posé.

En pratique

Les sorties ci-dessous sont des sorties typiques, construites d'après la documentation et le code source des outils ; les adresses publiques sont des adresses de documentation (203.0.113.0/24, 2001:db8::/32). Les vôtres différeront.

Étape 1 : savoir qui gère quoi

Sur chaque machine, commencez par constater :

$ ls -l /etc/netplan/ /etc/network/interfaces.d/ /etc/systemd/network/ 2>/dev/null
$ systemctl is-active systemd-networkd NetworkManager networking systemd-resolved
$ readlink -f /etc/resolv.conf
$ networkctl list
  • Des fichiers dans /etc/netplan/ et systemd-networkd actif : netplan pilote networkd.
  • networking actif (le service d'ifupdown) et des fichiers dans /etc/network/interfaces.d/ : ifupdown.
  • readlink -f /etc/resolv.conf qui renvoie /run/systemd/resolve/stub-resolv.conf : systemd-resolved est en place, en mode recommandé.

networkctl list est la commande la plus parlante, parce qu'elle dit pour chaque interface si systemd-networkd s'en occupe. Sur sig-app-1, la sortie ressemble à ceci :

IDX LINK TYPE     OPERATIONAL SETUP
  1 lo   loopback carrier     unmanaged
  2 ens2 ether    routable    configured
  3 ens5 ether    routable    configured

3 links listed.
  • OPERATIONAL : routable (lien et adresse routable), degraded (adresse locale seulement), no-carrier (pas de lien), off (éteinte).
  • SETUP : configured (networkd la gère, c'est fini), configuring (il attend, souvent un bail DHCP), unmanaged (aucun fichier .network ne la concerne), failed.

Sous ifupdown, tout apparaît unmanaged. Une interface configured et citée dans /etc/network/interfaces trahit deux gestionnaires concurrents, à corriger en priorité. Sous netplan, sudo netplan get affiche en plus la configuration fusionnée de tous les fichiers YAML. Notez le résultat dans la fiche du serveur (leçon 1).

Étape 2 : lire l'état du noyau

$ ip -br link
$ ip -br addr
$ ip route
$ ip -6 route
$ ip neigh

-br (brief) donne une ligne par interface. Sortie typique de ip -br addr sur sig-app-1 :

lo               UNKNOWN        127.0.0.1/8 ::1/128
ens2             UP             203.0.113.41/32 2001:db8:4c2:1a00::1/64 fe80::dc00:ff:fe12:3456/64
ens5             UP             172.16.8.11/22 fe80::ff:fe9a:bc01/64

Nom, état (UNKNOWN pour lo, qui n'a pas de vrai lien), adresses avec leur préfixe. L'adresse publique en /32 est typique d'une IP « routée » Scaleway, portée directement par l'instance. Chaque interface a aussi une adresse de lien local IPv6 en fe80::, que netplan active par défaut.

ip route affiche la table de routage principale :

default via 203.0.113.1 dev ens2 proto dhcp src 203.0.113.41 metric 100
172.16.8.0/22 dev ens5 proto kernel scope link src 172.16.8.11 metric 100
203.0.113.1 dev ens2 proto dhcp scope link src 203.0.113.41 metric 100
  • default via ... dev ens2 : la passerelle par défaut.
  • proto dit qui a posé la route : dhcp, kernel (réseau directement connecté, créé avec l'adresse), static (déclarée dans la configuration), ra (annonce de routeur IPv6). Une route sans proto affiché a été ajoutée à la main.
  • scope link : joignable directement, sans passerelle ; src : l'adresse source choisie.
  • metric : la priorité entre deux routes vers la même destination (la plus petite gagne) ; netplan fixe 100 pour les routes DHCP filaires.

ip -6 route montre l'équivalent IPv6 :

2001:db8:4c2:1a00::/64 dev ens2 proto ra metric 100 expires 86391sec pref medium
fe80::/64 dev ens2 proto kernel metric 256 pref medium
fe80::/64 dev ens5 proto kernel metric 256 pref medium
default via fe80::a:1 dev ens2 proto ra metric 100 expires 1791sec pref medium

Les IP routées IPv6 de Scaleway fonctionnent ainsi : un préfixe /64 par instance, configuré par SLAAC, passerelle et DNS appris par les annonces de routeur (proto ra). La route a une durée de vie (expires) renouvelée à chaque annonce : si l'instance cesse de les accepter (accept-ra: false), l'IPv6 tombe à retardement.

Enfin, ip neigh liste le cache des voisins (ARP en IPv4, NDP en IPv6) :

172.16.8.12 dev ens5 lladdr 02:00:00:1b:2c:3d REACHABLE
203.0.113.1 dev ens2 lladdr 00:07:cb:0b:0d:01 STALE
fe80::a:1 dev ens2 lladdr 00:07:cb:0b:0d:01 router STALE

REACHABLE : confirmé récemment ; STALE : à revérifier au prochain usage ; FAILED ou INCOMPLETE : le voisin ne répond pas, problème de niveau 2 (carte non attachée au réseau privé, mauvaise interface). Voir Ethernet et ARP.

Étape 3 : la configuration du réseau privé avec netplan

Supposons sig-app-2 recréée depuis une image sans l'autoconfiguration de scaleway-ecosystem : son interface privée reste unmanaged. On écrit un fichier dédié, sans toucher à celui de cloud-init, en désignant la carte par sa MAC :

# /etc/netplan/60-prive.yaml
network:
  version: 2
  ethernets:
    prive:
      match:
        macaddress: "02:00:00:1b:2c:3d"
      set-name: prive
      dhcp4: true
      dhcp4-overrides:
        route-metric: 200
      optional: true
  • ethernets: prive: : interfaces physiques ; avec match, prive est une étiquette libre. Pas de renderer: : le défaut est networkd.
  • match: macaddress: : s'applique à la carte qui porte cette MAC, quel que soit son nom ; set-name: prive la renomme, indépendamment de l'emplacement PCI.
  • dhcp4: true : l'adresse vient du DHCP, donc de la réservation IPAM.
  • dhcp4-overrides: : route-metric: 200 place les routes de ce lien derrière celles du lien public (100), pour qu'une route par défaut annoncée sur le réseau privé ne prenne pas le pas par surprise. Autres clés : use-dns, use-domains (true, false ou route), use-mtu.
  • optional: true : le démarrage n'attend pas cette interface (sinon systemd-networkd-wait-online l'attend jusqu'à son délai).

En statique (non pris en charge par Scaleway), on remplacerait dhcp4: true par :

      addresses: [ 172.16.8.12/22 ]
      nameservers:
        addresses: [ 169.254.169.254 ]
        search: [ pn-signalements.internal ]

nameservers déclare les serveurs DNS de ce lien ; netplan les transmet à systemd-resolved, pas à un fichier global.

Étape 4 : une route vers un autre réseau

Un jour, la mairie demande que l'export soit déposé sur un serveur de son réseau, 10.40.0.0/16, joint par une passerelle VPN placée sur le réseau privé à l'adresse 172.16.8.2 (adresse hypothétique pour l'exemple). La route s'ajoute à la définition de l'interface privée de sig-outils, écrite sur le même modèle que ci-dessus :

      routes:
        - to: 10.40.0.0/16
          via: 172.16.8.2
          metric: 100

via doit être joignable directement sur le lien (sinon on-link: true). Pour une route par défaut : to: default (l'ancienne clé gateway4 est dépréciée). La route peut d'abord se tester dans le noyau, sans persistance :

$ sudo ip route add 10.40.0.0/16 via 172.16.8.2 dev prive
$ ip route get 10.40.12.7
10.40.12.7 via 172.16.8.2 dev prive src 172.16.8.20 uid 1000
    cache
$ sudo ip route del 10.40.0.0/16 via 172.16.8.2 dev prive

ip route get montre la décision du noyau pour une adresse précise : route, interface, adresse source. Pourquoi 10.40.0.0/16 l'emporte sur default : voir Le routage.

Étape 5 : appliquer sans se couper l'accès

D'abord, valider et générer sans rien appliquer :

$ sudo chmod 600 /etc/netplan/60-prive.yaml
$ sudo netplan generate
$ ls /run/systemd/network/
10-netplan-ens2.network  10-netplan-prive.link  10-netplan-prive.network

netplan generate signale les erreurs avec ligne et colonne et écrit la configuration de networkd, sans toucher aux interfaces. Le fichier .link porte le renommage, appliqué par udev à l'apparition de la carte, donc souvent au redémarrage suivant seulement.

Ensuite, appliquer avec un filet :

$ sudo netplan try --timeout 120

netplan try applique la nouvelle configuration, puis attend une confirmation. Le texte affiché, tiré du code de netplan, est :

Do you want to keep these settings?


Press ENTER before the timeout to accept the new configuration


Changes will revert in 120 seconds

Si la session a survécu, appuyez sur Entrée : Configuration accepted.. Si vous êtes coupé, le délai (120 secondes par défaut) expire, netplan affiche Reverting. et restaure l'ancienne configuration. Réserves de la documentation : le retour arrière n'est pas pris en charge pour les ponts et agrégats (reverting custom parameters for bridges and bonds is not supported), et il faut vérifier l'état après un retour arrière. netplan apply applique sans filet, depuis une console ou un outil d'automatisation.

Warning

netplan try protège contre une configuration qui coupe la connexion pendant le délai. Il ne protège pas contre une configuration qui marche maintenant et casse au prochain démarrage (renommage d'interface, interface obligatoire absente). Avant de quitter, relisez netplan get et, si possible, redémarrez la machine pendant une fenêtre de maintenance, avec la console Scaleway ouverte.

Le cas ifupdown sur Debian

Si sig-outils s'avère gérée par ifupdown, la même interface privée se décrit ainsi :

# /etc/network/interfaces.d/60-prive
allow-hotplug ens5
iface ens5 inet dhcp
    post-up ip route add 10.40.0.0/16 via 172.16.8.2 dev ens5
    pre-down ip route del 10.40.0.0/16 via 172.16.8.2 dev ens5

allow-hotplug monte l'interface quand le noyau la détecte ; post-up et pre-down posent et retirent la route. Sur Debian 13, isc-dhcp-client est déprécié en amont et les notes de publication orientent vers dhcpcd-base. Le fichier /etc/network/interfaces doit contenir source /etc/network/interfaces.d/*. On applique avec sudo ifup ens5, ifquery ens5 montre ce qui est compris. Pas de systemctl restart networking à distance : il descend toutes les interfaces, la vôtre comprise, et ifupdown n'a pas d'équivalent de netplan try. On programme alors le retour arrière avant d'agir (systemd-run --on-active=5min ...), technique reprise à la leçon suivante.

Étape 6 : la résolution de noms

Sur Ubuntu, avec systemd-resolved :

$ resolvectl status

Sortie typique (systemd 255) :

Global
           Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
    resolv.conf mode: stub

Link 2 (ens2)
    Current Scopes: DNS
         Protocols: +DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 203.0.113.53
       DNS Servers: 203.0.113.53 2001:db8:4c2::53

Link 3 (ens5)
    Current Scopes: DNS
         Protocols: -DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 169.254.169.254
       DNS Servers: 169.254.169.254
        DNS Domain: ~internal pn-signalements.internal
  • resolv.conf mode: stub : /etc/resolv.conf pointe vers le fichier du relais. foreign signalerait un fichier écrit par quelqu'un d'autre.
  • +DefaultRoute : ce lien reçoit les requêtes qui ne correspondent à aucun domaine. Le lien privé, en -DefaultRoute, ne reçoit que les noms de ses domaines.
  • DNS Domain : ~internal est un domaine de routage, pn-signalements.internal un domaine de recherche (et implicitement de routage).

C'est la configuration visée : ce que le DHCP de Scaleway pousse comme domaines n'est pas documenté, resolvectl status vous le dira. S'il manque le domaine de routage, ajoutez nameservers: search: [ "~internal" ] sous l'interface privée.

Puis on interroge :

$ resolvectl query sig-outils.pn-signalements.internal
sig-outils.pn-signalements.internal: 172.16.8.20                  -- link: ens5

-- Information acquired via protocol DNS in 1.9ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: network
$ getent hosts sig-outils.pn-signalements.internal
172.16.8.20     sig-outils.pn-signalements.internal

resolvectl query interroge systemd-resolved : il dit quel lien a répondu, mais ignore /etc/hosts. getent hosts suit le chemin d'une application (NSS, /etc/hosts, DNS). S'ils divergent, le coupable est presque toujours une ligne de /etc/hosts. dig et nslookup ignorent NSS : ils ne disent pas ce que voit l'application.

C'est le cas de la ligne 172.16.8.40 sig-db héritée de Camille sur sig-app-1 : elle fige une adresse qui peut changer, et l'emporte sur le DNS. On la supprime et on configure Signalements avec le nom du point d'accès privé de la base.

Étape 7 : le nom d'hôte

Pour fixer durablement le nom et le FQDN sur une instance cloud :

$ printf 'preserve_hostname: true\n' | sudo tee /etc/cloud/cloud.cfg.d/99-hostname.cfg
$ sudo hostnamectl hostname sig-app-1
$ hostname -f
sig-app-1.signalements.lyneko.fr

99-hostname.cfg empêche cloud-init de réécrire le nom ; hostnamectl hostname règle les noms statique et transitoire (set-hostname reste accepté). hostname -f exige que /etc/hosts ou le DNS associe le nom au FQDN. Si cloud-init gère /etc/hosts (manage_etc_hosts: true), il le réécrit à chaque démarrage depuis /etc/cloud/templates/hosts.debian.tmpl : modifiez le modèle. Avec manage_etc_hosts: localhost, seule la ligne 127.0.1.1 est tenue à jour.

Étape 8 : diagnostiquer couche par couche

« Signalements ne joint plus la base » : on remonte les couches et on s'arrête à la première qui échoue (méthode complète dans Diagnostiquer un problème réseau) :

CoucheQuestionCommandeÉchec typique
LienL'interface est-elle là et active ?ip -br link, networkctl listDOWN, no-carrier, interface absente
AdresseA-t-elle la bonne adresse ?ip -br addr show ens5pas d'IPv4, adresse inattendue
RoutePar où part le paquet ?ip route get 172.16.8.40mauvaise interface, Network is unreachable
VoisinLe prochain saut répond-il ?ping -c 3 172.16.8.40, ip neighFAILED, Destination Host Unreachable
NomLe nom donne-t-il la bonne adresse ?getent hosts nom, resolvectl query nomnot found, mauvaise adresse
PortLe service accepte-t-il ?nc -zv 172.16.8.40 5432, curl -vConnection refused, délai dépassé

Dans l'autre sens, ss -tlnp vérifie que Signalements écoute bien sur l'adresse attendue.

Sous le capot

De la ligne YAML au noyau

Au démarrage, netplan s'exécute avant systemd-networkd, comme générateur systemd (un programme que systemd lance très tôt, avant de charger les unités, et qui peut écrire des fichiers dans /run). Il lit /lib/netplan, /etc/netplan et /run/netplan, fusionne, et écrit :

  • /run/systemd/network/10-netplan-<id>.network (et .link, .netdev si besoin), lus par systemd-networkd et udev ;
  • /run/systemd/system/systemd-networkd-wait-online.service.d/10-netplan.conf, qui indique quelles interfaces non optionnelles attendre.

La fusion suit l'ordre lexicographique des noms, quel que soit le répertoire (à nom égal, /run masque /etc, qui masque /lib). Pour une valeur simple, le dernier fichier gagne ; les listes s'additionnent. 60-prive.yaml complète donc 50-cloud-init.yaml.

Le fichier généré pour notre interface privée ressemble à ceci :

[Match]
PermanentMACAddress=02:00:00:1b:2c:3d
Name=prive

[Network]
DHCP=ipv4
LinkLocalAddressing=ipv6

[DHCP]
RouteMetric=200
UseMTU=true

Deux détails du code de netplan : la correspondance porte sur PermanentMACAddress, la MAC d'origine, qu'un agrégat ne peut pas modifier ; et UseMTU=true fait accepter la MTU annoncée par le DHCP, contrairement au défaut de networkd, parce que les nuages s'en servent (voir ICMP, ping, traceroute et la MTU). Pour forcer une valeur : mtu: dans netplan, et ip link show pour vérifier.

systemd-networkd n'appelle pas ip : il parle au noyau par netlink, avec les mêmes messages (RTM_NEWADDR, RTM_NEWROUTE), que ip monitor address route affiche en direct, très instructif pendant un netplan try. Il transmet ensuite les DNS de chaque lien à systemd-resolved par D-Bus : d'où nameservers: comme propriété d'interface.

Le trajet d'une requête DNS

Quand une application appelle getaddrinfo("sig-outils.pn-signalements.internal") :

  1. la glibc lit /etc/nsswitch.conf et appelle le module files, qui parcourt /etc/hosts : s'il trouve, le DNS n'est jamais consulté ;
  2. sinon, le résolveur lit /etc/resolv.conf, applique les domaines search (avec ndots:1 par défaut, un nom qui contient un point est d'abord essayé tel quel) et envoie une requête UDP à 127.0.0.53:53 ;
  3. systemd-resolved choisit le domaine le plus spécifique parmi ceux des liens (internal, lien privé), interroge le serveur de ce lien, met la réponse en cache et la renvoie.

systemd-resolved répond lui-même pour localhost, le nom de la machine et _gateway (la passerelle par défaut). Son cache peut prolonger une erreur DNS jusqu'à l'expiration du TTL : resolvectl flush-caches le vide.

Pièges courants

Modifier 50-cloud-init.yaml. La modification fonctionne, jusqu'au jour où cloud-init régénère le fichier. Écrivez votre configuration dans un autre fichier (60-*.yaml), ou désactivez la gestion du réseau par cloud-init avec network: {config: disabled}.

Des permissions trop ouvertes. À chaque commande, netplan avertit : Permissions for /etc/netplan/60-prive.yaml are too open. Netplan configuration should NOT be accessible by others. Ces fichiers peuvent contenir des secrets (clés WireGuard) : la documentation recommande root:root en 600. La configuration s'applique quand même.

Une tabulation dans le YAML. Le message, avec le chemin, la ligne et la colonne, est :

/etc/netplan/60-prive.yaml:7:1: Invalid YAML: tabs are not allowed for indent:

suivi de la ligne en cause. Une clé mal orthographiée donne Error in network definition: unknown key 'dhcp', une indentation manquante expected mapping (check indentation), et une vieille clé gateway4 l'avertissement `gateway4` has been deprecated, use default routes instead.

Deux gestionnaires sur la même interface. Une interface décrite à la fois dans /etc/network/interfaces et dans un fichier .network (ou gérée par NetworkManager) reçoit des ordres contradictoires : adresse qui change, route qui disparaît au renouvellement du bail. Choisissez une pile, désactivez l'autre (systemctl disable --now networking, ou retrait du paquet).

Un démarrage qui traîne deux minutes. Le journal affiche, pour systemd-networkd-wait-online.service :

Timeout occurred while waiting for network connectivity.

Une interface déclarée dans netplan n'a jamais atteint l'état attendu (carte privée détachée, DHCP qui ne répond pas). Marquez les interfaces non indispensables optional: true, ou corrigez la cause. networkctl list montre celle qui reste en configuring.

Une route posée avec ip et jamais écrite. Tout fonctionne jusqu'au redémarrage. Dans ip route, une route sans proto a été posée à la main : est-elle dans la configuration ?

Temporary failure in name resolution. (EAI_AGAIN de la glibc) : aucune réponse obtenue, relais arrêté ou aucun serveur DNS sur aucun lien. À distinguer de Name or service not known (EAI_NONAME) : un serveur a répondu que le nom n'existe pas. Vérifiez readlink -f /etc/resolv.conf, systemctl is-active systemd-resolved, puis resolvectl status.

sig-db.internal: resolve call failed: 'sig-db.internal' not found. C'est la forme d'une réponse NXDOMAIN dans resolvectl query. Vérifiez le nom (format <ressource>.<réseau-privé>.internal, un point dans le nom d'une ressource devenant un tiret) et que la requête part vers le lien privé.

/etc/resolv.conf remplacé par un fichier ordinaire pour « mettre 1.1.1.1 » : le routage par domaine disparaît et resolvectl status affiche resolv.conf mode: foreign. Rétablissez le lien : sudo ln -sf ../run/systemd/resolve/stub-resolv.conf /etc/resolv.conf.

sudo: unable to resolve host sig-app-1: Name or service not known. Après un renommage, le nouveau nom ne se résout plus (absent de /etc/hosts, ou modèle de cloud-init qui a remis l'ancien). Ajoutez la ligne 127.0.1.1.

ping: connect: Network is unreachable. Aucune route ne couvre la destination ; souvent une route par défaut disparue après une modification. ip route get le confirme.

Sécurité

  • Le réseau privé n'est pas filtré par les groupes de sécurité. La documentation de Scaleway le dit explicitement : les règles des groupes de sécurité s'appliquent au trafic Internet public, pas au réseau privé. Tout ce qui écoute sur l'adresse privée de sig-app-1 est joignable par toutes les ressources de pn-signalements. Le filtrage du réseau privé est l'affaire du pare-feu de l'hôte (leçon suivante).
  • Écouter sur la bonne adresse. Gunicorn sur 0.0.0.0:8000 écoute sur toutes les interfaces, publique comprise. Liez chaque service à l'adresse qui convient et vérifiez avec ss -tlnp : c'est l'esprit du guide BP-028 de l'ANSSI, n'exposer que le nécessaire.
  • /etc/hosts est un vecteur de détournement. Une ligne qui associe le nom de l'API de paiement ou du dépôt de paquets à une autre adresse détourne silencieusement le trafic, et NSS la consulte avant le DNS. Surveillez ce fichier (contrôle d'intégrité, leçon 15) et gardez-le minimal.
  • Le DNS n'est pas authentifié par défaut (Data is authenticated: no). C'est TLS, avec vérification du certificat, qui protège réellement les échanges sensibles. DNSSEC= et DNSOverTLS= existent dans resolved.conf, mais demandent des résolveurs compatibles et se testent avant d'être imposés.
  • IPv6 ouvre une seconde porte. Une instance avec une IP routée IPv6 est joignable en IPv6, et un filtrage limité à l'IPv4 laisse tout passer. Si vous n'utilisez pas IPv6, ne l'attachez pas.
  • Pas de routeur involontaire. Une machine à plusieurs interfaces avec net.ipv4.ip_forward=1 (leçon 3) route entre le public et le privé : ce paramètre reste à 0 sur Signalements.
  • Les métadonnées (169.254.42.42) sont lisibles par tout processus local : pas de secret dans les données utilisateur d'une instance.

En production

  • Le réseau se déclare, il ne se bricole pas. Réservations IPAM et attachements dans Terraform ou OpenTofu, fichiers de la machine par Ansible ou cloud-init : une instance recréée retrouve seule son adresse et son nom, l'objectif de l'infrastructure immuable.
  • DHCP avec réservation plutôt que statique, qui crée sur les machines un second registre d'adresses que personne ne réconcilie avec l'IPAM. Et des noms plutôt que des adresses dans la configuration des applications.
  • Toute modification à distance a un filet (netplan try, retour arrière programmé, console ouverte), et on traite sig-app-1 puis sig-app-2, jamais les deux à la fois.
  • Surveillez l'état du réseau : interface qui n'est plus routable, route par défaut absente, échec de systemd-networkd-wait-online au démarrage.

Exercices

1. Qui gère quoi (niveau 100). Sur sig-outils, networkctl list montre ens2 et ens5 en unmanaged, systemctl is-active networking répond active, et readlink -f /etc/resolv.conf renvoie /etc/resolv.conf. Quelle pile gère le réseau, où chercher la configuration, et comment est gérée la résolution de noms ?

Solution

Le réseau est géré par ifupdown : systemd-networkd ne gère aucune interface (unmanaged) et le service networking d'ifupdown est actif. La configuration est dans /etc/network/interfaces et dans les fichiers de /etc/network/interfaces.d/ qu'il inclut par source (dont 50-cloud-init écrit par cloud-init et, sur une image Scaleway, un 60-...-vpc pour le réseau privé). /etc/resolv.conf est un fichier ordinaire et non un lien : systemd-resolved n'est pas utilisé, le fichier est écrit par le client DHCP (ou par resolvconf). Pour les modifications : ifquery, ifup, ifdown, et jamais systemctl restart networking à distance.

2. Le nom qui revient (niveau 200). Vous renommez une instance en sig-outils avec sudo hostnamectl hostname sig-outils. Après le redémarrage suivant, l'invite affiche à nouveau scw-quirky-wing, le nom donné à la création, et sudo met plusieurs secondes à répondre avec sudo: unable to resolve host. Expliquez les deux symptômes et corrigez durablement.

Solution

cloud-init règle le nom d'hôte à chaque démarrage (module Update Hostname, fréquence « always ») à partir des métadonnées, c'est-à-dire du nom de l'instance chez Scaleway ; il a donc remis l'ancien nom. Le message de sudo vient de /etc/hosts : le nom courant ne s'y trouve pas (ou cloud-init l'a régénéré depuis son modèle). Correction : renommer aussi l'instance dans la console ou l'API Scaleway (la source de vérité), et/ou poser preserve_hostname: true dans /etc/cloud/cloud.cfg.d/99-hostname.cfg ; puis sudo hostnamectl hostname sig-outils ; enfin assurer la résolution du nom : si manage_etc_hosts est actif, modifier le modèle /etc/cloud/templates/hosts.debian.tmpl ou passer à manage_etc_hosts: localhost, sinon ajouter 127.0.1.1 sig-outils.signalements.lyneko.fr sig-outils dans /etc/hosts. Vérifier avec hostname -f et getent hosts sig-outils.

3. Les noms internes ne se résolvent plus (niveau 200). Depuis ce matin, sur sig-app-1, getent hosts sig-outils.pn-signalements.internal ne renvoie rien, alors que ping 172.16.8.20 fonctionne. resolvectl status affiche resolv.conf mode: foreign. Que s'est-il probablement passé, comment le confirmer et comment réparer ?

Solution

Le lien et le routage fonctionnent (le ping par adresse passe), le problème est à la couche « nom ». foreign signifie que /etc/resolv.conf n'est plus le lien vers le relais de systemd-resolved mais un fichier écrit par quelqu'un ou quelque chose d'autre. Confirmation : ls -l /etc/resolv.conf (fichier ordinaire au lieu d'un lien) et cat /etc/resolv.conf (probablement un nameserver public). Les requêtes partent donc directement vers ce serveur public, qui ne connaît pas les noms .internal ; le routage par domaine de systemd-resolved est contourné. Réparation : sudo ln -sf ../run/systemd/resolve/stub-resolv.conf /etc/resolv.conf, puis resolvectl query sig-outils.pn-signalements.internal (le lien privé doit répondre) et getent hosts .... Enfin, chercher qui a écrit le fichier (historique des commandes, paquet installé récemment comme un client VPN ou resolvconf) pour que cela ne se reproduise pas.

4. Changer de réseau privé sans perdre la main (niveau 300). La mairie impose un nouveau réseau privé dédié, pn-mairie (10.50.0.0/24), à attacher à sig-outils en plus de pn-signalements, pour y déposer l'export. La machine est sous netplan, vous n'y accédez que par SSH via son interface publique, et l'export de la nuit doit continuer à fonctionner. Décrivez votre plan, du côté Scaleway et du côté de la machine, avec les commandes et les vérifications.

Solution
  1. Préparer : noter l'état actuel (ip -br addr, ip route, resolvectl status, netplan get) dans la fiche ; ouvrir la console Scaleway de sig-outils dans un onglet, au cas où ; réserver dans l'IPAM l'adresse que sig-outils aura sur pn-mairie.
  2. Attacher la carte au nouveau réseau privé (console ou CLI Scaleway) et relever sa MAC. Sur la machine, ip -br link montre une nouvelle interface ; vérifier que les noms des interfaces existantes n'ont pas changé (le risque signalé par Scaleway quand on ajoute un réseau privé). Si l'autoconfiguration de scaleway-ecosystem a déjà activé le DHCP dessus, il suffit de contrôler.
  3. Sinon, écrire /etc/netplan/61-mairie.yaml : match: macaddress: avec la MAC, set-name: mairie, dhcp4: true, dhcp4-overrides: {use-routes: true, route-metric: 300, use-dns: false} (pour ne pas laisser un DNS de la mairie répondre aux requêtes générales), optional: true. chmod 600, puis sudo netplan generate pour valider.
  4. Appliquer avec sudo netplan try --timeout 180, vérifier dans une seconde session SSH ouverte avant (et non dans la session courante seule) que la connexion tient, puis confirmer.
  5. Vérifier : ip route get vers le serveur de la mairie (sortie par mairie), ip route get 172.16.8.11 (toujours par l'interface de pn-signalements), ip route (la route par défaut est toujours celle de l'interface publique), test de dépôt manuel de l'export.
  6. Pérenniser : la configuration réseau va dans le code (Terraform pour l'attachement et la réservation, Ansible pour le fichier netplan si besoin), un redémarrage est planifié pendant une fenêtre de maintenance pour vérifier que tout revient, la fiche serveur est mise à jour, et le pare-feu de l'hôte est ajusté pour n'autoriser sur mairie que le flux nécessaire (leçon suivante).

Récapitulatif

  • Le réseau existe dans le noyau (ce que montre ip, perdu au redémarrage) et dans des fichiers (ce que le démon applique au démarrage). ip sert à lire et à tester ; ce qui doit durer s'écrit dans la configuration.
  • Avant tout changement, constatez la pile : netplan et systemd-networkd sur Ubuntu Server et les images cloud Debian, ifupdown sur une Debian installée classiquement, NetworkManager sur Red Hat. networkctl list dit ce que networkd gère.
  • cloud-init écrit 50-cloud-init.yaml (ou interfaces.d/50-cloud-init) : ne le modifiez pas, ajoutez un autre fichier, ou désactivez la gestion par network: {config: disabled}. Même logique pour le nom (preserve_hostname) et /etc/hosts (manage_etc_hosts).
  • Sur Scaleway, le réseau privé fonctionne par DHCP adossé à l'IPAM : on réserve l'adresse plutôt que de la configurer en statique, et on utilise les noms <ressource>.<réseau>.internal.
  • netplan : fichiers en chmod 600, cartes désignées par leur MAC, routes: avec to: default au lieu de gateway4, optional: true pour les interfaces non vitales, netplan generate pour valider, netplan try pour appliquer à distance.
  • La résolution passe par NSS (hosts: files dns), /etc/hosts, /etc/resolv.conf et, sur Ubuntu, le relais 127.0.0.53 de systemd-resolved, qui route les requêtes par lien et par domaine. getent hosts teste comme une application, resolvectl query teste le relais.
  • Diagnostic : lien, adresse, route (ip route get), voisin, nom, port, et arrêt à la première couche qui échoue.

Pour aller plus loin

  • La référence YAML de netplan et la page netplan try, sur netplan.readthedocs.io, pour toutes les clés (VLAN, agrégats, ponts, tunnels WireGuard).
  • Les pages systemd.network(5), systemd-resolved.service(8) et resolved.conf(5), pour comprendre ce que netplan génère et régler le relais DNS.
  • La documentation de Scaleway sur le DNS interne des réseaux privés et sur la configuration manuelle des adresses privées.
  • Le cours Le réseau sous Linux, pour les espaces de noms réseau, les ponts, les VLAN et le routage avancé, et le cours DNS en profondeur pour le protocole lui-même.
  • La leçon suivante, Le pare-feu de l'hôte.
+20 XP Carte du ciel →Mon cosmonaute →

Sources