Troubleshooting NPM EADDRINUSE: Address Already in Use on Ubuntu 20.04 LTS Node.js Applications
Resolve 'EADDRINUSE address already in use' errors when starting Node.js applications on Ubuntu 20.04 LTS. Learn to identify and terminate conflicting processes quickly.
Resolve 'EADDRINUSE address already in use' errors when starting Node.js applications on Ubuntu 20.04 LTS. Learn to identify and terminate conflicting processes quickly.
When deploying or managing Node.js applications on an Ubuntu 20.04 LTS server, encountering the EADDRINUSE error can be a common frustration. This error typically manifests when you attempt to start your Node.js application, and it fails to bind to its designated network port. Your application will not become accessible, and the startup command will terminate with a clear error message in the console or logs.
Symptom & Error Signature
You will typically observe this error in your terminal or application logs when attempting to start a Node.js application, often via npm start, node server.js, or a process manager like PM2.
Here's a common example of the error signature:
> [email protected] start
> node server.js
events.js:292
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (net.js:1316:16)
at listenInCluster (net.js:1364:12)
at Server.listen (net.js:1450:7)
at Object.<anonymous> (/var/www/my-node-app/server.js:25:5)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
at internal/main/run_main_module.js:17:47 {
code: 'EADDRINUSE',
errno: -98,
syscall: 'listen',
address: '::',
port: 3000
}
The key information here is EADDRINUSE: address already in use :::3000, which explicitly states that port 3000 (or whatever port your application is trying to use) is already occupied.
Root Cause Analysis
The EADDRINUSE error occurs when a program attempts to bind to a network address and port that is already in use by another process. For Node.js applications on Ubuntu 20.04 LTS, the common underlying reasons include:
- Stale Process: A previous instance of your Node.js application (or another application) crashed, was not properly shut down, or is still running in the background, holding onto the port.
- Duplicate Application Instances: You or another administrator accidentally started the same Node.js application multiple times, each trying to listen on the same port. This is common in development environments where a process might be left running in a detached terminal.
- Conflicting Application: Another service or application (e.g., another web server, a database, a proxy like Nginx configured incorrectly, or a different Node.js app) is intentionally configured to listen on the same port.
- Improper Process Management: Without a robust process manager like PM2 or Systemd, Node.js applications can sometimes fail to release ports cleanly upon termination, especially if killed abruptly (e.g., via
kill -9).
Step-by-Step Resolution
Follow these steps to diagnose and resolve the EADDRINUSE error.
1. Identify the Occupied Port
First, confirm which port your Node.js application is trying to use. This is usually specified in the error message itself (e.g., :::3000). If not, check your application's source code (e.g., server.js, app.js) where the listen() method is called.
For this guide, let's assume the port in question is 3000.
2. Find the Process Using the Port
You need to identify which process (and its Process ID, or PID) is currently listening on the problematic port. We'll use lsof or netstat/ss.
Using
lsof(LiSt Open Files):lsofis often the most straightforward tool. If not installed, install it:sudo apt update sudo apt install lsof -yThen, run:
sudo lsof -i :3000Replace
3000with your actual port.Example output:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME node 12345 user 18u IPv6 123456 0t0 TCP *:3000 (LISTEN)In this example,
nodeis the command, and12345is the PID.Using
netstat(Network Statistics):netstatis a classic tool, thoughssis its modern replacement.sudo netstat -tulnp | grep :3000Example output:
tcp6 0 0 :::3000 :::* LISTEN 12345/nodeAgain,
12345is the PID andnodeis the process name.Using
ss(Socket Statistics):ssis faster and more efficient for large systems.sudo ss -tulnp | grep :3000Example output:
tcp LISTEN 0 128 [::]:3000 [::]:* users:(("node",pid=12345,fd=18))This output also clearly shows
pid=12345andnode.
If multiple processes are listed, carefully check the
COMMANDorusersfield to identify the correct application. It's usually the one associated withnodeor your application's name.
3. Terminate the Conflicting Process
Once you have identified the PID (e.g., 12345), you can terminate the process.
sudo kill 12345
If the process doesn't terminate immediately, or if it's a stubborn "zombie" process, you might need to use a more forceful kill:
sudo kill -9 12345
Using
kill -9(SIGKILL) should be a last resort. It immediately terminates the process without allowing it to perform any cleanup or graceful shutdown, which can lead to data corruption or other issues if the application is handling critical operations. Always trysudo kill <PID>first.
After killing the process, you can verify that the port is free:
sudo lsof -i :3000
# Or
sudo ss -tulnp | grep :3000
There should be no output for the port if the process was successfully terminated.
4. Restart Your Node.js Application
Now that the port is free, you can restart your Node.js application.
If you typically start it manually:
cd /path/to/your/node/app
npm start
# Or
node server.js
If you're using a process manager like PM2:
pm2 restart my-node-app-name
# Or, if starting for the first time
pm2 start server.js --name my-node-app-name
5. Implement Robust Process Management with Systemd (Recommended for Production)
To prevent EADDRINUSE errors caused by stale processes and ensure your Node.js application starts reliably on server boot, it's highly recommended to use systemd.
Create a Systemd Service File: Create a new service file for your application. Replace
myappwith your application's name, and adjust paths/ports as necessary.sudo nano /etc/systemd/system/myapp.servicePaste the following content, adjusting
User,WorkingDirectory, andExecStart:[Unit] Description=My Node.js Application After=network.target [Service] User=www-data # Or your application user (e.g., ubuntu, deploy) Group=www-data # Or your application group WorkingDirectory=/var/www/my-node-app # Path to your application's root directory ExecStart=/usr/bin/npm start # Or /usr/bin/node /var/www/my-node-app/server.js Restart=always RestartSec=3 StandardOutput=syslog StandardError=syslog SyslogIdentifier=myapp-node Environment=NODE_ENV=production PORT=3000 # Define environment variables [Install] WantedBy=multi-user.targetIf your
npm startscript requiresPATHto findnode, you might need to specify the full path tonodeinExecStart(e.g.,/usr/bin/node server.jsor/home/user/.nvm/versions/node/v18.x.x/bin/node server.js). You can find node's path withwhich node.Reload Systemd, Enable, and Start Your Service:
sudo systemctl daemon-reload # Reload systemd to recognize new service sudo systemctl enable myapp # Enable service to start on boot sudo systemctl start myapp # Start the serviceCheck Service Status:
sudo systemctl status myappYou should see
active (running)if everything is configured correctly.
6. Verify Nginx Configuration (if applicable)
If you're using Nginx as a reverse proxy for your Node.js application, ensure Nginx is proxying to the correct port and is not attempting to bind to the Node.js application's internal port itself. Nginx typically listens on ports 80/443, while Node.js listens on a higher port (e.g., 3000, 8080).
Example Nginx configuration snippet for proxying to Node.js on port 3000:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:3000; # Node.js app is listening here
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
The
proxy_passdirective points to your Node.js application's internal listener. Nginx itself should not be configured to listen on port 3000.
7. Docker Considerations
If your Node.js application is running in a Docker container, the EADDRINUSE error typically means:
- Inside the Container: Another process within that specific container is already using the port your Node.js app tries to bind to. Check the container's logs.
- Host Port Mapping Conflict: You're trying to map a host port to the container, and that host port is already in use by a process on the Docker host machine.
- Example:
docker run -p 3000:3000 my-node-app. If host port3000is busy, this will fail. - To resolve: Find and kill the host process (steps 2 & 3 above) or choose a different host port (e.g.,
docker run -p 3001:3000 my-node-app).
- Example:
By systematically following these steps, you can reliably resolve EADDRINUSE errors and ensure your Node.js applications run smoothly on Ubuntu 20.04 LTS.
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.