Skip to content

Troubleshooting

App not answering on its port: fix health check fails

Seeing "didn't answer on port within 90 seconds"? Learn why the health check fails and how to listen on PORT and 0.0.0.0 in Express, Flask and FastAPI.

Updated 3 min read

Every release on DployHub is zero-downtime. We start the new version next to the old one and wait up to 90 seconds for it to answer HTTP on your health check path with any status below 500. Only then does traffic switch. If the new version never answers, the old one keeps running and the deploy is marked failed with the last 50 log lines. Here is how to read each failure message and fix it.

"Your app didn't answer on port P within 90 seconds"

The full message reads: "Your app didn't answer on port P within 90 seconds. Make sure it listens on 0.0.0.0 and uses the PORT environment variable (PORT=P), or change the port in the app settings." It has three usual causes:

  • Your app listens on a hard-coded port that differs from the one in Settings.
  • Your app binds to localhost or 127.0.0.1, so it is unreachable from outside the container.
  • Startup is slow (migrations, cache warm-up) and takes longer than 90 seconds.

We always set the PORT environment variable. Read it and bind to 0.0.0.0.

Express (Node.js)

js
const express = require('express');
const app = express();

app.get('/', (req, res) => res.send('ok'));

const port = process.env.PORT || 3000;
app.listen(port, '0.0.0.0', () => console.log('listening on ' + port));

Flask (Python)

With auto-detection, Flask apps start with gunicorn app:app --bind 0.0.0.0:8000, which is already correct. If you run the file directly, bind explicitly:

python
import os
from flask import Flask

app = Flask(__name__)

@app.get("/")
def index():
    return "ok"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 8000)))

FastAPI (Python)

The variable must be named app. A custom start command should pass both host and port:

bash
uvicorn main:app --host 0.0.0.0 --port $PORT

If your app genuinely uses a different port, set "Port your app listens on" in Settings to match. See port and health checks.

"Your app kept answering with HTTP 5xx"

Symptom: "Your app kept answering with HTTP 5xx on /path for 90 seconds." Your app is running and reachable, but the health check path returns server errors. Typical causes are a missing environment variable (database URL, secret key), a database that is unreachable, or a health check path that requires login and crashes. For Django, a missing entry in ALLOWED_HOSTS is a classic cause.

  • Check the last 50 log lines on the failed deploy for the stack trace.
  • Confirm all required variables exist for this environment in the environment variables tab. Staging and live have separate sets.
  • Point the health check path at a light route such as /health that returns 200 without touching the database. Redirects and 4xx statuses count as healthy.

"Your app stopped right after starting"

Symptom: "Your app stopped right after starting (exit code N)…". The process exited instead of serving. Exit code 1 usually means an uncaught error at startup, such as a missing module or bad config. Exit code 137 means it was killed for using more memory than you gave it; see app crashed: out of memory. Run the start command locally with the same environment variables to reproduce it.

Still failing?

Open the Logs tab for the environment to see runtime output, and compare it with the deploy log. If you cannot find the cause, raise a ticket and attach the deployment so we receive its status, error summary and recent log lines.

Frequently asked questions

Is my site down while the health check fails?

No. The previous version keeps serving until a new version passes the health check.

Why does it work on localhost but not on DployHub?

Locally, binding to localhost is fine. In a container the app must bind to 0.0.0.0 so traffic from outside the container can reach it.

Does a 404 on the health check path fail the deploy?

No. Any status below 500 counts as healthy. Only no answer at all or repeated 5xx responses fail it.