Fix Nginx "bind() to 0.0.0.0:80 failed (98: Address already in use)" Error

beginner Nginx2026-03-21| Linux (Ubuntu, Debian, CentOS), Nginx 1.18+

Error Message

bind() to 0.0.0.0:80 failed (98: Address already in use)
#nginx#port#bind

What's happening

Nginx refuses to start, and the error log (or systemctl status nginx) shows something like this:

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()

Port 80 is already taken. Only one process can hold a port at a time, so Nginx bails out immediately.

The usual suspects:

  • A previous Nginx process crashed or didn't shut down cleanly — it's still holding the port.
  • Apache, Caddy, or another web server grabbed port 80 first.
  • A Node.js, Python, or other app was started directly on port 80.
  • A stale /run/nginx.pid pointing to a dead process caused systemd to spin up a second Nginx instance.

Step 1 — Find what's using port 80

Don't guess. Run one of these commands first.

Using ss (recommended)

sudo ss -tlnp | grep ':80'

Sample output:

LISTEN  0  511  0.0.0.0:80  0.0.0.0:*  users:(("nginx",pid=12345,fd=6))

The last column gives you the process name and PID — that's all you need.

Using lsof

sudo lsof -i :80
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   12345     root    6u  IPv4  98765      0t0  TCP *:http (LISTEN)
nginx   12346 www-data    6u  IPv4  98765      0t0  TCP *:http (LISTEN)

Using fuser

sudo fuser 80/tcp

This prints just the PID(s). Add -v to see the process name alongside it:

sudo fuser -v 80/tcp

Step 2 — Fix based on what you found

Case A: Another Nginx instance is already running

The most common cause. You ended up with two Nginx workers competing for the same port — usually from running sudo nginx directly on a systemd-managed server.

Try the clean approach first:

sudo systemctl stop nginx

systemctl says it's already stopped, but the process is still alive? Kill it by PID:

sudo kill 12345

Still stuck? Force it:

sudo kill -9 12345

Then wipe any stale PID file:

sudo rm -f /run/nginx.pid

Now start Nginx:

sudo systemctl start nginx

Case B: Apache is running on port 80

Apache and Nginx both default to port 80 — they can't share it. Stop Apache first:

sudo systemctl stop apache2      # Debian/Ubuntu
sudo systemctl stop httpd        # CentOS/RHEL

Not planning to use Apache on this server? Disable it so it doesn't come back after a reboot:

sudo systemctl disable apache2

Then start Nginx:

sudo systemctl start nginx

Case C: Another app (Node.js, Python, etc.) is on port 80

Take the PID from Step 1 and check what's actually running:

sudo ps -p 12345 -o comm=

Two ways forward:

  • Stop that app and let Nginx sit in front of it as a reverse proxy — the standard setup for most stacks.
  • Move that app to a different port (e.g. 3000 or 8000) and proxy it through Nginx.

Kill the process directly:

sudo kill 12345

Or stop it through its own service if it has one:

sudo systemctl stop myapp

Step 3 — Prevent it from happening again

Always use systemctl, never raw nginx commands

Running sudo nginx directly bypasses systemd's process tracking. That's exactly how orphan processes end up holding port 80 long after you think Nginx is stopped.

Stick to these four commands:

sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl reload nginx   # graceful config reload, zero downtime
sudo systemctl restart nginx

Keep Nginx enabled so systemd manages it properly

sudo systemctl enable nginx

Want to verify the full service config?

sudo systemctl cat nginx

Check that the [Service] section includes ExecStartPre=/usr/sbin/nginx -t. With this in place, a config syntax error fails fast — before Nginx even tries to bind the port.

Running both Apache and Nginx on the same server

Move Apache to port 8080 and put Nginx in front. In /etc/apache2/ports.conf:

Listen 8080

Then in your Nginx server block:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Step 4 — Verify the fix

Check that Nginx is actually up:

sudo systemctl status nginx

Look for Active: active (running). Then confirm port 80 is now owned by Nginx:

sudo ss -tlnp | grep ':80'
LISTEN  0  511  0.0.0.0:80  0.0.0.0:*  users:(("nginx",pid=9876,fd=6))

One quick HTTP test to seal it:

curl -I http://localhost

HTTP/1.1 200 OK means the port is free and Nginx is serving. You're done.

Quick reference

# 1. Find who owns port 80
sudo ss -tlnp | grep ':80'

# 2. Stop the conflicting process (example: apache)
sudo systemctl stop apache2

# 3. Remove stale PID file if needed
sudo rm -f /run/nginx.pid

# 4. Start Nginx
sudo systemctl start nginx

# 5. Verify
sudo systemctl status nginx
curl -I http://localhost

Related Error Notes