If you’re running macOS on an Apple Silicon Mac (M1, M2, M3) with Nginx installed via Homebrew, you might have seen this after a reboot:

nginx: [error] invalid PID number "" in "/opt/homebrew/var/run/nginx.pid"

This happens because Nginx keeps a PID file for its running process. Sometimes, after a reboot, that file is left behind, and Nginx refuses to start or reload.

I hit this enough times that I scripted a fix.

This script is tuned for Nginx installed via Homebrew on Apple Silicon. If you installed Nginx differently (for example, compiled from source or using a different path), you’ll need to modify the script — especially the path to the nginx.pid file.

Script Commands

  • nginxkill – Removes the stale nginx.pid file (/opt/homebrew/var/run/nginx.pid).
  • nginxreload – Reloads Nginx configuration and removes stale PID files if needed, then checks if Nginx is listening on port 80.
  • nginxrestart 🔥 – Stops and restarts Nginx, removes stale PID files if needed, then checks if Nginx is listening on port 80.
  • spinner_wait – For fun, it displays a simple spinner while waiting (used inside nginxrestart). You can replace this with a simple sleep 3 if you like. Nginx needs about 3 seconds to await the restart.

How to Use
Add these functions to your ~/.zshrc, reload your shell, then run nginxrestart whenever Nginx fails to start after a reboot.

# nginx
function nginxkill() { 
    sudo rm /opt/homebrew/var/run/nginx.pid 
}

function nginxreload() {
    echo "Reloading Nginx"
    
    output=$(sudo nginx -s reload 2>&1)
    echo "$output"

    local GREEN="\033[0;32m"
    local NC="\033[0m" # No Color

    # More robust regex match (handles spacing and newlines)
    if [[ "$output" =~ nginx\.pid && "$output" =~ error ]]; then
        echo "PID file error detected. Removing stale nginx.pid..."
        nginxkill
        spinner_wait 3   # Wait 3 seconds for Nginx to fully start
    fi

    # --- Check if Nginx is actually serving traffic on port 80 ---
    if sudo lsof -nP -iTCP:80 -sTCP:LISTEN | grep -q nginx; then
        # Replace spinner with "Done!" in green
        echo "Nginx is online and listening on port 80"
        echo "${GREEN}PID error fixed!${NC}"
    else
        echo "Nginx failed to start or is not bound to port 80 (check logs)"
        echo "Try running 'nginxkill' and then restarting Nginx again."
    fi
}

function nginxrestart() {
    echo "Restarting Nginx"
    
    # Stop and start separately, capturing all output
    stop_output=$(sudo nginx -s stop 2>&1)
    start_output=$(sudo nginx 2>&1)
    output="$stop_output"$'\n'"$start_output"
    local GREEN="\033[0;32m"
    local NC="\033[0m" # No Color

    echo "$output"

    # Use =~ regex match (handles variable spacing and order)
    if [[ "$output" =~ nginx\.pid && "$output" =~ error ]]; then
        echo "PID file error detected. Removing stale nginx.pid..."
        nginxkill
        spinner_wait 3   # Wait 3 seconds for Nginx to fully start
    fi

    # --- Check if Nginx is actually serving traffic on port 80 ---
    if sudo lsof -nP -iTCP:80 -sTCP:LISTEN | grep -q nginx; then
        echo "Nginx is online and listening on port 80"
        echo "${GREEN}PID error fixed!${NC}"
    else
        echo "Nginx failed to start or is not bound to port 80 (check logs)"
        echo "Try running 'nginxkill' and then restarting Nginx again."
    fi
}

# spin for ~3 seconds
# spinner_wait 3 "Optional message"
spinner_wait() {
    local duration=$1
    local message=${2:-"Waiting... "}
    local end=$((SECONDS + duration))
    local chars=( "/" "-" "\\" "|" )
    local i=0
    local GREEN="\033[0;32m"
    local NC="\033[0m" # No Color

    # Print message and leave a space for spinner
    echo -n "$message "

    while (( SECONDS < end )); do
        # \r returns to start of line, then reprint message and spinner
        echo -ne "\r$message ${chars[i]}"
        sleep 0.2
        (( i = (i + 1) % ${#chars[@]} ))
    done

    # Replace spinner with "Done!" in green
    echo -e "\r$message ${GREEN}Done!${NC}"
}

Why This Helps

  • Automatically removes stale nginx.pid files.
  • Confirms Nginx is actually listening on port 80.
  • Makes reboot issues on macOS less annoying.

Put this in your ~/.zshrc and you’re set, and do not forget to reload your ZSH/bash source.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Get Involved & Explore More

an abstract painting with blue and yellow colors

Catch up on what I’ve been writing lately.

Show your gratitude.

Join Dare To Code Email List

Get emails from me on full-stack PHP development by subscribing to the Dare To Code mailing list.