- EADDRINUSE signifie que le port est exclusivement occupé par un autre process : c'est le comportement normal du noyau Linux.
- sudo lsof -i :PORT identifie le PID et l'utilisateur du process qui occupe le port.
- Deux installations du même outil (root + utilisateur normal) créent deux services systemd en conflit sur le même port.
- kill PID (SIGTERM) en premier, puis kill -9 PID si le process ne répond pas.
- Corriger le fichier systemd et relancer daemon-reload pour éviter la récidive au prochain démarrage du serveur.
Lecture complète : 5 min
TL;DR : EADDRINUSE signifie qu’un autre process utilise déjà le port que ton service essaie d’occuper. Pour le corriger : lsof -i :PORT pour identifier le process coupable, kill -9 PID pour le tuer, et une vérification de ton fichier de service systemd pour éviter que ça se reproduise au prochain démarrage. Si tu as deux installations du même outil (une en root, une en utilisateur normal), c’est probablement là que vient le conflit.
Tu lances ton service, tu regardes les logs, et tu tombes sur ça :
Error: listen EADDRINUSE: address already in use :::18789
at Server.setupListenHandle [as _listen2] (node:net:1432:16)
at listenInCluster (node:net:1480:12)
Le service plante. Tu le relances. Il plante à nouveau. Tu cherches sur Google, tu trouves des fils Stack Overflow en anglais qui te disent de “kill the process” sans expliquer lequel ni pourquoi ça arrive.
Ce guide répond aux deux questions : ce que signifie EADDRINUSE concrètement, et comment le corriger de manière définitive sur un VPS Ubuntu.
Ce que signifie EADDRINUSE concrètement
EADDRINUSE est un code d’erreur système Linux. Il signifie littéralement “address already in use” : l’adresse réseau (ici, la combinaison IP + port) que ton process essaie d’occuper est déjà prise par un autre process.
Quand Node.js démarre un serveur sur un port donné, le système d’exploitation lui attribue l’exclusivité de ce port. Aucun autre process ne peut écouter sur le même port en même temps. Si tu essaies de démarrer un deuxième process sur ce même port, le système refuse et renvoie EADDRINUSE.
Ce n’est pas un bug Node.js. C’est le comportement normal du noyau Linux. Node.js se contente de propager l’erreur.
Les deux causes principales sur un VPS Ubuntu
Deux instances du même service en cours d’exécution
La cause la plus fréquente : le service tourne déjà quelque part, et tu essaies d’en lancer une deuxième instance sur le même port.
Ça arrive plus souvent qu’on ne le pense sur un VPS. Tu as peut-être lancé le service à la main en SSH, oublié de le couper, et systemd essaie de le relancer automatiquement. Ou tu as deux fichiers de service systemd qui pointent vers le même outil.
Dans mon cas, décrit dans l’article sur la configuration de mon VPS pour automatiser la création de contenu, j’avais installé OpenClaw deux fois : une fois en root lors d’un premier essai, une fois depuis mon utilisateur normal. Deux installations, deux fichiers de configuration différents, deux services qui tentaient d’écouter sur le port 18789 au démarrage.
Un service systemd qui pointe vers un chemin obsolète
Deuxième cause classique : tu as réinstallé ou déplacé un outil, mais le fichier de service systemd pointe encore vers l’ancienne installation. systemd démarre le vieux binaire, qui occupe le port. Quand le nouveau service essaie de démarrer à son tour, le port est déjà pris.
C’est plus difficile à diagnostiquer parce que les deux processus semblent identiques dans les logs.
Identifier quel process occupe le port
Avant de tuer quoi que ce soit, il faut savoir ce qu’on tue.
Avec lsof
lsof (list open files) est l’outil le plus lisible pour ce diagnostic. Il liste les fichiers et ports ouverts par chaque process.
sudo lsof -i :18789
Remplace 18789 par ton numéro de port. La sortie ressemble à ça :
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 3847 root 23u IPv6 42891 0t0 TCP *:18789 (LISTEN)
node 4102 samwane 23u IPv6 43012 0t0 TCP *:18789 (LISTEN)
Ici, deux process Node.js écoutent sur le même port : un en root (PID 3847) et un sous l’utilisateur samwane (PID 4102). C’est exactement le cas de double installation décrit plus haut.
La colonne PID donne l’identifiant du process à éliminer. La colonne USER dit sous quel utilisateur il tourne, ce qui aide à comprendre d’où il vient.
Avec ss ou netstat
Si lsof n’est pas installé sur ta machine, ss est disponible par défaut sur Ubuntu :
sudo ss -tlnp | grep 18789
La sortie est moins lisible mais contient les mêmes informations :
LISTEN 0 511 *:18789 *:* users:(("node",pid=3847,fd=23))
netstat fonctionne de la même façon mais est progressivement abandonné au profit de ss :
sudo netstat -tlnp | grep 18789
Tuer le process et libérer le port
Une fois le PID identifié, deux options selon l’urgence.
Arrêt propre (à préférer) :
sudo kill PID
Le signal SIGTERM par défaut laisse au process le temps de se fermer proprement, de vider ses buffers et de libérer ses ressources. C’est ce qu’il faut utiliser en premier.
Arrêt forcé si le process ne répond pas :
sudo kill -9 PID
Le signal SIGKILL coupe le process immédiatement sans lui laisser le temps de faire quoi que ce soit. À utiliser uniquement si kill sans option ne répond pas après quelques secondes.
Pour tuer les deux process de l’exemple précédent :
sudo kill -9 3847
sudo kill -9 4102
Vérifie ensuite que le port est libre :
sudo lsof -i :18789
Si la commande ne renvoie rien, le port est libéré.
Corriger le fichier de service systemd pour éviter la récidive
Tuer le process résout le problème immédiatement. Mais si la cause racine n’est pas traitée, l’erreur reviendra au prochain démarrage du VPS.
Le fichier de service systemd se trouve généralement dans /etc/systemd/system/. Pour lister les services actifs liés à ton outil :
sudo systemctl list-units --type=service | grep nom-du-service
Pour voir le contenu du fichier de service et vérifier vers quel chemin pointe ExecStart :
sudo systemctl cat nom-du-service
La sortie ressemble à ça :
[Unit]
Description=Mon service Node.js
After=network.target
[Service]
User=root
WorkingDirectory=/root/.openclaw
ExecStart=/root/.nvm/versions/node/v20.0.0/bin/node server.js
Restart=always
[Install]
WantedBy=multi-user.target
Si User=root alors que tu as réinstallé l’outil depuis ton utilisateur normal, c’est là que vient le conflit. Le service systemd démarre le vieux binaire en root pendant que ton installation utilisateur tente de démarrer de son côté.
Correction : édite le fichier de service pour pointer vers le bon chemin et le bon utilisateur.
sudo nano /etc/systemd/system/nom-du-service.service
Après modification, recharge la configuration systemd et redémarre le service :
sudo systemctl daemon-reload
sudo systemctl restart nom-du-service
sudo systemctl status nom-du-service
Mon cas concret : double installation OpenClaw root/utilisateur
Voici la séquence exacte de ce qui s’est passé dans mon cas, documentée dans l’article sur la configuration de mon VPS.
-
Première installation en root lors d’un premier test rapide :
sudo npm install -g openclaw -
Quelques jours plus tard, réinstallation “propre” depuis mon utilisateur normal sans avoir supprimé la première :
npm install -g openclaw
Deux binaires, deux dossiers de configuration, deux services systemd dont l’un pointait encore vers /root/.openclaw. Au démarrage du VPS, les deux tentaient d’écouter sur le port 18789.
La correction complète passait par un nettoyage des deux installations avant de repartir proprement :
sudo npm uninstall -g openclaw
rm -rf ~/.openclaw
sudo rm -rf /root/.openclaw
Puis réinstallation unique depuis l’utilisateur normal, et correction du fichier de service systemd pour pointer vers le bon chemin. Plus d’EADDRINUSE depuis.
La leçon retenue : sur un VPS, toujours vérifier qu’une installation précédente n’existe pas avant d’en créer une nouvelle, notamment en distinguant les installations root des installations utilisateur. La commande which nom-outil et sudo which nom-outil permettent de vérifier les deux en dix secondes.
Pour aller plus loin
Ces deux articles du blog traitent directement du contexte dans lequel j’ai rencontré cette erreur et de la stack autour :
- Configurer un VPS pour automatiser sa création de contenu : le récit complet du debug, dont cette erreur EADDRINUSE et le conflit de double installation.
- Automatiser la promotion de son SaaS depuis un VPS : la stack Python/Gemini/Notion qui tourne sur ce même VPS une fois les conflits résolus.
Discussion