"502 Bad Gateway" after a deploy

Last verified

502 Bad Gateway means nginx, the web server in front of your site, asked your app for the page and got no usable answer. The app is not running, not listening where nginx looks, or it crashed mid-request. It is most common on Node.js apps, right after a deploy, a version switch or a new start command.

Why it happens

A Node.js app runs as a service of its own. nginx passes every request it cannot serve from public/ to your app on the port in the PORT environment variable. A 502 follows when:

  • The app listens on the wrong port. It listens on a fixed port, like 3000 or 8080, instead of process.env.PORT.
  • The start command is wrong. It points at a file the build did not produce, for example node build when the output is somewhere else.
  • The app crashes on start. A dependency it needs at runtime sits in devDependencies (we install production dependencies only), or a required environment variable is missing. The service manager restarts a crashed app a few times in quick succession, then gives up. The app stays down until the next deploy, restart or switch.
  • The app ran out of memory and was stopped. See "Allowed memory size exhausted" / out of memory.
  • On a PHP site: PHP itself is not running, for example straight after a PHP version switch that did not finish.

Note: Every deploy checks your site right after the switch. A Node.js app must start and answer on its port, and the site must answer without a server error such as a 502. If it does not, the deploy fails at Checking the site after the switch and, when there is an earlier release, your site goes back to it. With no earlier release to go back to, the new code stays live and its row in Recent deploys reads live, failing. The check is one moment, though. An app that crashes a minute later, or only on some pages, still passes, so open the site yourself after each deploy.

Fix it

  1. Read the app's own output. Open Sites, choose your site, then Logs → Application. For a Node.js app, this is everything your app printed to the console, including the crash. Look for Error: Cannot find module …, EADDRINUSE, or a stack trace from your start-up code.
  2. Check what nginx saw. In Logs → Web server errors, connect() failed (111: Connection refused) while connecting to upstream means nothing was listening. upstream prematurely closed connection means the app crashed while answering.
  3. Put the last good release back while you fix it. If the deploy failed at Checking the site after the switch and says it switched your site back, this is already done. Otherwise, on the Deploys tab, use Roll back to … on the Live now strip. Your files return to the previous release and your database stays as it is. See Approve a release, discard it or roll back.
  4. Check the port. Your app must listen on process.env.PORT. In your app (Express): app.listen(process.env.PORT || 3000).
  5. Check the start command. Under Configure → Node.js → Start command, an empty field runs npm start (or node server.js / node index.js). Nuxt needs node .output/server/index.mjs. SvelteKit needs node build. Press Save; your app restarts with it within a minute. Node.js apps lists the commands per framework.
  6. Check dependencies. Anything your app requires or imports at runtime must be in dependencies, not devDependencies. Commit an up-to-date package-lock.json.
  7. Start it again. After a fix that needs no new code (an environment variable, say), press Install & restart in the Deploys tab's side panel. It installs production dependencies and restarts your app. For a fix in your code, push and deploy again.

On a PHP site, open Configure → PHP version, choose the version under Run on and press Switch again. Wait for Now running PHP ….

Still stuck?

If Application is empty and Web server errors shows refused connections, your app never started at all. Contact us with the site name and the time of the deploy, and we will look at the service on our side.

Stuck? Contact support — replies within one business day.