Common causes
- The Node, Python, PHP-FPM or other backend process is stopped or crashed on startup
- The backend listens on a different port, or on a Unix socket while Nginx uses TCP (or the reverse)
- The app binds to 127.0.0.1 inside a Docker container, so other containers cannot reach it
- proxy_pass uses localhost inside a Nginx container, which points to the Nginx container itself
- localhost resolves to IPv6 ::1 but the app only listens on IPv4 127.0.0.1
- The backend is still starting up or restarting after a deploy
How to fix it
- Read the upstream address. The upstream: field in the log shows exactly where Nginx tried to connect, for example http://127.0.0.1:3000 or fastcgi://127.0.0.1:9000.
- Check what is listening. Run sudo ss -ltnp | grep -E ':3000|:9000' to see whether any process listens on that port and on which address. No output means the backend is not running there.
- Start or fix the backend. Run systemctl status for the service (for example php8.3-fpm or your app's unit) and journalctl -u <service> -n 50 to see why it stopped. Fix the startup error and restart it.
- Match the address in Nginx. Make proxy_pass or fastcgi_pass use the same port or socket as the backend, for example the listen value in the PHP-FPM pool file. Use 127.0.0.1 instead of localhost to avoid IPv6 surprises.
- Fix Docker networking. Make the app listen on 0.0.0.0 inside its container and use the Compose service name in Nginx, for example proxy_pass http://app:3000;. Both containers must be on the same network.
- Reload and test. Run sudo nginx -t && sudo systemctl reload nginx, then curl -I http://127.0.0.1:3000 from the Nginx host or container to confirm the backend answers.
Nginx reverse proxy
upstream app_backend {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app_backend;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
} How to stop it happening again
- Run backends under systemd or a process manager with automatic restart
- Keep backend port and socket settings in one place and reference them from Nginx
- Add health checks so deploys wait until the backend is listening
- In Docker, always refer to services by name, never localhost