EQVPS
Tableau de bordCommencer

Vérifier les ports ouverts d'un VPS : ce qui écoute, ce qu'Internet voit et la surprise Docker

Voyez chaque port sur lequel votre serveur écoute, trouvez le processus derrière, scannez le serveur depuis l'extérieur comme le ferait un attaquant et fermez ce qui ne sert pas. Avec le port Docker qui reste ouvert même pare-feu activé. Chaque chiffre mesuré sur un serveur Ubuntu 24.04 neuf.

Un port ouvert et oublié est la porte d'entrée classique d'un serveur : une base de données sur une adresse publique, un tableau de bord de débogage, un conteneur qui a publié un port que personne ne voulait publier. La vérification prend une minute quand on connaît deux commandes et un piège. Nous avons tout fait ci-dessous sur un serveur Ubuntu 24.04 neuf issu de notre image, puis nous l'avons scanné depuis une seconde machine : les sorties sont celles que vous verrez sur votre propre serveur.

1. Ce qui écoute

La commande est ss. Les lettres signifient TCP, UDP, sockets en écoute, ports numériques et nom du processus :

sudo ss -tulpn

Sur un serveur neuf, elle affiche six lignes :

Netid State  Local Address:Port  Process
udp   UNCONN    127.0.0.54:53    systemd-resolve
udp   UNCONN 127.0.0.53%lo:53    systemd-resolve
tcp   LISTEN    127.0.0.54:53    systemd-resolve
tcp   LISTEN 127.0.0.53%lo:53    systemd-resolve
tcp   LISTEN       0.0.0.0:22    sshd
tcp   LISTEN          [::]:22    sshd

La colonne qui compte est Local Address. Elle dit qui peut se connecter :

AdresseQui peut la joindre
127.0.0.1:… ou 127.0.0.53Seulement les programmes de ce serveur
0.0.0.0:…Tout le monde en IPv4, sauf blocage par le pare-feu
[::]:…Tout le monde en IPv6 (et en général IPv4 aussi)
10.0.0.5:… (une adresse précise)Quiconque peut joindre cette adresse

Le serveur neuf n'expose donc qu'une chose : SSH sur le port 22, en IPv4 et en IPv6. Le résolveur DNS sur 127.0.0.53 est privé.

Pour ne lister que ce qu'Internet pourrait voir, filtrez les adresses de bouclage :

sudo ss -tlnp | awk 'NR>1 && $4 !~ /^(127\.|\[::1\])/ {print $4, $6}'

Lancez-la après chaque installation. Nous avons installé nginx, Docker et une petite application Python, et la liste est passée de 2 à 10 lignes, dont un docker-proxy sur 0.0.0.0:8081 et un socket containerd sur un port localhost aléatoire.

2. Quel processus occupe un port

Quand un port est pris et que vous voulez savoir par qui :

sudo lsof -i :80 -P -n
sudo fuser 80/tcp
sudo ss -tlnp 'sport = :80'

lsof est le plus lisible. Pour nginx, il a listé un processus maître en root et un worker en www-data, tous deux sur *:80, en IPv4 et IPv6. fuser n'affiche que les PID, pratique dans les scripts. S'il faut libérer le port, arrêtez le service au lieu de tuer le PID, sinon systemd le relance : sudo systemctl stop nginx.

3. Ce qu'Internet voit

ss donne le point de vue du serveur. Celui d'Internet peut différer, parce qu'un pare-feu s'intercale ou qu'un service est lié à 127.0.0.1. Pour voir la réalité, scannez le serveur depuis une autre machine, votre portable ou un second serveur. L'outil est nmap (apt install nmap, ou l'installateur de nmap.org sous Windows et macOS).

nmap your-server-ip
nmap -p- your-server-ip
nmap -p 22,80,443,3306 your-server-ip

La première forme teste les 1 000 ports les plus courants, la deuxième les 65 535, la troisième une liste. Sur notre serveur neuf, avant tout pare-feu :

Not shown: 999 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
Nmap done: 1 IP address (1 host up) scanned in 6.83 seconds

Le scan complet des 65 535 ports a pris 8,9 secondes et a trouvé le même port unique. Les ports fermés répondent instantanément par un reset, d'où la rapidité.

Trois états comptent :

  • open : un programme a accepté la connexion. C'est votre surface d'attaque.
  • closed : le serveur a répondu que rien n'écoute là. Sans danger, mais cela confirme que le serveur existe et ce qu'il ne fait pas tourner.
  • filtered : pas de réponse. Un pare-feu a jeté le paquet. Le scanner ne peut pas savoir si un service se cache derrière.

Pour un seul port sans rien installer, nc -zv ip-du-serveur 443 répond succeeded ou refused, et reste bloqué jusqu'au délai d'attente sur un port filtré. Pour l'UDP, ajoutez -sU à nmap et attendez-vous à de la lenteur ; sur notre serveur, les trois ports UDP courants, 53, 123 et 161, étaient closed.

Une remarque pour les offres NAT : depuis Internet, seul le port SSH que nous vous avons redirigé est joignable. Un scan de l'adresse partagée montre notre bordure, pas votre serveur, et les autres ports sont injoignables, quoi qu'il y écoute. Avec une offre dotée de sa propre adresse IPv4, chaque port ouvert est à vous de gérer.

4. Fermer ce qui ne sert pas

Trois méthodes, de la meilleure à la plus large.

Lier à localhost. Si seuls des programmes du serveur utilisent un service, faites-le écouter sur 127.0.0.1. Nous avons lancé une petite application web avec --bind 127.0.0.1 8080 : ss l'a montrée sur 127.0.0.1:8080, et nmap depuis l'extérieur a indiqué 8080/tcp closed. Pour les bases de données, c'est le bon réglage par défaut : Redis, MySQL et PostgreSQL écoutent sur localhost dès l'installation sous Ubuntu, et nos guides Redis et MySQL le laissent ainsi.

Arrêter le service. sudo systemctl disable --now nom supprime l'écoute pour de bon. Vérifiez avec ss qu'elle a disparu.

Activer le pare-feu. Autorisez d'abord SSH, puis ce que vous servez, puis activez :

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw enable
sudo ufw status verbose

Le scan depuis l'extérieur a complètement changé :

Not shown: 997 filtered tcp ports (no-response)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
8081/tcp open  blackice-icecap
Nmap done: 1 IP address (1 host up) scanned in 10.18 seconds

Chaque port non autorisé est passé de closed à filtered, et le scan complet des 65 535 ports a pris 110 secondes au lieu de 8,9. Plus de temps par port pour le scanner, moins d'informations sur votre serveur. Notre guide UFW couvre la limitation de débit, l'autorisation d'une seule IP et l'IPv6.

Mais regardez la troisième ligne.

5. La surprise Docker

Le port 8081 est resté ouvert, pare-feu actif et sans règle l'autorisant. Ce port appartient à un conteneur lancé avec docker run -p 8081:80 nginx:alpine. Docker ajoute ses propres règles au pare-feu du noyau, et elles sont évaluées avant celles d'ufw. La règle qu'il a écrite sur notre serveur :

-A DOCKER ! -i docker0 -p tcp --dport 8081 -j DNAT --to-destination 172.17.0.2:80

Tout paquet destiné au port 8081 est redirigé dans le conteneur avant qu'ufw n'ait son mot à dire. C'est le cas de chaque conteneur avec -p ou une entrée ports:, et ss l'affiche honnêtement comme docker-proxy sur 0.0.0.0:8081.

La correction consiste à publier sur localhost uniquement :

docker rm -f web
docker run -d --name web -p 127.0.0.1:8081:80 nginx:alpine

Dans Compose, écrivez "127.0.0.1:8081:80" sous ports:. Après la modification, ss a montré 127.0.0.1:8081, la règle Docker a gagné -d 127.0.0.1/32, et le scan depuis l'extérieur a indiqué 8081/tcp filtered. Placez nginx en reverse proxy devant pour le côté public, avec HTTPS, afin que les seuls ports ouverts du serveur soient 22, 80 et 443.

Check-list après chaque changement

  1. sudo ss -tulpn : chaque ligne 0.0.0.0 ou [::] est-elle voulue ?
  2. nmap ip-du-serveur depuis votre portable : les ports ouverts correspondent-ils ?
  3. Une base de données, un cache ou un panneau d'administration sur une adresse publique : passez-le sur 127.0.0.1 ou derrière le pare-feu aujourd'hui.
  4. Chaque entrée Docker ports: : commence-t-elle par 127.0.0.1: si ce n'est pas le port web public ?
  5. SSH ouvert à tous : ajoutez fail2ban ou la connexion par clé uniquement.

Sous Windows Server, la même vérification est Get-NetTCPConnection -State Listen, et les règles vivent dans le pare-feu Windows. Chaque offre Linux, dès le Nano à $3, existe en version avec sa propre adresse IPv4, et là, ce que vous voyez dans ss est ce que le monde voit, moins votre pare-feu.

FAQ

Quels ports sont ouverts sur un VPS neuf ?

Sur notre image Ubuntu 24.04, un seul : SSH sur le port 22. Les seuls autres services à l'écoute sont le résolveur DNS local sur 127.0.0.53 et 127.0.0.54, inaccessible depuis Internet. Un scan des 65 535 ports TCP depuis une autre machine a trouvé exactement un port ouvert.

Quelle différence entre un port closed et filtered ?

Closed signifie que le serveur a répondu que rien n'écoute là, le scanner le sait donc tout de suite. Filtered signifie aucune réponse, c'est ce que fait un pare-feu qui jette les paquets. Les deux bloquent les intrus, mais filtered cache aussi quels services existent et rend un scan complet environ douze fois plus lent sur notre serveur.

Pourquoi ss affiche un port que nmap dit closed ?

Le service n'écoute que sur 127.0.0.1, l'adresse de bouclage. Les programmes du serveur lui-même peuvent s'y connecter, personne de l'extérieur. Dans ss, regardez la colonne Local Address : 127.0.0.1:8080 est privé, 0.0.0.0:8080 ou [::]:8080 est joignable depuis Internet si le pare-feu le permet.

J'ai activé ufw, pourquoi mon port Docker est-il encore ouvert ?

Docker écrit ses propres règles de pare-feu, évaluées avant celles d'ufw. Un conteneur lancé avec -p 8081:80 était joignable depuis l'extérieur sur notre serveur, ufw actif et sans règle pour 8081. Publiez plutôt sur localhost, -p 127.0.0.1:8081:80, et placez nginx ou Caddy devant pour le côté public.

Comment vérifier un port depuis mon ordinateur ?

Lancez nc -zv ip-du-serveur 443 pour un port, ou installez nmap et lancez nmap ip-du-serveur pour les mille ports les plus courants. Sur une offre NAT, seul votre port SSH redirigé répond depuis Internet ; tout le reste est injoignable par conception.

Commentaires

Pas encore de commentaires. Soyez le premier.

Laisser un commentaire

Les commentaires sont modérés avant leur publication.