Nuxt 3 502 Bad Gateway — fix guide
TL;DR
How to diagnose and fix 502 Bad Gateway errors when running self-hosted Nuxt 3 behind nginx.
Key facts
- Topic
- Production error triage
- Stack
- Nuxt.js / nginx / Linux
TL;DR
A 502 Bad Gateway from nginx in front of Nuxt 3 means nginx attempted to proxy a request to the Nitro server but received no valid response. The Nitro process has either crashed, is not listening on the port nginx expects, or is taking too long to render an SSR page. This is the most common Nuxt 3 self-hosting issue.
Common causes
- Nitro process crashed — PM2 shows the process in
erroredorstoppedstate - Port mismatch — Nitro defaults to port 3000, but
NUXT_PORToverrides this; nginx must proxy to the correct port - Bind address mismatch — Nitro listening on
127.0.0.1while nginx proxies to0.0.0.0, or vice versa - Upstream timeout — complex SSR pages taking longer than nginx's
proxy_read_timeout(default 60s) - Process not started after deploy —
nuxt buildcompleted but nobody started the production server
Diagnosis workflow
Check if the Nitro server is running and listening:
pm2 status
ss -tlnp | grep :3000
If the port shows nothing, the Nitro process is not running. Check PM2 logs:
pm2 logs nuxt-app --lines 50
Review nginx error logs for the upstream failure:
tail -100 /var/log/nginx/error.log
Look for connect() failed (111: Connection refused) (process not running) or upstream timed out (SSR too slow).
Test the Nitro server directly, bypassing nginx:
curl -I http://127.0.0.1:3000/
Fix the port configuration
Nuxt 3 uses environment variables to configure the Nitro server's listen address:
NUXT_HOST=127.0.0.1
NUXT_PORT=3000
Set these in your PM2 ecosystem file or systemd service. Then ensure nginx proxies to the same address:
upstream nuxt_app {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://nuxt_app;
proxy_http_version 1.1;
proxy_set_header Connection "";
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 60s;
proxy_connect_timeout 10s;
}
location /_nuxt/ {
alias /var/www/nuxt-app/.output/public/_nuxt/;
expires 365d;
add_header Cache-Control "public, immutable";
access_log off;
}
}
Test and reload:
sudo nginx -t && sudo systemctl reload nginx
Fixing timeout-related 502s
If SSR pages are legitimately slow (data-heavy pages during cold start), increase nginx's upstream timeout:
proxy_read_timeout 120s;
proxy_connect_timeout 15s;
proxy_send_timeout 60s;
However, slow SSR is a symptom — consider adding server-side caching with Nitro's built-in route rules:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/blog/**': { swr: 3600 },
'/api/**': { cors: true, swr: false },
},
})
Starting Nitro after a deploy
A complete deploy sequence for Nuxt 3:
cd /var/www/nuxt-app
git pull origin main
npm ci
npx nuxt build
pm2 restart nuxt-app
sleep 3
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/
If the health check fails, check .output/server/index.mjs exists and review PM2 error logs.
Where Reflex helps
Reflex correlates nginx 502 errors with Nitro process health in real time. When it detects a 502 spike, Reflex checks whether the Nuxt process is listening, restarts it via PM2 if needed, verifies the 502 rate drops, and alerts your team with a full incident timeline including the root cause. See How it works.