One of the most frequent errors encountered when launching a web server (Nginx/Apache), a Node.js API, or a Docker container is:
bind: address already in use or Error: listen EADDRINUSE: address already in use :::3000.
This happens when another running process is already bound to that network port. In this guide, you will learn how to find the exact application holding the port and resolve the conflict.
1. Finding the Application Using lsof
The lsof command is the cleanest and most direct tool for inspecting port bindings.
Search by Port Number
sudo lsof -i :80
(Replace 80 with whatever port you are checking, e.g., 3000, 8080, 25565).
Example Output:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 1420 root 6u IPv4 23984 0t0 TCP *:80 (LISTEN)
nginx 1421 www-data 6u IPv4 23984 0t0 TCP *:80 (LISTEN)
In this example:
- COMMAND:
nginx - PID:
1420 - USER:
root
2. Finding the Application Using ss
If lsof is not installed on your server:
sudo ss -lptn 'sport = :80'
Or use a general grep filter:
sudo ss -tulpn | grep ':80 '
3. Finding and Killing Instantly with fuser
The fuser tool can identify and even terminate the process occupying a specific TCP/UDP port in one command.
Check Process on Port:
sudo fuser 80/tcp
Output:
80/tcp: 1420 1421
Kill the Process Occupying the Port:
sudo fuser -k 80/tcp
[!WARNING] Using
fuser -kimmediately sends a kill signal to all processes attached to that port. Use with caution on production servers!
4. How to Handle the Conflicting Service
Once you have identified the PID and application name:
Case 1: An Abandoned or Zombie Background Script
If it is a test script or node process that was left running:
kill -15 <PID>
Case 2: A Managed Systemd Service (e.g., Apache vs Nginx)
If Apache is occupying port 80 and preventing Nginx from starting:
sudo systemctl stop apache2
sudo systemctl disable apache2
sudo systemctl start nginx
Case 3: A Docker Container
If the port is held by docker-proxy:
docker ps --filter "publish=80"
docker stop <container_id>
Common Mistakes
- Running port commands without
sudo: Without administrative privileges,ssandlsofwill hide process names and PIDs belonging to other system users. - Killing the wrong service: Always verify the
COMMANDandUSERbefore issuingkillorfuser -k.
Troubleshooting
- Port appears closed in
ss, but app still throwsEADDRINUSE: Check if the application is trying to bind to an IPv6 address (:::80) where an IPv6 listener is active, or check if the socket is stuck inTIME_WAITstate (ss -tan | grep TIME-WAIT). - Cannot kill process (PID not dying): Check if the process is managed by
systemdorpm2with automatic restart policies. If so, stop the supervisor directly (sudo systemctl stop <service>orpm2 stop <app>).
Best Practices
- Standardize port allocations across your development and production environments.
- Use reverse proxies like Nginx or Traefik on ports 80/443 so multiple backend applications can run on internal ports (e.g., 3000, 3001, 8080) behind domain names.
Frequently Asked Questions
Why does ss -tulpn not show process names when run as a standard user?
Linux security policy forbids unprivileged users from viewing file descriptors and socket handles owned by other users or the root account.
How do I check UDP ports specifically?
Use sudo ss -ulpn 'sport = :53' or sudo lsof -i udp:53.
Conclusion
Resolving port conflicts is quick and simple once you know how to leverage lsof and ss. Use these tools to keep your RivinCloud VPS services organized and running smoothly!
