Nginx

How to Resolve "nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address Already in Use)"

4 min read by DebuggedIt

Quick answer

Nginx refuses to start or reload, reporting that port 80 (or whatever port it's configured for) is already claimed by something else. This means another...

Nginx refuses to start or reload, reporting that port 80 (or whatever port it's configured for) is already claimed by something else. This means another process β€” possibly a previous Nginx instance that didn't fully stop, possibly a completely different service β€” already has that port bound at the OS level.

The Problem

Starting or restarting Nginx fails immediately, before it can serve any requests:

$ sudo systemctl start nginx
Job for nginx.service failed because the control process exited with error code.
$ sudo nginx -t
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: configuration file /etc/nginx/nginx.conf test failed
Only one process can bind a port port 80 apache2 (already bound) nginx (trying, rejected)

Why It Happens

Only one process can bind a given IP/port combination at a time on Linux. This error appears for a handful of specific, common scenarios:

  • A previous Nginx process is still running β€” a restart command failed partway, or an old process wasn't killed cleanly and is still holding the port even though a newer start attempt is happening.
  • A completely different web server β€” Apache, Caddy, or another service is already installed and running on the same port, especially common right after installing Nginx alongside an existing Apache setup.
  • A Docker container is publishing the same host port, which looks identical to a native process holding it from Nginx's perspective.
  • Multiple Nginx configuration files both declare a listen directive for the same port without proper server_name-based differentiation, though this specific case usually produces a different, more specific Nginx error about duplicate listen directives.

The Fix

Find out exactly what's holding the port before doing anything else:

sudo lsof -i :80
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
apache2  1234  root    4u  IPv6  28123      0t0  TCP *:http (LISTEN)

If it's a stale Nginx process rather than a different service, stop it cleanly first rather than force-killing immediately:

sudo systemctl stop nginx
sudo pkill -f nginx  # only if the above doesn't fully clear it
sudo lsof -i :80     # confirm the port is now free

Then start fresh:

sudo systemctl start nginx

If it's a different service like Apache that's legitimately meant to keep running, you have two real options. Either stop and disable the other service if Nginx is meant to replace it:

sudo systemctl stop apache2
sudo systemctl disable apache2
sudo systemctl start nginx

Or, if both need to coexist on the same machine, put them on different ports and use Nginx as a reverse proxy in front of Apache, which is the standard approach for running multiple web servers side by side:

# Apache listens on 8080 instead of 80
# /etc/apache2/ports.conf
Listen 8080
# Nginx proxies to it on port 80
server {
    listen 80;
    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

Still Not Working?

If lsof shows nothing on the port but Nginx still reports it as in use, the conflict might be coming from inside a Docker container publishing that host port, which doesn't always show up cleanly in lsof depending on your Docker networking mode:

docker ps --filter "publish=80"

If a container is the culprit, stop it or remap its published port before starting Nginx on the host:

docker stop <container_id>

Also double-check you don't have two separate Nginx server blocks both explicitly binding 0.0.0.0:80 in a way that conflicts with itself β€” this is a different, self-inflicted variant of the same error and shows up specifically when running nginx -t against your own configuration, independent of any other process on the system:

grep -rn "listen 80" /etc/nginx/sites-enabled/

It's also worth understanding why this error specifically shows the number 98 rather than something more descriptive β€” that's the raw Linux errno for EADDRINUSE, and Nginx surfaces it directly rather than translating it into friendlier wording. Getting familiar with a handful of these common errno codes in Nginx's startup errors (98 for address in use, 13 for permission denied, 111 for connection refused) makes future error messages much faster to diagnose without needing to search for an explanation every time:

# Quick reference for common nginx bind errors
# 98  - EADDRINUSE  - something else already has the port
# 13  - EACCES      - insufficient permission (e.g. binding <1024 as non-root)
# 99  - EADDRNOTAVAIL - the IP address isn't assigned to any interface

If you're setting up Nginx to run as a non-root user and see errno 13 alongside a port-in-use-looking message, that's actually a separate permissions issue β€” ports below 1024 require elevated privileges on Linux by default, and the fix there is either running Nginx with the appropriate capability granted or binding to a higher port and using a separate mechanism (like a load balancer or iptables redirect) to forward traffic from port 80 down to it.