98: Address already in use high
nginx [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
Another process already holds port 80 or 443, so nginx can't bind its listen socket and refuses to start.
What you see
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] still could not bind()
What’s actually happening
systemctl start nginx fails immediately and the site is down. The log names the exact socket — 0.0.0.0:80 or [::]:443 — that's already taken. Two flavors: either a different web server (Apache/httpd, Caddy, a Node app) owns the port, or a previous nginx didn't shut down cleanly and a stale master is still listening. A reload won't fix it because there's nothing healthy to reload into.
Common causes
- Apache/httpd is installed and running on the same box, already bound to 80/443 (extremely common after a control-panel install).
- A stale nginx master process survived a botched stop or crash and still holds the socket.
- Another service — a Docker container with -p 80:80, a dev server, HAProxy — grabbed the port first.
- Both an IPv4 (0.0.0.0:80) and IPv6 ([::]:80) listen directive where one address is already in use.
- Two nginx server blocks both trying to listen on the same port without one being marked default.
How to fix it
- Find what owns the portRun ss -tlnp 'sport = :80' (or sudo lsof -i :80, or netstat -tlnp | grep :80). It prints the PID and process name holding the socket. This is the whole diagnosis — everything depends on what that process turns out to be.
- If it's a stale nginx master, kill it and restartWhen the holder is nginx itself, the service got confused about its own state. sudo pkill -f 'nginx: master' (or kill the specific PID), confirm with ss -tlnp that :80 is free, then systemctl start nginx. Check ps afterward so you don't have orphaned workers.
- If it's Apache, decide who serves port 80Two web servers can't both own 80. Either stop and disable Apache (systemctl disable --now apache2 / httpd) if nginx is the real server, or — if Apache is your backend — change nginx to a different port and proxy, or bind Apache to 127.0.0.1:8080 and let nginx front it. Don't just stop Apache without disabling it, or it'll grab the port again on reboot.
- For a Docker/other-service conflict, free or remap the portdocker ps shows containers with 0.0.0.0:80->... published. Stop the container or change its host port (-p 8080:80). For non-Docker services, stop whatever ss named. Then start nginx.
- Fix duplicate listen directivesIf ss shows nginx isn't running at all yet but -t still complains about bind on start, you may have two server blocks listening on the same address:port. Mark one listen 80 default_server; and remove the duplicate bare listen.
Stop it recurring
On a fresh server pick one web server up front and systemctl disable the other so it can't reclaim the port after a reboot.
Related errors