Django/Heroku error "Web process failed to bind to $PORT"

I am trying to configure a Django/PostgreSQL project to deploy on Heroku using Waitress. (I've only done this once successfully, several years ago using Guincorn).

I am ultimately running into an error

Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch

The full error log is:

2025-04-09T07:09:48.289599+00:00 heroku[web.1]: State changed from crashed to starting
2025-04-09T07:09:52.235046+00:00 heroku[web.1]: Starting process with command `waitress-serve project.wsgi:application`
2025-04-09T07:09:52.781389+00:00 app[web.1]: Python buildpack: Detected 512 MB available memory and 8 CPU cores.
2025-04-09T07:09:52.781847+00:00 app[web.1]: Python buildpack: Defaulting WEB_CONCURRENCY to 2 based on the available memory.
2025-04-09T07:09:53.244456+00:00 app[web.1]: INFO:waitress:Serving on http://0.0.0.0:8080
2025-04-09T07:10:52.357945+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
2025-04-09T07:10:52.370446+00:00 heroku[web.1]: Stopping process with SIGKILL
2025-04-09T07:10:52.421789+00:00 heroku[web.1]: Process exited with status 137
2025-04-09T07:10:52.445044+00:00 heroku[web.1]: State changed from starting to crashed"

I initially thought this was a issue with defining PORT, but after leaving it out of my Procfile, it seems like Heroku is designating PORT locally, and so that problem may be resolved?

I'm hoping someone might have some ideas that might cause "failed to bind to $PORT." Could it be an issue with DATABASE_URL? I am using Heroku's SSL but have not have figured out those settings clearly.

Procfile:

web: waitress-serve project.wsgi:application

.env:

WEB_CONCURRENCY=3
PORT=PORT
SECRET_KEY=[text-of-secret-key]

And my settings files, base.py and heroku.py base.py

base.py

import os
import django_on_heroku
import environ
from environ import Env
from dotenv import load_dotenv
import dj_database_url

load_dotenv()

env = Env()

BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

environ.Env.read_env(os.path.join(BASE_DIR, '.env'))

SECRET_KEY = env('SECRET_KEY')
PORT = env('PORT')

SECURE_HSTS_SECONDS = 3600
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

DEBUG = True

ALLOWED_HOSTS = ['.herokuapp.com/', 'localhost']

INSTALLED_APPS = [
    'cgp.apps.CgpConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.humanize',
    'ajax_datatable',
    'whitenoise.runserver_nostatic',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'project.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "templates")],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'django.template.context_processors.request',
            ],
        },
    },
]

WSGI_APPLICATION = 'project.wsgi.application'


IS_HEROKU_APP = "DYNO" in os.environ and "CI" not in os.environ

if IS_HEROKU_APP:
    DATABASES = {}
    DATABASES['default'] = dj_database_url.config(conn_max_age=600)
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': 'cgp',
            'USER': 'postgres',
            'PASSWORD': 'postgres',
            'HOST': 'localhost',
            'PORT': '5432',
        }
    }

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


STATIC_ROOT = os.path.join(BASE_DIR, 'static') ##same as beta

STATIC_URL = '/static/' ##same as beta

STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' ##same as beta


STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'cgp/static'),
]

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

django_on_heroku.settings(locals())

(I'm not sure my conditional definition of DATABASES is necessary, but I get the same error leaving out the first heroku condition.)

heroku.py

import environ
#import dj_database_url

# If using in your own project, update the project namespace below
from project.settings.base import *

env = environ.Env(
    # set casting, default value
    DEBUG=(bool, True)
)

# False if not in os.environ
DEBUG = env('DEBUG')

# Raises django's ImproperlyConfigured exception if SECRET_KEY not in os.environ
SECRET_KEY = env('SECRET_KEY')

ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')

# Parse database connection url strings like psql://user:pass@127.0.0.1:8458/db
DATABASES = {
    # read os.environ['DATABASE_URL'] and raises ImproperlyConfigured exception if not found
    'default': env.db(),
}

requirements.txt

asgiref==3.7.2
dj-database-url==2.3.0
Django==4.2.5
django-ajax-datatable==4.5.0
django-environ==0.12.0
django-heroku==0.3.1
django-on-heroku==1.1.2
gunicorn==23.0.0
packaging==24.2
psycopg2==2.9.7
psycopg2-binary==2.9.10
python-dotenv==1.0.1
sqlparse==0.4.4
typing_extensions==4.12.2
tzdata==2023.3
waitress==3.0.2
whitenoise==6.9.0

Welcome to Sushiro Bedok Mall Outlet in Singapore. Sushiro, Japan’s largest conveyor belt sushi chain, has an outlet at Bedok Mall in Singapore. This branch is located at 311 New Upper Changi Road, #B1-10, and offers various fresh and affordable sushi dishes. The restaurant operates daily from 11:00 AM to 10:00 PM, making it a convenient spot for both lunch and dinner.

During my visit to Sushiro Singapore I was impressed by the efficient service and quality of the sushi. The conveyor belt system allowed me to choose from diverse dishes, all at reasonable prices. The lively atmosphere and friendly staff made the dining experience enjoyable. https://sushiromenusg.org/sushiro-bedok-mall/

The <a href="https://kfcmenuuk.info/">KFC MENU</a> in the UK has a lot of tasty chicken meals. You can get their famous fried chicken, which is made with a special mix of spices. They sell chicken pieces, burgers like the Zinger, and meals to share like big chicken buckets. If you want something small, you can try Popcorn Chicken or wings. They also have sides like chips, corn, and coleslaw. You can get drinks and desserts too. If you don’t eat meat, there’s a vegan burger as well. There’s something for everyone to enjoy.

Back to Top