You start your app and it dies straight away:

Error: listen EADDRINUSE: address already in use :::3000 bind() to 0.0.0.0:80 failed (98: Address already in use) Bind for 0.0.0.0:8080 failed: port is already allocated 

Three tools, three wordings, one meaning: something else is already listening on that port. Here's how to find out what in about a minute, and how to fix it without breaking anything else.

Step 1: find who owns the port

Ask the kernel. On any modern Linux server:

sudo ss -ltnp 'sport = :3000' 

You'll get a line like:

LISTEN 0 511 *:3000 *:* users:(("node",pid=48213,fd=21)) 

That's the process name and its PID. Two alternatives if you prefer them:

sudo lsof -i :3000 sudo fuser 3000/tcp 

Use sudo. Without it you often can't see processes owned by other users, and the output is empty, which makes it look like nothing is using the port.

Now match what you found to one of the cases below.

Case 1: an old copy of your own app

The most common one. A previous npm start, a nodemon you forgot in another terminal, a screen or tmux session, or a crashed run that left a child process behind.

Stop it gently first, then harder only if you must:

kill 48213 # asks the process to exit cleanly kill -9 48213 # only if it ignores the first one 

If the app is managed by something, stop it there instead, or it will just come back:

pm2 list && pm2 stop myapp sudo systemctl stop myapp 

Case 2: another web server on 80 or 443

You install Nginx and it fails on port 80 because Apache is already there (or the other way round). Some server images ship with one preinstalled.

sudo ss -ltnp 'sport = :80' sudo systemctl disable --now apache2 sudo systemctl restart nginx 

Use disable --now, not just stop, or it comes back on the next reboot.

Case 3: a Docker container

If ss shows docker-proxy, a container has published that port. Find it:

docker ps --filter publish=8080 

Then stop that container, or docker compose down in its project folder. If two Compose projects both publish 8080:80, change one of them to another host port, like 8081:80.

Case 4: systemd is holding the socket

Some services use socket activation: systemd listens on the port and only starts the service when a connection arrives. Stopping the service isn't enough, because the socket unit still owns the port.

systemctl list-sockets sudo systemctl stop myapp.socket 

On Ubuntu 24.04, SSH works this way (ssh.socket), which is why changing the SSH port needs a socket reload, not just a service restart.

Case 5: it's your own app, restarting too fast

If your server exits and immediately restarts on the same port, a custom server can fail for up to a minute while the old connections finish closing. Most frameworks set the SO_REUSEADDR socket option for you, which avoids this. If you wrote your own socket server, set it yourself before you bind:

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

Not the same error: "permission denied"

Error: listen EACCES: permission denied 0.0.0.0:80 

That's a different problem. Ports below 1024 need root or a capability. Don't run your app as root to fix it. Run it on a high port like 3000 and put Nginx or Caddy in front on 80 and 443, which is the setup you want in production anyway.

Or just use another port

Sometimes the simplest fix is right: make the port configurable and pick a free one.

PORT=3001 npm start 

Then point your reverse proxy at the new port, and you're done.

Checklist

  1. sudo ss -ltnp 'sport = :PORT' to find the process and PID
  2. Old copy of your app? kill PID, or stop it in pm2 or systemd
  3. Apache vs Nginx? systemctl disable --now the one you don't use
  4. docker-proxy? docker ps --filter publish=PORT
  5. Still busy after stopping the service? systemctl list-sockets
  6. EACCES is a different error: use a high port and a reverse proxy
  7. Make the port configurable with PORT=

More fixes

We publish fixes like this every week on the VeloxaHost blog. Running a Node app? See Node.js hosting on VeloxaHost.

Disclosure: we run VeloxaHost, a web hosting and VPS provider. Everything above works on any Linux server.