Nginx “Address already in use” Error on Port 80: Diagnosis and Solutions for macOS Developers


16 views

The error message bind() to 0.0.0.0:80 failed (48: Address already in use) indicates that Nginx cannot bind to port 80 because another process has already claimed it. This commonly occurs when:

  • Another web server (Apache, httpd) is running
  • Previous Nginx instances weren't properly terminated
  • MacOS system services are using the port

Use these terminal commands to identify the offending process:

sudo lsof -i :80
sudo lsof -iTCP:80 -sTCP:LISTEN

Sample output might reveal:

COMMAND  PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
httpd   1234 root    4u  IPv6 0xffff800123456789      0t0  TCP *:http (LISTEN)

MacOS has several native services that might interfere:

# Check for Apple-specific services
sudo launchctl list | grep -i apache
sudo launchctl list | grep -i http

First try gracefully stopping the service:

sudo apachectl stop       # For Apache
sudo nginx -s stop        # For Nginx

If that fails, terminate the process forcefully:

sudo kill -9 [PID]        # Replace [PID] with actual process ID
sudo killall httpd        # Alternative approach

Modify Nginx configuration to avoid conflicts:

# /usr/local/etc/nginx/nginx.conf
server {
    listen 80 reuseport;  # Added reuseprot option
    # ... rest of config
}

For development environments, consider using higher ports:

server {
    listen 8080;          # Alternative port
    server_name localhost;
    # ... rest of config
}

Create a bash script to handle port conflicts:

#!/bin/bash
PORT=80
PID=$(lsof -ti :$PORT)
if [ ! -z "$PID" ]; then
    echo "Killing process $PID using port $PORT"
    kill -9 $PID
fi
nginx

Use these diagnostic commands:

sudo nginx -t               # Test configuration
sudo nginx -T               # Show full configuration
sudo nginx -s reload        # Reload configuration
journalctl -u nginx -f      # View logs (systemd systems)

When Nginx fails to bind to port 80, it's typically because another process has already claimed that privileged port. On macOS, this could be caused by:

  • Apache running in the background
  • Other web servers like Microsoft IIS
  • Docker containers using port 80
  • macOS built-in services

First, let's definitively check what's using port 80:

sudo lsof -i :80
sudo netstat -anp tcp | grep LISTEN

For more detailed process information:

sudo lsof -i :80 -sTCP:LISTEN -nP

If the offender is Apache (common in macOS):

sudo apachectl stop
sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist

For lingering Nginx processes:

sudo pkill -f nginx
sudo nginx -s stop

If you can't free port 80, consider running Nginx on a different port temporarily:

# In nginx.conf
server {
    listen 8080;
    server_name localhost;
    ...
}

For production setups, create a proper launchd plist to prevent conflicts:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>nginx</string>
    <key>ProgramArguments</key>
    <array>
      <string>/opt/local/sbin/nginx</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>

Save to /Library/LaunchDaemons/nginx.plist and load with:

sudo launchctl load -w /Library/LaunchDaemons/nginx.plist

After making changes, verify Nginx is running properly:

sudo nginx -t
sudo nginx
ps aux | grep nginx
curl -I http://localhost