Before explaining the issue, I want to tell you that I have already tried these solutions on StackOverflow:
- Django Heroku not serving static files when Debug=False
- Django: Whitenoise not working in production with debug false
Heroku Ticket
I raised a ticket on Heroku also. I got this in reply:
Please try running the command
python manage.py collectstatic
on your local machine before deploying your app to Heroku. This would make the required arrangements in your application directory which you can later push to Heroku.
The reason why it isn't working is due to the ephemeral file system of Heroku. This means that any changes made to the file system will not be persistent. Every dyno boots with a fresh copy of your deployed application file system. When you run this command from the Heroku bash, it spins a one-off dyno and runs the task on this dyno. So, once you run the task and exit the bash, these changes are deleted. They do not reflect on your application's live dyno. This is why you need to make all the file system changes on your local machine and push them to your Heroku app.
Furthermore, when you set the
DEBUG=false
in your settings.py, it doesn't display any internal error log or data when you browse your app. Displaying this information on your production app is not ideal. This is why it is suggested to set DEBUG=false. If your application is still in the testing phases, you can try setting it to true. But, please make sure you make it false before your final release.
What I did in response:
- Ran
python manage.py collecstatic
on my local machine. - Pushed my code to GitHub repository with new files in
staticfiles/
folder - Set
DEBUG=False
. But, it's still showing me Server Error (500).
Now they said that the issue is with my app and they can't help me out at the application level. So, I am back here again.
Minimal Production
production.py
import os
import django_heroku
import dj_database_url
import dotenv
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
dotenv_file = os.path.join(BASE_DIR, ".env")
if os.path.isfile(dotenv_file):
dotenv.load_dotenv(dotenv_file)
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
# Application definition
INSTALLED_APPS = [
'home',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
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 = 'portfolio.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['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',
],
},
},
]
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
STATIC_ROOT = os.path.join(BASE_DIR, "live-static", "static-root")
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "live-static", "media-root")
django_heroku.settings(locals())
- Directory structure
.
├── home
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── live-static
│ ├── media-root/
│ └── static-root/
├── manage.py
├── portfolio
│ ├── settings
│ │ ├── base.py
│ │ ├── __init__.py
│ │ ├── local.py
│ │ └── production.py
│ └── urls.py
├── Procfile
├── requirements.txt
├── runtime.txt
├── static/
├── staticfiles/
└── templates/
requirements.txt
:
whitenoise==5.1.0