What's Actually Happening

Nginx returns 503 Service Unavailable when backend services are overloaded or temporarily unavailable. Backend cannot handle requests, rate limits are hit, or services are under maintenance.

The Error You'll See

503 Service Unavailable:

bash
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx</center>
</body>
</html>

Nginx error log:

```bash tail -f /var/log/nginx/error.log

limiting requests, excess 50.100 by zone "api_limit" ```

Why This Happens

  1. 1.Backend overloaded - Backend cannot handle request volume
  2. 2.Rate limiting - Request rate limit exceeded
  3. 3.Backend queue full - Backend connection queue full
  4. 4.Insufficient workers - Not enough backend workers
  5. 5.Resource exhaustion - Backend out of memory or CPU
  6. 6.Maintenance mode - Backend under maintenance
  7. 7.Backend crashing - Backend crashing repeatedly

Step 1: Check Nginx Error Logs

```bash tail -f /var/log/nginx/error.log

grep -i "503|limit|unavailable" /var/log/nginx/error.log | tail -20

journalctl -u nginx -f | grep -i "503|limit" ```

Step 2: Check Backend Load

```bash systemctl status backend

top -p $(pgrep -f backend)

ps aux | grep backend

# Check backend processes: pgrep -c backend-process

# Backend resource usage: pidstat -p $(pgrep -f backend) 1 5 ```

Step 3: Check Backend Queue

```bash # For PHP-FPM: php-fpm -tt 2>&1 | grep -i listen

ss -tlnp | grep php-fpm

# Check PHP-FPM status: curl http://localhost/php-fpm-status

# For Gunicorn: curl http://localhost/server-status

# Check connection queue: netstat -an | grep backend-port | grep SYN ```

Step 4: Check Rate Limiting

```bash cat /etc/nginx/nginx.conf | grep -A 10 limit_req

cat /etc/nginx/conf.d/*.conf | grep -A 5 limit_req_zone

# Rate limit configuration: limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

# Current rate limit status: # Check nginx stub_status curl http://localhost/nginx_status ```

Step 5: Check Backend Configuration

```bash # PHP-FPM workers: cat /etc/php-fpm.d/www.conf | grep -E "pm\.(max_children|start_servers)"

# Gunicorn workers: cat /etc/systemd/system/gunicorn.service | grep workers

# uWSGI workers: cat /etc/uwsgi/apps-enabled/app.ini | grep workers

# Node.js cluster: # Check cluster worker count ```

Step 6: Increase Backend Capacity

```bash # PHP-FPM: # Increase workers: pm.max_children = 50 pm.start_servers = 10

systemctl restart php-fpm

# Gunicorn: # Increase workers: ExecStart=/usr/bin/gunicorn --workers 4 --threads 2 app:app

systemctl restart gunicorn ```

Step 7: Adjust Rate Limits

```bash # Increase rate limit: limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;

# Or allow burst: limit_req zone=api_limit burst=50 nodelay;

# Or disable rate limit temporarily: # Comment out limit_req directives

nginx -t systemctl reload nginx ```

Step 8: Check Backend Resources

```bash free -h

df -h

iostat -x 1

# Check backend memory: ps aux | grep backend | awk '{sum += $6} END {print sum/1024 " MB"}'

# Check CPU: top -b -n 1 | grep -A 5 "PID USER" ```

Step 9: Implement Caching

```bash # Enable proxy caching: proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m;

location /api/ { proxy_pass http://backend; proxy_cache api_cache; proxy_cache_valid 200 10m; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; }

nginx -t systemctl reload nginx ```

Step 10: Monitor Service Availability

```bash watch -n 5 'curl -s -o /dev/null -w "%{http_code}" http://localhost/api/health'

# Monitor backend status: watch -n 5 systemctl status backend

# Monitor nginx status: watch -n 5 'curl -s http://localhost/nginx_status'

# Monitor resources: watch -n 5 'free -h && echo && df -h' ```

Nginx 503 Service Unavailable Checklist

CheckCommandExpected
Error logstail error.logSpecific error
Backend loadtop/systemctlNormal
Rate limitsnginx configNot exceeded
Workersbackend configSufficient
Resourcesfree/dfAvailable
Queuenetstat/ssNot full

Verify the Fix

```bash curl -I http://localhost/api/endpoint

systemctl status backend

tail -f /var/log/nginx/error.log | grep -i 503

top -p $(pgrep -f backend)

curl -s http://localhost/nginx_status

free -h ```

  • [Fix Nginx 502 Bad Gateway](/articles/fix-nginx-502-bad-gateway)
  • [Fix Nginx Upstream Timeout](/articles/fix-nginx-upstream-timeout)
  • [Fix PHP-FPM Service Unavailable](/articles/fix-php-fpm-service-unavailable)