Troubleshooting

Fix Nginx failed to start: address already in use

Nginx will not start when another program already holds port 80 or 443. Find what is using the port with ss, stop or move it, fix duplicate listen lines, then start Nginx.

BeginnerLinux server5 min read

You run systemctl start nginx or restart it after a change, and it fails. The status shows a line like bind to 0.0.0.0:80 failed (98: Address already in use). Only one program can listen on a port at a time, and something else got there first: often Apache, an old Nginx process, or a container. This guide finds the culprit, frees the port and gets Nginx running.

Before you start

  • A Linux VPS with Nginx installed.
  • SSH access with sudo. If SSH works but the website is down, that is fine; this does not affect SSH.

Confirm the error

Bash
sudo systemctl status nginx --no-pager
sudo journalctl -u nginx -n 30 --no-pager

Look for:

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

The address and port tell you which one is taken. A related message, duplicate listen options for 0.0.0.0:80, means a problem in your own config, covered further down.

Find what is using the port

Bash
sudo ss -ltnp '( sport = :80 or sport = :443 )'

-l shows listening sockets, -t TCP, -n numbers instead of names, and -p the process. Example output:

State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0      511          0.0.0.0:80        0.0.0.0:*     users:(("apache2",pid=1123,fd=4),("apache2",pid=1122,fd=4))

The users: part names the program and its process ID. If ss is not available, sudo lsof -i:80 gives the same answer.

Apache is running

The most common case, especially on AlmaLinux or Rocky (httpd) or after installing a package that pulled in Apache.

Ubuntu and Debian:

Bash
sudo systemctl stop apache2
sudo systemctl disable apache2

AlmaLinux and Rocky Linux:

Bash
sudo systemctl stop httpd
sudo systemctl disable httpd

disable stops it starting again at the next reboot.

Warning: If Apache was serving live sites, stopping it takes them offline until Nginx is configured for them. Check ls /etc/apache2/sites-enabled/ or /etc/httpd/conf.d/ first. If you want both, move Apache to another port such as 8080 and proxy to it. See Switch from Apache to Nginx.

An old Nginx process

Sometimes Nginx itself holds the port, for example a copy started by hand with sudo nginx instead of systemd. ss shows nginx as the process, but systemd thinks it is stopped.

Stop it cleanly, then start it through systemd:

Bash
sudo nginx -s quit
sudo systemctl start nginx

If nginx -s quit fails because the PID file is missing, stop the stray master process by its PID from the ss output:

Bash
sudo kill 1234

Replace 1234 with the real PID. Wait a few seconds and check ss again before starting Nginx.

Other programs

  • Docker containers publishing 80:80 or 443:443: list them with docker ps --format '{{.Names}} {{.Ports}}', then stop the container or change its published port.
  • Caddy, Traefik, Lighttpd, a control panel's web server: stop and disable the service if Nginx should own the ports.
  • A Node.js or Python app run as root on port 80: move it to a high port such as 3000 and put Nginx in front. See Set up Nginx as a reverse proxy.
  • Certbot standalone: a renewal using --standalone briefly binds port 80. Wait a minute and try again, or switch renewals to the --nginx or webroot method.

Duplicate listen lines

If no other program holds the port, the clash may be inside your own config. Messages such as duplicate listen options for [::]:443 or a duplicate default server for 0.0.0.0:80 point there.

List every listen line with its file:

Bash
sudo nginx -T 2>/dev/null | grep -nE "# configuration file|listen"

Rules to follow:

  • Only one server block per port may have default_server.
  • Options such as ipv6only=on, reuseport or backlog= may only appear on one listen line per address and port.
  • On Ubuntu/Debian, a site linked twice into sites-enabled under two names loads twice. Check with ls -l /etc/nginx/sites-enabled/.

Start Nginx

Once the port is free and the config is clean:

Bash
sudo nginx -t
sudo systemctl start nginx
sudo systemctl enable nginx

Check it works

Bash
systemctl is-active nginx
sudo ss -ltnp '( sport = :80 or sport = :443 )'

The first command should print active, and ss should now show nginx on the ports. Then load your site:

Bash
curl -I http://example.com/

Reboot later at a quiet time to confirm the right service starts on its own and the other one stays off.

Troubleshooting

  • Port is free but Nginx still fails: read the full journalctl -u nginx output. A different [emerg] line, such as a missing certificate file, may be the real error.
  • The other service comes back after a reboot: you stopped but did not disable it. Run systemctl disable for it.
  • bind to [::]:80 failed only: two server blocks bind IPv6 with conflicting ipv6only options. Keep the default and remove the extra option.
  • Permission denied binding a custom port on AlmaLinux or Rocky: SELinux only allows web ports it knows. See Fix Nginx permission denied caused by SELinux.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.