Debian 13 — Changement du port SSH : corriger le pare-feu et l’ordre sshd sans se bloquer (cas n°87)

Cet article vous a aidé ?

Vous avez changé le port SSH. Cela semblait responsable. Puis votre terminal a gelé à la connexion, votre supervision s’est déclenchée, et vous avez réalisé que vous venez peut‑être d’apprendre à un serveur à vous ignorer. Le pire : tout paraît « correct » depuis l’intérieur.

Le cas n°87 est classique : sshd est configuré pour le nouveau port, mais le pare‑feu et l’ordre de démarrage ne sont pas alignés. Ou sshd n’a jamais lié la socket que vous croyez. La solution n’est pas « redémarrer et prier ». C’est une migration contrôlée avec points de contrôle vérifiables et un plan de retour en arrière qui survit à la latence, aux erreurs humaines et à systemd.

Ce qui a réellement changé (et ce qui n’a pas changé)

Changer le port SSH correspond en réalité à deux problèmes distincts que l’on confond souvent :

  • sshd doit écouter sur le nouveau port (et ne pas échouer à la validation de la configuration, ne pas se binder sur la mauvaise interface, ou ne pas être bloqué par un autre service).
  • le réseau doit autoriser le nouveau port (pare‑feu local, groupes de sécurité cloud, ACL en amont, hôtes de saut, NAT, et tout équipement périmétrique « utile » en entreprise).

Debian 13 ne bloque pas « magiquement » votre nouveau port, mais il embarque des choix modernes : activation de sockets systemd dans certaines configurations, nftables comme backend par défaut pour beaucoup d’outils d’administration, et des politiques de durcissement de plus en plus opinionées. L’ordre de démarrage des services au boot peut importer plus que vous ne le souhaitez, surtout si des règles de pare‑feu sont appliquées tard, vidées de façon inattendue ou remplacées par un outil qui se croit propriétaire.

Voici la vérité centrale : si vous ne pouvez pas prouver ce qui écoute et ce qui est autorisé, vous devinez. Deviner, c’est ce qui mène aux tickets qui commencent par « Ça marchait hier » et finissent par « On a attaché un ISO de secours ».

Faits intéressants et brève histoire (ce qui change votre façon de dépanner)

  1. Le port 22 n’a pas toujours été la valeur par défaut. Dans les premières installations SSH, les ports étaient plus fluides ; les conventions se sont solidifiées avec les outils et la documentation.
  2. Changer le port ne « sécurise » pas SSH au sens cryptographique. Cela réduit surtout le bruit des scans automatisés. Cela peut rester utile opérationnellement.
  3. systemd a rendu le démarrage des services déterministe… et aussi plus facile à réordonner accidentellement. En ajoutant des drop‑ins sans précaution, vous pouvez créer des races au boot qui n’apparaissent qu’après redémarrage.
  4. nftables a remplacé iptables comme orientation des firewalls Linux. Beaucoup de systèmes conservent des couches de compatibilité iptables ; le mix d’outils peut produire des situations où « les règles ont l’air correctes mais ne sont pas actives ».
  5. OpenSSH supporte depuis longtemps plusieurs ports d’écoute. Vous pouvez exécuter 22 et 2222 en parallèle pendant une fenêtre de migration et supprimer l’ancien plus tard.
  6. Les pare‑feu cloud sont distincts des pare‑feu hôtes. Vous pouvez ouvrir nftables et être quand même bloqué par un groupe de sécurité, ou inversement.
  7. sshd peut échouer silencieusement du point de vue des clients distants. Une mauvaise config peut empêcher le bind ; le service peut redémarrer en boucle tandis que les clients voient « Connection refused » ou des timeouts.
  8. Dans certains environnements, systemd gère l’activation de socket pour ssh. Dans ce cas, le port écouté est contrôlé par une unité socket, pas uniquement par sshd_config.

Une citation que je garde collée à mon écran, parce qu’elle résume le travail en une phrase :
« L’espoir n’est pas une stratégie. » — Gene Kranz

Kit de diagnostic rapide

Quand SSH casse après un changement de port, vous n’avez pas besoin de philosophie. Vous avez besoin d’une séquence qui identifie le goulot d’étranglement rapidement.

Première étape : déterminer quelle défaillance vous observez

  • « Connection refused » : rien n’écoute sur cet IP:port, ou un pare‑feu rejette activement.
  • Timeout / blocage : un pare‑feu laisse tomber les paquets, le routage/NAT est erroné, ou vous ciblez la mauvaise IP.
  • Handshake mais échec d’auth : sshd est joignable, mais la configuration (utilisateurs/clefs/AllowUsers/blocs Match) a changé.

Deuxième étape : prouver que sshd écoute là où vous le pensez

  • Vérifiez ss -lntp localement.
  • Consultez systemctl status ssh et les logs.
  • Si l’activation de socket est en jeu, vérifiez systemctl status ssh.socket.

Troisième étape : prouver que le port est autorisé de bout en bout

  • Pare‑feu hôte : état nftables/UFW/iptables.
  • Pare‑feu en amont : groupe de sécurité cloud, NACL, ACL d’entreprise, ou routeur.
  • Depuis un hôte distant : nc -vz ou ssh -vvv pour voir si les SYN reviennent.

Quatrième étape : confirmer l’ordre au boot si ça ne marche qu’après redémarrage

  • Cherchez des services de pare‑feu qui vident/réappliquent les règles après le démarrage de sshd.
  • Vérifiez les dépendances : sshd ne doit pas démarrer « avec succès » puis perdre le port parce que des règles ont été remplacées.

Blague n°1 : Changer les ports SSH à 16h59 est une excellente façon de s’assurer d’être « disponible » tout le week‑end.

Comment changer le port SSH sans provoquer d’indisponibilités auto‑infligées

Le changement de port le plus sûr est une migration, pas un basculement. Faites écouter les deux ports temporairement, validez depuis au moins deux réseaux clients indépendants, puis supprimez l’ancien port. Oui, c’est ennuyeux. Oui, l’ennui est l’objectif.

Principe 1 : Gardez une ligne de vie

Avant de toucher quoi que ce soit : assurez‑vous d’avoir un chemin hors bande. Cela peut être une console série cloud, IPMI/iDRAC/iLO, une console hyperviseur, ou un bastion « casse‑verre ». Si vous ne l’avez pas, votre fenêtre de changement est déjà un pari.

Principe 2 : Validez la config avant de redémarrer

sshd est strict pour une raison. Une faute de frappe dans sshd_config peut faire tomber le service. Validez la config avec sshd -t puis rechargez. Reload vaut mieux que restart quand vous êtes distant — restart ferme les sessions existantes plus rapidement.

Principe 3 : Ne vous fiez pas à un seul outil de pare‑feu

Choisissez une autorité : nftables, ou UFW (qui gère nftables/iptables en interne), ou une politique CM qui possède les règles. Mélanger des commandes iptables avec des systèmes gérés par nftables est la recette pour créer des règles qui semblent présentes mais ne s’appliquent pas, ou qui disparaissent au prochain reload.

Principe 4 : Prouvez la joignabilité depuis l’extérieur

Les vérifications locales mentent par omission. Votre serveur peut écouter sans problème pendant qu’un groupe de sécurité bloque le port. Validez depuis un hôte externe sur Internet ou au moins depuis un segment différent de votre poste d’administration.

Principe 5 : Rendez‑le réversible en 60 secondes

Lorsque vous modifiez le port, préparez un rollback : gardez un shell root ouvert, planifiez un retour automatique du pare‑feu avec at ou systemd-run, et n’annulez que lorsque vous confirmez que vous pouvez vous reconnecter sur le nouveau port.

Blague n°2 : Les pare‑feu sont comme les organigrammes d’entreprise — tout le monde pense les comprendre jusqu’à ce qu’il faille faire une petite exception.

Tâches pratiques (commandes, sorties, décisions)

Ce sont les tâches que j’exécute en production quand quelqu’un dit « SSH est mort après un changement de port ». Chacune inclut ce que la sortie signifie et la décision suivante. Faites‑les dans l’ordre quand c’est possible.

Tâche 1 : Confirmer quel port sshd pense devoir utiliser

cr0x@server:~$ sudo sshd -T | grep -E '^(port|listenaddress)\b'
port 2222
listenaddress 0.0.0.0
listenaddress ::

Signification : C’est la configuration effective de sshd après includes et blocs Match. Si port affiche encore 22, votre édition n’a pas été appliquée ou est surchargée. Si listenaddress est restreint, vous pourriez binder uniquement sur une interface de gestion.
Décision : Si le port est incorrect, corrigez la config d’abord. Si le port est correct, passez aux sockets d’écoute.

Tâche 2 : Valider la syntaxe de sshd avant toute recharge

cr0x@server:~$ sudo sshd -t
cr0x@server:~$ echo $?
0

Signification : Le code de sortie 0 signifie que la syntaxe est OK. Non‑zéro signifie que sshd n’acceptera pas cette config au démarrage.
Décision : Si non‑zéro, ne redémarrez pas. Corrigez la config et relancez sshd -t.

Tâche 3 : Vérifier ce qui écoute réellement sur la machine

cr0x@server:~$ sudo ss -lntp | grep -E '(:22|:2222)\b' || true
LISTEN 0      128          0.0.0.0:2222      0.0.0.0:*    users:(("sshd",pid=944,fd=3))
LISTEN 0      128             [::]:2222         [::]:*    users:(("sshd",pid=944,fd=4))

Signification : sshd est lié sur IPv4 et IPv6 pour le port 2222. Si vous voyez uniquement IPv6, les clients IPv4 échoueront. Si vous ne voyez rien, sshd ne s’est pas bindé — soit il est arrêté, soit l’activation de socket est en jeu, soit il a planté.
Décision : Si rien n’écoute, inspectez l’état systemd et les logs ensuite.

Tâche 4 : Vérifier l’état du service sshd et les erreurs récentes

cr0x@server:~$ systemctl status ssh --no-pager
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; enabled; preset: enabled)
     Active: active (running) since Wed 2025-12-31 10:11:22 UTC; 2min 9s ago
       Docs: man:sshd(8)
             man:sshd_config(5)
   Main PID: 944 (sshd)
      Tasks: 1 (limit: 19000)
     Memory: 6.4M
        CPU: 72ms
     CGroup: /system.slice/ssh.service
             └─944 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"

Signification : « Running » est bon, mais ne prouve pas la joignabilité. Si vous voyez des boucles de redémarrage, des problèmes de config ou de bind sont probables.
Décision : Si actif, passez au pare‑feu. Si en échec, consultez les logs.

Tâche 5 : Lire les logs sshd pour problèmes de bind et d’auth

cr0x@server:~$ sudo journalctl -u ssh -n 50 --no-pager
Dec 31 10:11:21 server sshd[944]: Server listening on 0.0.0.0 port 2222.
Dec 31 10:11:21 server sshd[944]: Server listening on :: port 2222.

Signification : Le bind a réussi. Si vous voyez à la place « Bad configuration option » ou « Could not load host key », sshd peut refuser des connexions.
Décision : Si le bind est OK, élargissez l’investigation : pare‑feu et couches en amont.

Tâche 6 : Détecter si l’activation de socket systemd est impliquée

cr0x@server:~$ systemctl list-unit-files | grep -E '^ssh\.socket'
ssh.socket                                disabled        enabled

Signification : Si ssh.socket est enabled et actif, il peut définir le(s) port(s) d’écoute. S’il est disabled, sshd se bind directement.
Décision : Si l’activation de socket est activée, inspectez et éditez l’unité socket, pas seulement sshd_config.

Tâche 7 : Inspecter l’unité socket pour les ports d’écoute (si applicable)

cr0x@server:~$ systemctl cat ssh.socket
# /lib/systemd/system/ssh.socket
[Unit]
Description=OpenBSD Secure Shell server socket
Before=sockets.target

[Socket]
ListenStream=22
Accept=no

[Install]
WantedBy=sockets.target

Signification : Cette socket est toujours sur 22. Si elle est active, les clients visant 2222 échoueront.
Décision : Mettez à jour ListenStream (ou ajoutez‑en un autre) et redémarrez la socket, ou désactivez l’activation de socket et lancez ssh.service normalement.

Tâche 8 : Confirmer le backend pare‑feu et l’état des règles actives

cr0x@server:~$ sudo update-alternatives --display iptables | sed -n '1,12p'
iptables - auto mode
  link best version is /usr/sbin/iptables-nft
  link currently points to /usr/sbin/iptables-nft
  link iptables is /usr/sbin/iptables
  slave iptables-restore is /usr/sbin/iptables-restore
  slave iptables-save is /usr/sbin/iptables-save

Signification : Cet hôte utilise iptables‑nft en compatibilité. Si vous exécutez des commandes iptables « classiques » en supposant un comportement legacy, votre modèle mental peut diverger.
Décision : Préférez inspecter nftables directement avec nft list ruleset.

Tâche 9 : Lister les règles nftables et chercher votre port SSH

cr0x@server:~$ sudo nft list ruleset | sed -n '1,120p'
table inet filter {
	chain input {
		type filter hook input priority 0; policy drop;
		ct state established,related accept
		iif "lo" accept
		tcp dport 2222 accept
		icmp type echo-request accept
	}
}

Signification : La politique drop signifie « tout ce qui n’est pas explicitement accepté meurt ». Vous avez bien une règle acceptant tcp/2222.
Décision : Si la règle manque, ajoutez‑la avant de déplacer sshd sur le nouveau port (ou gardez les deux ports temporairement).

Tâche 10 : Si vous utilisez UFW, vérifiez qu’il autorise réellement le nouveau port

cr0x@server:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
2222/tcp                    ALLOW IN    Anywhere
2222/tcp (v6)               ALLOW IN    Anywhere (v6)

Signification : UFW autorise tcp/2222 pour IPv4 et IPv6. Si une famille n’existe pas, les clients de cette famille échoueront.
Décision : Ajoutez les deux familles si vous êtes dual‑stack. Puis testez depuis l’extérieur.

Tâche 11 : Tester depuis le serveur lui‑même (sanity check, pas une preuve)

cr0x@server:~$ nc -vz 127.0.0.1 2222
Connection to 127.0.0.1 2222 port [tcp/*] succeeded!

Signification : Le loopback local fonctionne. Cela prouve « écoute » mais pas « accessible à distance ».
Décision : Si cela échoue, sshd n’écoute pas ou la politique locale bloque. Corrigez localement avant de toucher l’amont.

Tâche 12 : Tester depuis un hôte distant avec SSH verbeux

cr0x@server:~$ ssh -vvv -p 2222 admin@203.0.113.10
OpenSSH_9.7p1 Debian-2, OpenSSL 3.0.14 4 Jun 2024
debug1: Connecting to 203.0.113.10 [203.0.113.10] port 2222.
debug1: Connection established.
debug1: Remote protocol version 2.0, remote software version OpenSSH_9.7p1 Debian-2
debug1: Authenticating to 203.0.113.10:2222 as 'admin'
debug1: Offering public key: /home/cr0x/.ssh/id_ed25519
debug1: Server accepts key: /home/cr0x/.ssh/id_ed25519
Authenticated to 203.0.113.10 ([203.0.113.10]:2222).

Signification : Cela montre les étapes critiques : connexion TCP, handshake, auth. Si ça bloque avant « Connection established », c’est probablement un pare‑feu ou routage. Si le handshake a lieu mais que l’auth échoue, concentrez‑vous sur les contrôles d’auth de sshd.
Décision : Si la connexion distante fonctionne, gardez la session ouverte et procédez à la suppression de l’ancien port plus tard. Sinon, ne retirez pas 22 pour l’instant.

Tâche 13 : Confirmer que le service est joignable sur l’interface publique (erreurs d’adresse d’écoute)

cr0x@server:~$ ip -br a
lo               UNKNOWN        127.0.0.1/8 ::1/128
ens3             UP             203.0.113.10/24 2001:db8:10::10/64

Signification : Si sshd est lié à 127.0.0.1 ou à une interface privée uniquement, l’accès distant échoue.
Décision : Assurez‑vous que ListenAddress dans sshd_config couvre les interfaces correctes, ou retirez‑le pour binder sur toutes.

Tâche 14 : Détecter les bugs d’ordre « ça marche jusqu’au reboot »

cr0x@server:~$ systemd-analyze critical-chain ssh.service
ssh.service +42ms
└─network-online.target @3.211s
  └─systemd-networkd-wait-online.service @1.902s +1.292s
    └─systemd-networkd.service @1.501s +386ms
      └─systemd-udevd.service @1.221s +265ms
        └─systemd-tmpfiles-setup-dev.service @1.159s +54ms
          └─kmod-static-nodes.service @1.085s +58ms
            └─systemd-journald.socket @1.010s

Signification : Cela vous dit ce que ssh a attendu. Si votre service de pare‑feu arrive plus tard et vide les règles, ssh peut être joignable brièvement puis plus du tout.
Décision : Inspectez l’ordre des unités pare‑feu et assurez‑vous que le pare‑feu est appliqué avant que ssh soit considéré « prêt », ou faites en sorte que le pare‑feu ne vide pas les politiques établies de façon inattendue.

Tâche 15 : Vérifier l’ordonnancement du service pare‑feu et s’il vide les règles

cr0x@server:~$ systemctl status nftables --no-pager
● nftables.service - nftables
     Loaded: loaded (/lib/systemd/system/nftables.service; enabled; preset: enabled)
     Active: active (exited) since Wed 2025-12-31 10:10:59 UTC; 2min 50s ago
       Docs: man:nft(8)
    Process: 611 ExecStart=/usr/sbin/nft -f /etc/nftables.conf (code=exited, status=0/SUCCESS)

Signification : nftables a chargé un fichier puis est sorti (normal). Si vous avez un autre gestionnaire de pare‑feu, vérifiez son unité et ses scripts pour un « flush des règles ».
Décision : Si le pare‑feu n’est pas activé, les règles ne persisteront peut‑être pas après reboot. Activez‑le ou gérez la persistance autrement.

Tâche 16 : Prouver la persistance : vérifier la config reboot‑safe sans redémarrer

cr0x@server:~$ sudo nft -c -f /etc/nftables.conf && echo "nftables.conf parses OK"
nftables.conf parses OK

Signification : -c vérifie la syntaxe et la sémantique sans appliquer. Si ça échoue, un reboot pourrait appliquer un jeu de règles cassé et bloquer SSH.
Décision : Corrigez les erreurs de parse maintenant. Puis confirmez que l’unité est enable pour charger les bonnes règles au boot.

Tâche 17 : Planifier un rollback temporisé des changements de pare‑feu

cr0x@server:~$ echo "sudo nft flush ruleset; sudo nft -f /root/nftables.known-good.conf" | at now + 5 minutes
warning: commands will be executed using /bin/sh
job 12 at Wed Dec 31 10:20:00 2025

Signification : Vous venez de créer un parachute. Si vous vous bloquez, le serveur revertira dans 5 minutes (en supposant que la tâche puisse s’exécuter).
Décision : N’annulez la tâche que lorsque vous avez confirmé SSH distant sur le nouveau port et validé la persistance des règles du pare‑feu.

Tâche 18 : Annuler le rollback une fois le nouveau port vérifié

cr0x@server:~$ atq
12	Wed Dec 31 10:20:00 2025 a root
cr0x@server:~$ atrm 12
cr0x@server:~$ atq

Signification : Plus de rollback planifié.
Décision : À présent, il est sûr de procéder à la suppression du port 22 (plus tard), car vous avez prouvé l’accès et retiré les petites roues.

Ordonnancement systemd : sshd vs pare‑feu au démarrage

La plupart des incidents « J’ai changé le port et ça marchait jusqu’au reboot » ne sont pas mystiques. Ce sont des problèmes d’ordre et de propriété : un pare‑feu se charge après sshd et remplace les règles, un outil vide le jeu de règles, ou un agent de gestion de configuration écrit une politique plus ancienne au boot.

Ce que « ordonnancement » signifie vraiment ici

L’ordonnancement systemd ne concerne pas seulement quelle unité démarre en premier. Il concerne aussi quelle unité est considérée « prête » et ce qu’elle tire via ses dépendances. sshd « active (running) » ne signifie pas « joignable depuis votre portable ». Cela signifie juste que le démon est vivant.

Faire appliquer les règles de pare‑feu tôt, de façon cohérente, et depuis une seule source

Sur Debian, si vous gérez le pare‑feu via nftables.service, les règles sont typiquement chargées depuis /etc/nftables.conf. Si vous gérez via UFW, UFW a son propre service systemd et générera les règles. Si un agent d’entreprise gère le système, il peut réécrire les deux.

L’objectif est simple :

  • La politique de pare‑feu est appliquée avant que vous ne comptiez dessus pour l’accès.
  • La politique de pare‑feu n’est pas vidée ou remplacée de façon inattendue après que sshd soit déjà en service.
  • Le port SSH dont vous avez besoin est autorisé dans la même politique qui se charge réellement au boot.

Approche pratique : garder sshd joignable pendant les transitions

Lors de la migration de ports, autorisez les ports ancien et nouveau dans le pare‑feu, et configurez sshd pour écouter sur les deux ports temporairement. Ensuite, supprimez le port 22 du pare‑feu seulement après avoir validé le nouvel accès depuis plusieurs points de vue et survécu à au moins un reboot.

Éditer sshd_config en toute sécurité : ports multiples

OpenSSH supporte plusieurs directives Port. Pour une fenêtre de migration, faites ceci :

cr0x@server:~$ sudo sh -c 'printf "\n# Migration window: keep 22 temporarily\nPort 22\nPort 2222\n" >> /etc/ssh/sshd_config'

Puis validez et rechargez (pas restart) quand vous êtes distant :

cr0x@server:~$ sudo sshd -t && sudo systemctl reload ssh

Décision : Ne supprimez Port 22 qu’après avoir pu vous connecter de manière fiable sur le nouveau port et confirmé la persistance du pare‑feu.

Quand ssh.socket change la donne

Si ssh.socket est activé, systemd possède la socket d’écoute. Dans ce cas :

  • Modifier Port dans sshd_config ne produira pas forcément l’effet attendu.
  • Vous devriez modifier ListenStream dans l’unité socket (de préférence via un drop‑in).
  • Puis redémarrez l’unité socket, pas seulement le service.

Si vous ne voulez pas de l’activation de socket, désactivez‑la intentionnellement — ne vivez pas dans l’état incertain où vous ignorez qui possède le port.

Recettes pare‑feu : nftables, UFW, iptables

Le « bon » pare‑feu est celui que votre système utilise réellement, de façon cohérente au travers des reboots et de l’automatisation. Sur Debian 13, nftables est la voie la plus propre. Si vous utilisez UFW, traitez‑le comme votre seule interface. Si vous êtes coincé avec iptables dans un parc legacy, soyez explicite sur le backend (legacy ou nft).

nftables : autoriser le nouveau port SSH (table inet)

Exemple de snippet pour /etc/nftables.conf. On suppose une politique d’entrée par défaut drop :

cr0x@server:~$ sudo grep -n 'chain input' -n /etc/nftables.conf | head
12:	chain input {

Ajoutez une règle d’acceptation proche des autres accept TCP :

cr0x@server:~$ sudo nft add rule inet filter input tcp dport 2222 accept

Signification : Cela modifie le ruleset en cours mais pas nécessairement le fichier de config. Si vous redémarrez sans sauvegarder, cela peut disparaître.
Décision : Répercutez immédiatement le changement dans /etc/nftables.conf (ou votre include géré) et validez avec nft -c.

UFW : autoriser le nouveau port SSH (et le rendre survivable)

cr0x@server:~$ sudo ufw allow 2222/tcp
Rule added
Rule added (v6)

Signification : UFW a créé des règles pour IPv4 et IPv6.
Décision : Gardez ufw status verbose comme source de vérité. Ne mélangez pas avec des règles nft brutes sauf si vous aimez déboguer à 2h du matin.

iptables (parcs legacy) : autoriser le nouveau port avec prudence

cr0x@server:~$ sudo iptables -S INPUT | sed -n '1,25p'
-P INPUT DROP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT

Ajoutez la nouvelle règle :

cr0x@server:~$ sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT

Signification : Règle ajoutée en fin de chaîne ; si l’ordre importe (et c’est souvent le cas), vous préférerez insérer avant une règle de rejet/log.
Décision : Assurez la persistance via le mécanisme choisi (fichier géré ou service). Sinon, un reboot vous fera revenir en arrière.

N’oubliez pas les pare‑feu en amont

Le pare‑feu hôte peut être parfait et quand même inutile si :

  • un groupe de sécurité cloud bloque 2222,
  • une ACL périmétrique d’entreprise n’autorise que 22 vers votre sous‑réseau,
  • un load balancer a un health check fixé sur 22 et déclare votre nœud mort.

Votre preuve est dans le comportement réseau : « refused » signifie généralement que vous avez atteint l’hôte ; les timeouts signifient souvent que vous ne l’avez pas atteint. Traitez cette différence comme une boussole.

Trois retours d’expérience en entreprise

1) L’incident causé par une mauvaise hypothèse : « On a ouvert le pare‑feu »

Une entreprise moyenne a migré une flotte vers Debian 13 et décidé de « réduire la surface d’attaque » en déplaçant SSH sur 2222. L’ingénieur de service a ouvert 2222 dans UFW et confirmé que ss -lntp montrait sshd à l’écoute. Tout semblait validé. Ils ont ensuite supprimé le port 22 partout. Confiants, ordonnés, et faux.

Le lendemain matin, la moitié de la flotte était injoignable. Pas toutes — seulement les hôtes d’une région. Les logs des hôtes joignables étaient propres, et sur les injoignables la console montrait sshd fonctionnel. L’équipe a passé des heures à chasser des bugs fantômes et a même reconstruit une VM depuis une image juste pour la « réinitialiser ».

La cause racine était en amont : un template de groupe de sécurité cloud était spécifique à la région. Une région n’autorisait que 22, une autre utilisait un service nommé « SSH » mappé sur 22, et seule une troisième avait la règle 2222. L’hypothèse de l’ingénieur — « le pare‑feu hôte équivaut à l’accès » — était le piège.

La correction fut ennuyeuse : mettre à jour les groupes de sécurité, déployer l’écoute dual‑port pendant 48 heures, et ajouter un test de connectivité externe dans la procédure de changement. L’équipe a appris à considérer « je peux me connecter depuis l’intérieur du VPC » comme une vérité partielle, pas comme une victoire.

2) L’optimisation qui a tourné mal : « Simplifions le démarrage du pare‑feu »

Une grande équipe plateforme a standardisé nftables et écrit une petite unité systemd oneshot qui vidait et rechargait le ruleset au boot. Leur objectif était sain : une source de vérité, pas de dérive, démarrage rapide. Ils l’ont déployée largement et sont passés à autre chose.

Quelques semaines plus tard, une autre équipe a changé les ports SSH pendant une fenêtre approuvée. Ils ont mis à jour /etc/nftables.conf, rechargé nftables, validé l’accès externe, puis rebooté pour un update du kernel. Après le reboot, SSH était mort — mais seulement de façon intermittente pour certains hôtes.

Le coupable était cette unité d’« optimisation ». Elle s’exécutait après network‑online mais avant que certains noms d’interface ne se stabilisent, et elle vidait aussi les règles comme première étape. Pendant une courte fenêtre, l’hôte avait une politique drop par défaut sans règles acceptées chargées. Certaines connexions tentées pendant cette fenêtre ont échoué. Les humains ont dit « SSH cassé », mais c’était en réalité une course au démarrage plus un flush agressif.

La correction permanente : arrêter de vider sans discernement, charger un ruleset atomique, et ordonner l’unité pare‑feu assez tôt pour que les services dépendant d’un accès entrant n’éprouvent pas un bref trou « deny all ». Aussi : ne « optimisez » pas le démarrage du pare‑feu sans mesurer l’impact sur la joignabilité au boot.

3) La pratique ennuyeuse mais correcte qui a sauvé la mise : dual‑port + rollback temporisé

Une équipe de services financiers avait une règle : tout changement pouvant vous verrouiller doit avoir un rollback temporisé. Pas « on fera attention ». Un revert planifié réel. Les gens se plaignaient que c’était paranoïaque. Puis un vendredi, ça leur a rendu service, silencieusement.

Un ingénieur a changé SSH en 2222 et mis à jour le pare‑feu. Ça fonctionnait depuis son poste. Ça ne fonctionnait pas depuis les runners CI qui habitaient un sous‑réseau séparé avec une politique de sortie différente. Personne n’a remarqué avant que les déploiements commencent à échouer. L’équipe avait encore une session SSH ouverte, mais ils étaient à un déconnectage d’un incident réel.

Parce qu’ils avaient planifié un rollback, ils ont pu expérimenter en toute sécurité. Ils ont rouvert 22 temporairement, corrigé la politique de sortie des runners, testé 2222 depuis les deux réseaux, puis supprimé 22. Pas de consoles de secours, pas de réimages, pas de panique « qui a le mot de passe de l’hyperviseur ? »

La leçon est consternante mais cohérente : la meilleure pratique de fiabilité ressemble souvent à une cérémonie inutile jusqu’au moment où elle empêche une panne.

Erreurs courantes : symptôme → cause → correctif

1) Symptom : « Connection refused » sur le nouveau port

  • Cause racine : sshd n’écoute pas ce port, ou il est lié seulement à localhost/une autre interface, ou ssh.socket est toujours sur 22.
  • Correctif : Vérifiez sshd -T, ss -lntp, et systemctl cat ssh.socket. Corrigez Port/ListenAddress ou l’unité socket, validez avec sshd -t, puis reload.

2) Symptom : Timeout / blocage à la connexion

  • Cause racine : drop du pare‑feu (hôte ou en amont), mauvaise IP, routage/NAT incorrect, ou groupe de sécurité non mis à jour.
  • Correctif : Depuis un hôte distant, lancez ssh -vvv. Sur le serveur, vérifiez nftables/UFW. Ensuite confirmez les règles en amont. Les timeouts ne sont presque jamais dus à une mauvaise config sshd.

3) Symptom : Ça marche depuis un réseau, échoue depuis un autre

  • Cause racine : allowlists asymétriques ; l’egress d’entreprise bloque les ports élevés ; seul un chemin a été mis à jour.
  • Correctif : Testez depuis au moins deux points de vue (bureau + subnet CI, ou ISP domestique + bastion). Mettez à jour les ACL. Envisagez de garder 22 ouvert mais restreint à la plage IP du bastion pendant la migration.

4) Symptom : Ça marche jusqu’au reboot, puis échoue

  • Cause racine : règles pare‑feu non persistantes ; un service au boot vide les règles ; activation de socket revert ; gestion de config qui écrase vos changements.
  • Correctif : Assurez‑vous que le service pare‑feu est enabled et charge une config valide. Confirmez avec nft -c -f /etc/nftables.conf. Auditez systemctl list-dependencies pour votre outil pare‑feu et vérifiez les politiques CM.

5) Symptom : SSH se connecte mais l’auth échoue après changement de port

  • Cause racine : Vous avez modifié autre chose que le port : AllowUsers, PasswordAuthentication, PubkeyAuthentication, ou un bloc Match s’applique différemment.
  • Correctif : Utilisez sshd -T pour voir les paramètres effectifs ; vérifiez journalctl -u ssh pour les messages d’auth ; assurez‑vous que les fichiers de clefs et leurs permissions sont corrects.

6) Symptom : IPv6 fonctionne, IPv4 échoue (ou inversement)

  • Cause racine : sshd lié seulement à une famille ; règles pare‑feu existantes seulement pour v4 ou v6 ; les clients préfèrent une famille que vous n’avez pas testée.
  • Correctif : Confirmez que ss montre à la fois 0.0.0.0:2222 et [::]:2222 si vous souhaitez du dual‑stack. Dupliquez les règles pare‑feu pour les deux familles.

7) Symptom : Le port semble ouvert localement, mais le distant voit « No route to host »

  • Cause racine : problème de routage/ACL en amont ; parfois l’ICMP est bloqué et le PMTU complique les choses, mais « No route » est généralement réseau.
  • Correctif : Confirmez l’IP publique correcte, vérifiez le groupe de sécurité/NACL, et testez depuis un hôte dans la même région/sous‑réseau.

Checklists / plan étape par étape

Plan A : Migration sûre (recommandé en production)

  1. Gardez une session SSH existante ouverte (de préférence deux : un shell root/sudo, un observateur lecture seule).
  2. Confirmez l’accès hors bande (console cloud, IPMI, console hyperviseur).
  3. Ouvrez d’abord le nouveau port dans le pare‑feu (hôte et amont). Ne supprimez pas 22 encore.
  4. Configurez sshd pour écouter les deux ports : Port 22 et Port 2222.
  5. Validez la config : sshd -t et sshd -T | grep '^port '.
  6. Rechargez sshd (pas restart) : systemctl reload ssh.
  7. Vérifiez les sockets d’écoute : ss -lntp | grep ':2222'.
  8. Testez depuis deux points distants : poste de travail + un hôte dans un autre réseau.
  9. Planifiez un job de rollback avant de retirer 22 ; annulez‑le seulement après succès.
  10. Faites au moins un reboot durant la fenêtre si possible, pour prouver la persistance et l’ordre.
  11. Retirez le port 22 de sshd_config et du pare‑feu après la fenêtre de migration.
  12. Mettez à jour l’automatisation (inventaire Ansible, configs bastion, monitoring, runbooks d’incident).

Plan B : Récupération d’urgence quand vous êtes déjà bloqué

  1. Utilisez la console hors bande pour accéder à l’hôte.
  2. Vérifiez l’état et les logs de sshd : systemctl status ssh, journalctl -u ssh.
  3. Vérifiez les ports d’écoute : ss -lntp.
  4. Autorisez temporairement le port 22 (ou votre port connu‑bon) dans le pare‑feu hôte et en amont.
  5. Restaurez sshd_config en dual‑port et validez avec sshd -t.
  6. Rechargez sshd, puis testez depuis l’extérieur.
  7. Puis seulement retentez une migration contrôlée en suivant le Plan A.

Plan C : Si l’activation de socket systemd est activée

  1. Confirmez la propriété : vérifiez si ssh.socket est enabled et actif.
  2. Éditez via un drop‑in plutôt que de modifier les unités vendor directement.
  3. Ajoutez un nouveau ListenStream pour la migration (ex. 22 et 2222), puis reload daemon et redémarrez la socket.
  4. Validez avec ss -lntp et des tests distants.
  5. Supprimez 22 plus tard en enlevant l’ancien ListenStream.

FAQ

1) Est‑ce que changer le port SSH en vaut la peine ?

Ce n’est pas une magie de sécurité. C’est une réduction de bruit. Si vous exigez déjà des clefs, désactivez l’auth par mot de passe, et restreignez par IP ou bastion, le changement de port est optionnel. Dans des environnements à fort bruit, il peut réduire le spam de logs et les tentatives par force brute. Traitez‑le comme un ajustement opérationnel, pas comme un contrôle sur lequel vous misez votre audit.

2) Dois‑je restart ou reload sshd ?

Reload quand vous êtes distant. Le reload applique la config sans fermer la plupart des sessions existantes. Restart est acceptable quand vous avez une console ou une fenêtre de maintenance, mais c’est un risque inutile quand vous modifiez le moyen de connexion actif.

3) Est‑ce que sshd peut écouter sur deux ports à la fois ?

Oui. Ajoutez plusieurs lignes Port dans /etc/ssh/sshd_config. C’est la technique de migration la plus sûre car réversible et testable.

4) J’ai changé Port, mais sshd écoute encore sur 22. Pourquoi ?

Causes communes : un fichier de configuration ultérieur l’écrase (includes), un bloc Match modifie le comportement, ou l’activation de socket systemd est activée et ssh.socket reste sur 22. Utilisez sshd -T et systemctl cat ssh.socket pour arrêter de deviner.

5) Pourquoi j’ai des timeouts au lieu de « refused » ?

Les timeouts signifient généralement une suppression de paquets quelque part : politique drop du pare‑feu hôte, groupe de sécurité, ACL amont, ou routage. « Refused » signifie généralement que vous avez atteint l’hôte et que rien n’écoutait (ou que c’était rejeté activement). Cette distinction est un des meilleurs signaux de dépannage.

6) Dois‑je ouvrir le port pour IPv6 aussi ?

Si votre hôte a de la connectivité IPv6 et que des clients peuvent l’atteindre, oui. Sinon vous aurez des résultats incohérents : un client touche v6 et ça marche, un autre touche v4 et échoue. Dupliquez les règles pour les deux familles si vous êtes dual‑stack.

7) Quelle est la technique de rollback la plus sûre ?

Gardez une session existante ouverte et planifiez un rollback temporisé du pare‑feu et/ou de la config sshd avec at ou systemd-run. N’annulez le rollback qu’après vous être connecté avec succès sur le nouveau port depuis un hôte externe et avoir validé la persistance après reboot.

8) Comment éviter de casser l’automatisation et la supervision ?

L’inventaire et les outils supposent souvent le port 22 : gestion de configuration, agents de sauvegarde, contrôles de monitoring, bastions, et runners CI. Mettez à jour ces configs pendant la fenêtre de migration alors que les deux ports fonctionnent, puis retirez 22. Si vous inversez d’abord, vous passerez votre soirée à retrouver chaque hypothèse cachée.

9) Changer le port casse‑t‑il fail2ban ou les règles IDS ?

Ça peut. Certains jeux de règles et jails sont liés aux définitions de service « ssh » ou à l’hypothèse du port 22. Après la migration, vérifiez que vos outils de sécurité surveillent le nouveau port et n’agissent pas en silence comme si de rien n’était.

10) Dois‑je restreindre SSH par IP source plutôt que changer le port ?

Préférez la restriction par source (bastion‑only, VPN‑only, IP admin allowlist) quand c’est possible. Le changement de port peut s’ajouter en couche, mais le contrôle d’accès bat l’obscurcissement. Faites les deux si cela correspond à votre modèle de menace et à votre tolérance opérationnelle.

Conclusion : prochaines étapes pratiques

Si vous ne retenez qu’une chose du cas n°87, que ce soit ceci : traitez les changements de port SSH comme une migration en production, pas comme un simple tweak de configuration. Ouvrez d’abord le nouveau chemin, gardez l’ancien pendant la validation, prouvez la joignabilité depuis l’extérieur, puis fermez l’ancienne porte.

Prochaines étapes qui rapportent immédiatement :

  • Exécutez sshd -T et ss -lntp pour confirmer la réalité, pas l’intention.
  • Choisissez une autorité pare‑feu (nftables ou UFW) et rendez‑la persistante au reboot.
  • Adoptez la migration dual‑port plus un job de rollback temporisé comme procédure standard.
  • Redémarrez pendant la fenêtre de changement au moins une fois, si possible, pour attraper les problèmes d’ordre et de persistance tant que des humains sont réveillés.

Les systèmes de production ne récompensent pas la bravoure. Ils récompensent des habitudes répétables, des preuves propres, et le genre de paranoïa qui ressemble à du professionnalisme.

← Précédent
ZFS et Proxmox : paramètres de stockage VM à modifier immédiatement
Suivant →
Dépannage de la performance Proxmox : CPU steal, IO wait, ARC ZFS et voisins bruyants

Laisser un commentaire