Changer le port SSH avec SELinux et firewalld
Sur Rocky Linux ou AlmaLinux, changez le port SSH sans perdre votre session : configurez firewalld, le label SELinux et sshd_config dans le bon ordre.
Pourquoi le changement du port SSH nécessite trois étapes ici
Pour changer le port SSH sur Rocky Linux, AlmaLinux, CentOS Stream ou Fedora, une seule modification ne suffit pas. Trois systèmes distincts déterminent chacun si une connexion sur le nouveau port fonctionne. firewalld décide si le paquet atteint la machine. SELinux décide si sshd est autorisé à utiliser ce numéro de port. sshd_config détermine le port demandé par le daemon. Si vous oubliez l’étape SELinux, le daemon refuse de démarrer. Si vous oubliez l’étape firewalld, il démarre et écoute, mais personne ne peut le joindre.
Sur Ubuntu, cette opération se limite à une modification et à un redémarrage, car Ubuntu utilise AppArmor à la place de SELinux et ne fournit aucun profil qui limite les ports auxquels sshd peut s’attacher. Si ufw est actif, ajoutez une règle. C’est toute la différence. Sur une installation fraîche, la famille RHEL fournit firewalld en fonctionnement et SELinux en mode enforcing, et ces deux composants tiennent compte des numéros de port.
Effectuez les opérations dans cet ordre pour maintenir votre session actuelle active à chaque étape :
- Ouvrez le nouveau port dans firewalld en laissant le port 22 ouvert pour le moment.
- Ajoutez l’étiquette SELinux du nouveau port avec
semanage. - Définissez le port dans la configuration de sshd.
- Redémarrez
sshd, puis connectez-vous sur le nouveau port depuis un deuxième terminal avant de fermer le premier.
Repérez la console web de votre fournisseur (VNC ou série) avant de commencer et vérifiez que vous pouvez vous y connecter. Cette console vous permettra de reprendre la main si la modification se passe mal. Un changement de port est l’une des raisons les plus fréquentes pour lesquelles un locataire se verrouille lui-même hors d’un serveur qu’il vient de payer.
Installez d’abord semanage
semanage est l’outil qui modifie les paramètres de la policy SELinux. Une installation minimale de Rocky Linux ou d’AlmaLinux ne l’inclut pas. Il se trouve dans policycoreutils-python-utils.
sudo dnf install -y policycoreutils-python-utilsL’exécution de la commande avant l’installation de ce paquet affiche sudo: semanage: command not found. C’est à ce stade que beaucoup de lecteurs concluent que SELinux n’est pas installé et passent cette étape. SELinux est bien installé. Seul l’outil de gestion est manquant. Si la syntaxe de dnf est nouvelle pour vous, les équivalents des commandes dnf et apt permettent de retrouver les commandes que vous connaissez déjà.
Choisissez un port et vérifiez qu’aucun service ne l’utilise
N’importe quel port TCP libre entre 1024 et 65535 convient. Effectuez ces deux vérifications avant de l’utiliser :
sudo ss -tlnp | grep -w 2222
sudo semanage port -l | grep -w 2222La première vérifie si un processus est déjà en écoute sur ce numéro. La seconde vérifie si la politique SELinux l’associe déjà à un autre type de service. Un port libre ne renvoie rien dans les deux cas. Si la politique l’utilise déjà, le semanage port -a de l’étape 2 échoue avec ValueError: Port tcp/2222 already defined. Il faut alors choisir un autre numéro.
2222 sert d’exemple dans ce guide. C’est également le premier port qu’un scanner teste après le port 22. Sur un serveur réel, choisissez donc un port moins évident.
Étape 1 : ouvrir le port dans firewalld
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports--permanent écrit la règle dans le fichier de zone sur le disque et ne modifie pas le firewall en cours d’exécution. --reload charge la configuration enregistrée sur le disque dans le firewall en cours d’exécution. Si vous omettez le rechargement, la règle existe, mais ne fait rien jusqu’au prochain redémarrage de firewalld. C’est l’une des causes les plus fréquentes d’échec apparent de toute cette procédure.
Laissez l’entrée de service ssh telle quelle pour le moment. Elle maintient le port 22 ouvert et vous sert de solution de secours pendant les tests.
Vérifiez également le panneau de contrôle de votre fournisseur. De nombreux hébergeurs utilisent un firewall réseau devant le VPS, en dehors du système d’exploitation. Un port ouvert dans firewalld peut donc toujours être bloqué en amont. Le guide des bases de firewalld pour un VPS explique les zones et la distinction entre la configuration runtime et la configuration permanente si ce modèle ne vous est pas familier.
Étape 2 : étiquetez le port pour SELinux
sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo semanage port -l | grep ssh_port_t-a ajoute une nouvelle affectation de port. -t ssh_port_t est le type associé aux ports SSH. La deuxième commande répertorie tout ce que ssh_port_t couvre désormais. Vous pouvez ainsi vérifier que votre numéro a bien été ajouté avant de modifier le daemon.
Pourquoi SELinux bloque le port
SELinux (security-enhanced Linux) attribue une étiquette à chaque objet du système. Les numéros de port TCP sont eux aussi des objets. Le daemon SSH s’exécute dans un domaine appelé sshd_t. La policy autorise sshd_t à écouter sur les ports TCP portant l’étiquette ssh_port_t. Par défaut, seul le port 22 porte cette étiquette. Si vous demandez au daemon d’écouter sur 2222, le kernel vérifie l’étiquette, trouve le type générique attribué par la policy à ce numéro et refuse la permission name_bind sur le socket.
C’est pourquoi cette erreur ne ressemble pas à un problème de firewall. Le kernel refuse l’opération avant même qu’un socket en écoute existe. sshd signale l’erreur et se termine. Avec un problème de firewall, la situation est inverse : le daemon fonctionne normalement et les paquets sont rejetés à leur arrivée.
getenforce indique le mode utilisé par le système. En mode Permissive, un refus est journalisé mais n’est pas appliqué. Le changement de port semble donc fonctionner, puis échoue lorsque quelqu’un exécute setenforce 1 ou lorsque le système redémarre en mode enforcing. Étiquetez le port dans tous les cas. Le guide des bases de SELinux pour un serveur explique en détail les modes, les contextes et les booleans. Les ports ne sont pas les seuls objets concernés. La même policy empêche un conteneur de lire un répertoire de l’hôte monté tant que ce chemin n’a pas été réétiqueté. C’est pourquoi installer Docker sur Rocky Linux ou AlmaLinux comporte une étape SELinux que les guides Ubuntu ne mentionnent jamais.
Étape 3 : définir le port dans la configuration de sshd
Sur Rocky Linux 9 et 10, AlmaLinux 9 et 10, ainsi que sur les versions actuelles de Fedora, /etc/ssh/sshd_config commence par une directive include. Le fichier drop-in est donc l’emplacement approprié pour votre modification. Les mises à jour des paquets n’écraseront ainsi jamais votre configuration.
grep -n '^Include' /etc/ssh/sshd_config
echo 'Port 2222' | sudo tee /etc/ssh/sshd_config.d/10-port.conf
sudo sshd -tSi grep ne trouve aucune ligne Include, comme c’est le cas sur Rocky Linux 8 et d’autres images plus anciennes, ajoutez directement Port 2222 dans /etc/ssh/sshd_config. sshd -t analyse l’ensemble de la configuration, y compris les fichiers drop-in, et signale les erreurs de syntaxe. Corrigez toutes les erreurs signalées avant de redémarrer, car une configuration impossible à analyser empêche le daemon de redémarrer.
Port peut apparaître plusieurs fois, et sshd écoute sur chaque port indiqué. Conserver Port 22 avec Port 2222 pendant le premier jour constitue une précaution simple, à condition de penser à supprimer ensuite l’ancien port.
Votre sshd est-il démarré par une unité socket ?
Certaines images démarrent SSH via l’activation de sockets systemd, et non comme un service qui s’exécute en continu. Dans ce cas, systemd gère le socket en écoute et transmet les connexions à sshd. La ligne Port dans sshd_config est donc totalement ignorée. Vérifiez ce point avant de redémarrer quoi que ce soit :
systemctl is-enabled sshd.socketUne réponse enabled signifie que le port est défini dans l’unité socket, et non dans sshd_config :
sudo systemctl edit sshd.socket[Socket]
ListenStream=
ListenStream=2222La directive ListenStream= sans valeur est nécessaire. Les valeurs s’accumulent dans les drop-ins. Sans affectation vide pour vider d’abord la liste, le socket continue donc d’écouter sur 22 et sur 2222. Appliquez la modification avec sudo systemctl daemon-reload, puis sudo systemctl restart sshd.socket. Si l’unité est désactivée ou absente de votre serveur, cette section ne vous concerne pas.
Étape 4 : redémarrez, puis testez depuis un deuxième terminal
sudo systemctl restart sshd
systemctl status sshd
sudo ss -tlnp | grep sshdGardez ce terminal ouvert. Ne vous déconnectez pas. Ouvrez un deuxième terminal sur votre propre machine et connectez-vous sur le nouveau port :
ssh -p 2222 youruser@203.0.113.10Fermez la première session seulement après la réussite de cette deuxième connexion. Si la connexion échoue, vous disposez encore d’un shell depuis lequel vous pouvez annuler toutes les modifications. Cette habitude fait la différence entre une modification de cinq minutes et un après-midi passé sur la console du fournisseur.
Pare-feu qui bloque ou refus SELinux ? Comment les distinguer
Depuis votre portable, les deux échecs semblent presque identiques. Sur le serveur, ils n’ont rien à voir.
- Si
systemctl status sshdindique que l’unité a échoué, le daemon n’a jamais obtenu son socket. Il s’agit d’une erreur de configuration ou d’un refus SELinux. - Si l’unité est active et que
ss -tlnpindique que sshd écoute sur le nouveau port, le daemon fonctionne. Le problème se situe sur le chemin réseau : firewalld, le pare-feu distinct du fournisseur, ou l’adresse et le port que vous avez utilisés.
Dans le cas de SELinux, consultez l’enregistrement d’audit au lieu de faire des suppositions :
sudo ausearch -m AVC -ts recent
sudo journalctl -u sshd -n 50 --no-pagerUn refus name_bind sur la classe tcp_socket indique le processus dans comm="sshd", le numéro de port dans src= et le label effectivement associé au port dans tcontext=. Ce dernier champ donne la réponse. Toute valeur différente de ssh_port_t signifie que l’étape 2 ne s’appliquait pas au port utilisé, généralement à cause d’une erreur dans le numéro ou de l’utilisation du mauvais protocole. Installez setroubleshoot-server si vous préférez que sealert transforme l’enregistrement en phrase.
Le message qu’écrit sshd lorsque le kernel refuse le bind ressemble à ceci :
error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.Permission denied sur un port supérieur à 1024, sur lequel aucun privilège root n’est nécessaire pour effectuer le bind, caractérise un refus SELinux. Address already in use dans cette même ligne indique un autre problème : un autre processus utilise déjà le port. Depuis le client, la différence entre une connexion refusée et une connexion qui expire permet de distinguer les deux cas réseau : un refus signifie que votre paquet a atteint l’hôte et qu’aucun processus n’écoutait, tandis qu’un timeout signifie que rien n’a répondu.
Fermez le port 22 et mettez à jour vos clients
Une fois que plusieurs connexions au nouveau port ont réussi, retirez le port 22 :
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-allNe modifiez pas le label SELinux du port 22. Il provient de la stratégie de base et n’accorde aucun accès dès lors que le pare-feu ne laisse plus entrer les paquets.
Mettez ensuite à jour les clients, car chaque outil qui supposait le port par défaut doit maintenant recevoir cette information. Ajoutez-la une fois dans ~/.ssh/config sur votre propre machine au lieu de saisir -p à chaque fois :
Host myvps
HostName 203.0.113.10
Port 2222
User youruserscp, sftp, rsync et Ansible lisent tous ce fichier. Les tâches de sauvegarde, les contrôles de supervision et les scripts cron qui codent en dur le port 22 ne le lisent pas. Recherchez-les maintenant, pendant que la modification est encore récente.
Ce que le changement de port apporte ou non
Il réduit le bruit dans les journaux. Les scanners automatisés martèlent constamment le port 22. Le déplacer supprime donc la plupart de ces lignes du journal, ce qui facilite l’identification des événements réels. Ce n’est pas une mesure de sécurité. Un scanner qui balaie toute la plage de ports trouve votre daemon et lit malgré tout sa bannière de version. Considérez le changement de port comme une opération de maintenance. La véritable protection repose sur l’authentification par clé uniquement, avec les connexions par mot de passe désactivées. Le guide de durcissement SSH pour un VPS décrit cette procédure étape par étape.
Tout ce qui précède fonctionne de manière identique sur les deux principales distributions reconstruites à partir de RHEL, car elles sont basées sur les mêmes sources. Consultez la comparaison entre Rocky Linux et AlmaLinux si vous hésitez encore entre les deux. Il existe deux distributions reconstruites presque identiques parce que CentOS a cessé d’en être une en 2020. L’histoire de Red Hat à CentOS, puis à Rocky et AlmaLinux raconte ce changement en détail. Vérifiez la release qui vous a réellement été fournie avant de suivre un guide ancien, avec cat /etc/os-release. Les guides écrits pour Rocky Linux 8 restent bien référencés, et leurs étapes semanage et firewall-cmd restent correctes. Cependant, Rocky 8 ne possède aucune ligne sshd_config.d include ni socket unit à prendre en compte. La partie consacrée à sshd dans ces guides ne correspond donc pas à un système actuel.
fail2ban doit connaître le nouveau port
fail2ban ne se trouve pas dans les dépôts de base. Il provient d’EPEL (extra packages for enterprise Linux) :
sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalldLe sous-paquet fail2ban-firewalld permet à fail2ban d’appliquer ses bannissements via firewalld. C’est ce qu’il faut utiliser sur un serveur où firewalld gère le jeu de règles.
La jail sshd fournie par défaut définit port = ssh. Ce nom est résolu par /etc/services vers le port 22. Après votre modification, la jail surveille un port qui ne reçoit aucune attaque. Elle ne bannit donc personne, tandis que les échecs de connexion s’accumulent sur le port 2222. Définissez le port par son numéro dans /etc/fail2ban/jail.local :
[sshd]
enabled = true
port = 2222
backend = systemd
maxretry = 5
bantime = 3600backend = systemd lit les échecs dans le journal plutôt que dans /var/log/secure. C’est le choix le plus sûr sur une installation minimale, où rsyslog peut être absent. Démarrez-le avec sudo systemctl enable --now fail2ban, puis vérifiez la jail avec sudo fail2ban-client status sshd. La syntaxe de la jail est la même que celle utilisée dans la configuration de fail2ban pour SSH sur Ubuntu 24.04. Seuls la source du paquet et l’action de bannissement diffèrent.
Les correctifs comptent plus que le port
Un serveur dont le port SSH a été modifié, mais qui n’a reçu aucune mise à jour de sécurité depuis quatre mois, est plus vulnérable qu’un serveur qui écoute sur le port 22 et installe des correctifs chaque nuit. Activez les mises à jour automatiques dans la même session, puisque vous êtes déjà connecté en tant que root : mises à jour automatiques avec dnf sur Rocky Linux et AlmaLinux explique la configuration du timer et le choix entre télécharger les mises à jour et les appliquer. L’installation d’une mise à jour ne redémarre pas les daemons qui exécutent encore l’ancien code. Il est donc utile de vérifier quels services nécessitent encore un redémarrage ou un reboot dès que openssh-server ou une bibliothèque dont il dépend est mise à jour.
FAQ
Pourquoi sshd refuse-t-il de démarrer après la modification du port sur Rocky Linux ?
Le label de port SELinux est presque toujours manquant. sshd s’exécute dans le domaine sshd_t, et la policy l’autorise uniquement à écouter sur des ports portant le label ssh_port_t, qui correspond par défaut au seul port 22. Le kernel refuse le bind. Le daemon s’arrête donc au lieu d’écouter, et journalctl -u sshd contient une ligne de la forme error: Bind to port 2222 on 0.0.0.0 failed: Permission denied. Exécutez sudo semanage port -a -t ssh_port_t -p tcp 2222 avec votre propre numéro de port, puis redémarrez le service. Si semanage est introuvable, installez d’abord policycoreutils-python-utils.
Ai-je encore besoin de semanage si SELinux est en mode permissif ?
Oui. En mode permissif, le refus est enregistré et le bind est tout de même autorisé. La modification semble donc fonctionner. Le label est toujours manquant. Dès que quelqu’un exécute setenforce 1, ou que la machine démarre avec SELINUX=enforcing dans /etc/selinux/config, sshd cesse de démarrer sur ce port. Ajouter le label ne demande qu’une commande et supprime une panne qui pourrait sinon apparaître plusieurs semaines plus tard, sans cause évidente.
Le port est labellisé et sshd fonctionne. Pourquoi ma connexion expire-t-elle alors ?
Un daemon en fonctionnement signifie que SELinux autorise l’opération. Le paquet est donc bloqué avant d’atteindre la machine. Vérifiez sudo firewall-cmd --list-ports pour votre port. Vérifiez aussi que vous avez exécuté firewall-cmd --reload après la règle --permanent, car une règle permanente seule n’est jamais appliquée par le firewall en cours d’exécution. Consultez ensuite le panneau de contrôle de votre hébergeur pour vérifier la présence d’un firewall réseau distinct devant le VPS. C’est le second endroit où les connexions sont souvent bloquées. Le système d’exploitation ne peut rien afficher à ce sujet.
Quel port utiliser à la place du port 22 ?
Utilisez n’importe quel port TCP libre compris entre 1024 et 65535. Évitez 2222 et 22222 sur un serveur réel, car les scanners les testent immédiatement après le port 22. Vérifiez que le numéro est libre avec sudo ss -tlnp. Vérifiez que la policy SELinux ne l’a pas déjà réservé avec sudo semanage port -l. Évitez également les ports attribués à un service que vous pourriez installer ultérieurement. Un numéro élevé et difficile à mémoriser convient très bien. Vous l’inscrirez une fois dans ~/.ssh/config et vous n’aurez plus à le saisir.