Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild
Back to Blog Troubleshooting

500 Internal Server Error Nginx: 7 Causes and the Right Fix

Sean

Platform Writer

Jul 05, 2026
6 min read

500 Internal Server Error from nginx means the upstream (your app, PHP-FPM, etc.) failed. Per Nginx troubleshooting, the most common causes are: app errors, file permissions, proxy_pass misconfiguration, missing upstream, timeouts, and worker limit. The team that walks through this checklist resolves the issue in minutes.

500 Internal Server Error Nginx: 7 Causes and the Right Fix

Table of contents

Check the nginx error log

First step:

sudo tail -50 /var/log/nginx/error.log

The team that reads the error log has the specific error message. Common entries: connect() failed, upstream timed out, permission denied.

Cause 1: upstream app crashed

The backend (Node, Python, PHP-FPM, etc.) crashed or returned 5xx:

# Check the app logs
sudo journalctl -u myapp --since "5 min ago"

The team that checks the app log finds the root cause (e.g., Python traceback).

Cause 2: file permissions

Nginx can’t read the files (static assets, socket):

# Fix ownership
sudo chown -R www-data:www-data /var/www/myapp

# Fix permissions
sudo chmod 755 /var/www/myapp
sudo chmod 644 /var/www/myapp/index.html

The team that has wrong permissions sees permission denied in error log.

Cause 3: proxy_pass misconfiguration

location /api/ {
    proxy_pass http://localhost:8080/;  # Note the trailing slash
}

Missing trailing slash can cause double-prefixing. The team that has wrong proxy_pass sees 404 not found for proxied requests.

Cause 4: upstream not running

# Check the upstream
sudo systemctl status myapp
curl -v http://localhost:8080/

The team that has a stopped upstream sees connection refused in nginx log.

Cause 5: timeouts

location /api/ {
    proxy_pass http://backend;
    proxy_connect_timeout 5s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
}

Default 60s. The team that has long-running endpoints has higher timeouts.

Cause 6: worker limit

worker_connections 1024;  # default

If exceeded, nginx returns 500. Check /var/log/nginx/error.log for worker_connections are not enough. The team that has high traffic has higher worker limits.

Cause 7: SELinux / AppArmor

On RHEL family or Ubuntu with AppArmor:

# Check SELinux denials
sudo ausearch -m avc -ts recent

# Check AppArmor
sudo aa-status

The team that has SELinux denied has permission denied in audit log.

Common fixes

  1. Check upstream app logs (root cause often there).
  2. Verify file permissions.
  3. Check upstream is running.
  4. Increase timeouts for slow endpoints.
  5. Check worker_connections and worker_rlimit_nofile.
  6. Configure proper error pages:
error_page 500 502 503 504 /50x.html;
location = /50x.html {
    root /var/www/errors;
}

The team that has custom 50x pages has better UX during outages.

FAQ

Where is the nginx error log?

/var/log/nginx/error.log (Debian/Ubuntu) or /var/log/nginx/error.log (RHEL family). The team that reads the error log has the specific error.

Why does 500 happen intermittently?

Either upstream overload (CPU/memory exhausted), or transient network issues. The team that monitors upstream metrics has correlation.

How do I serve a custom 500 page?

error_page 500 /50x.html; in the server or location block. The team that has custom error pages has better UX.

Is 500 from nginx different from 500 from the app?

Yes - nginx 500 means nginx couldn’t get a valid response from the upstream. App 500 means the app returned 500 to nginx. The team that traces which layer has the error has the fix path.

How do I prevent 500s during deployment?

Use nginx upstream health checks + proxy_next_upstream to retry on failure. The team that has zero-downtime deploys uses these features.

If you are sizing the infrastructure for the kind of project this post covers, the RunxBuild hosting calculator is the right place to model the line items. The compute, the memory, the storage, the bandwidth, the database - each one is a separate number, and the team’s mental model for the platform is the sum of those numbers. The RunxBuild dashboard is where the team sees the actual usage in one place.

Useful related references:

#nginx#troubleshooting#500#dev-infra