Skip to main content

Next.js 502 Bad Gateway on EC2 — how to fix

TL;DR

How to diagnose and fix 502 Bad Gateway errors when running self-hosted Next.js behind nginx on AWS EC2.

Key facts

Topic
Production error triage
Stack
Next.js / nginx / AWS EC2

TL;DR

A 502 Bad Gateway from nginx in front of a self-hosted Next.js application on EC2 means nginx could not get a valid response from the upstream Next.js process. The Next.js server has either crashed, is not listening on the port nginx expects, or is taking too long to respond to SSR requests.

Common causes

  • Next.js process crashed — PM2 shows the process in errored state or it has disappeared entirely
  • Port mismatch — Next.js listens on port 3000 but nginx proxies to a different port, or the standalone server binds to a random port
  • PM2 process not started after deploy — the build completed but nobody ran pm2 reload
  • nginx upstream timeout too low — SSR pages with heavy data fetching exceed the default 60-second proxy_read_timeout
  • proxy_pass misconfiguration — pointing to localhost instead of 127.0.0.1 when IPv6 is not configured, or missing the trailing slash causing path issues

Diagnosis workflow

Check if the Next.js process is alive and listening:

pm2 status
ss -tlnp | grep :3000
curl -I http://127.0.0.1:3000

Review the nginx error log for specific upstream messages:

tail -100 /var/log/nginx/error.log

Look for connect() failed (111: Connection refused) (process down), upstream timed out (SSR too slow), or upstream prematurely closed connection (process crashed mid-response).

Test the upstream directly from the EC2 instance:

curl -v http://127.0.0.1:3000/

Fix the nginx configuration

A correct nginx setup for Next.js on EC2:

upstream nextjs {
    server 127.0.0.1:3000;
    keepalive 64;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://nextjs;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 120s;
        proxy_connect_timeout 10s;
        proxy_send_timeout 120s;
    }

    location /_next/static {
        alias /var/www/nextapp/.next/static;
        expires 365d;
        access_log off;
        add_header Cache-Control "public, immutable";
    }
}

Key details: use 127.0.0.1 rather than localhost to avoid IPv6 resolution issues. Set proxy_read_timeout high enough for your slowest SSR page. Serve _next/static directly from nginx to avoid burdening the Node.js process with static asset requests.

EC2-specific checks

Verify the security group allows traffic on port 80/443 from the internet and that the instance's internal firewall is not blocking localhost connections:

sudo ufw status
sudo iptables -L -n

Check if the instance ran out of memory, causing the OOM killer to terminate the Next.js process:

dmesg | grep -i "killed process"

Where Reflex helps

Reflex correlates nginx 502 errors with Next.js process health on your EC2 instances. When a 502 spike occurs, Reflex checks the upstream process, restarts it if down, verifies the response code normalises, and alerts your team with a correlated timeline of nginx logs and PM2 status changes. See How it works.