BlogWeb Servers

How to Fix HTTP 503 Service Unavailable (Nginx & Apache)

Web Servers·10 min read·By the TorixPulse Team

A 503 Service Unavailable is one of the most misunderstood HTTP errors. Unlike a 500 (your application threw an error) or a 404 (the resource doesn't exist), a 503 usually means the web server is running fine but cannot hand the request to the thing that's supposed to handle it — the app server is down, overloaded, restarting, or the site is in maintenance mode.

This guide walks through the real causes and how to fix them on the two most common stacks: Nginx (as a reverse proxy to PHP-FPM or an app server) and Apache.

What a 503 actually means

The server received your request and decided it can't fulfil it temporarily. The most common triggers are:

  • The upstream application (PHP-FPM, Node, Gunicorn, etc.) is down or crashed.
  • The upstream is overloaded — every worker is busy, so new requests are rejected.
  • A maintenance mode or rate-limit rule is deliberately returning 503.
  • A reverse proxy can't reach the backend (wrong socket/port, backend restarting).

Step 1: Read the logs first

Never guess. The error log tells you exactly what failed.

bash
# Nginx
sudo tail -n 100 /var/log/nginx/error.log

# Apache (Debian/Ubuntu)
sudo tail -n 100 /var/log/apache2/error.log

# PHP-FPM
sudo tail -n 100 /var/log/php8.2-fpm.log

An entry like connect() to unix:/run/php/php8.2-fpm.sock failed (2: No such file or directory) tells you PHP-FPM isn't running or the socket path is wrong.

Step 2: Check the backend is actually running

bash
sudo systemctl status php8.2-fpm
sudo systemctl status your-app   # node, gunicorn, etc.

# If it's dead, start it and check why it died
sudo systemctl restart php8.2-fpm
sudo journalctl -u php8.2-fpm --since "10 min ago"

Step 3: Fix the Nginx → PHP-FPM connection

A very common 503/502 cause is a mismatch between the socket Nginx points at and the one PHP-FPM listens on. Confirm they match.

nginx
# /etc/nginx/sites-available/example.conf
location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;   # must match FPM pool
    fastcgi_read_timeout 60s;
}
ini
; /etc/php/8.2/fpm/pool.d/www.conf
listen = /run/php/php8.2-fpm.sock

After any change: sudo nginx -t && sudo systemctl reload nginx.

Step 4: Fix an overloaded backend

If the backend is up but every worker is busy, requests queue and then fail with 503. For PHP-FPM, tune the pool to your server's RAM:

ini
; www.conf — dynamic process manager
pm = dynamic
pm.max_children = 20      ; total workers (RAM / avg process size)
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500     ; recycle workers to avoid memory leaks

Set pm.max_children based on available memory: divide free RAM by the average memory a single PHP process uses (often 30–60 MB). Too high and you'll swap; too low and you'll 503 under load.

Step 5: Maintenance mode and rate limits

Sometimes a 503 is intentional. Frameworks like Laravel return 503 in maintenance mode (php artisan down) — run php artisan up to restore. If you use Nginx rate limiting, an aggressive limit can 503 legitimate traffic (including uptime monitors):

nginx
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

location /api/ {
    limit_req zone=api burst=20 nodelay;
}
If your monitoring tool reports intermittent 503s but the site works for you, you're likely rate-limiting the monitor. Allowlist its IPs, or exempt them from the limit.

Quick checklist

  1. Read the web server and app logs.
  2. Confirm the backend service is running.
  3. Verify the proxy socket/port matches the backend.
  4. Tune worker counts if the backend is overloaded.
  5. Rule out maintenance mode and rate limits.
Monitor it with TorixPulseCatch 503s the instant they start — TorixPulse tells you which status code your site returned.
Start free