Heroku Django app not loading static files (404 Not Found) - python

I have been trying to deploy a django app onto heroku. However, it's not able to obtain the static files. I ran collecstatic on heroku and there is a static folder in the root directory of the app that contains the correct files:
~/static/rest_framework/css/bootstrap.min.css.
Settings.py:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
cURL:
curl 'https://xxx.herokuapp.com/static/rest_framework/css/bootstrap.min.css' \
-XGET \
-H 'Referer: https://xxx.herokuapp.com/users/login' \
-H 'Accept: text/css,*/*;q=0.1' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7'

I've spent some hours before I was able to figure out this. #VipinMohan solution works for whitenoise<4. However, in version 4+, WhiteNoise removes some options which were deprecated in the previous major release. For the record, I am using Django 2.1.
From the docs:
The WhiteNoise middleware should be placed directly after the Django SecurityMiddleware (if you are using it) and before all other middleware.
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
# the next line of code is the one that solved my problems
'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'
]
Pay attention to the Note in the section of the provided link.
You might find other third-party middleware that suggests it should be given highest priority at the top of the middleware list. Unless you understand exactly what is happening you should ignore this advice and always place WhiteNoiseMiddleware above other middleware.

Django does not support serving static files in production. However, the fantastic WhiteNoise project can integrate into your Django application, and was designed with exactly this purpose in mind.
pip install whitenoise
add whitenoise to your requirements.txt
add this code in app/wsgi.py
from whitenoise.django import DjangoWhiteNoise
application = DjangoWhiteNoise(application)

Add collectstatic to Procfile
web: python manage.py collectstatic --no-input; gunicorn myapp.wsgi --log-file - --log-level debug
Thanks to this stack overflow answer

WhiteNoise configuration should be changed if you use v4.0 or later.
Please refer this whitenoise-changelog

Related

Server error (500) when trying to deploy django app with DEBUG=False on heroku

I am trying to deploy an django application on heroku. when the DEBUG variable is False, I receive a server error (500). Everything works fine when DEBUG is True. How to solve this problem ?
Here is some of the logs:
2021-08-17T10:15:08.603841+00:00 app[web.1]: 10.1.59.205 - - [17/Aug/2021:10:15:08 +0000] "GET /connexion?next=/ HTTP/1.1" 500 145 "-" "Mozilla/5.0 (Windows NT 10.0;
Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67"
2021-08-17T10:15:08.603943+00:00 heroku[router]: at=info method=GET path="/connexion?next=/" host=pnl-testapi.herokuapp.com request_id=edc211c1-244d-49ad-aac6-6e2c1d9
cf5c0 fwd="160.119.178.105" dyno=web.1 connect=0ms service=63ms status=500 bytes=403 protocol=https
Did you add your domain in the ALLOWED_HOSTS variable in settings.py?
ALLOWED_HOSTS = ['.herokuapp.com']
Edit: You have added the access log of the webserver, please also add the exception. Have you tried running your project locally so you have quick and easy access to the console?
Fix for Server error (500) when trying to deploy django app with DEBUG=False on heroku
pip install whitenoise
Edit your settings.py file and add WhiteNoise to the MIDDLEWARE list, above all other middleware apart from Django’s SecurityMiddleware:
MIDDLEWARE = [
# 'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
# ...
]
If you install django-heroku, try to comment it out and also comment django_heroku.settings(locals()) out.
You can turn your DEBUG = False and redeploy to Heroku.
This method actually worked for me. You can give it a try.
You can also read whitenoise documentation: http://whitenoise.evans.io/en/stable/
As a rule of thumb this error is generated due to 3 things:
1.- You did not define the path for your static file directories
2.- You did not especify ALLOWED_HOST
3.- You did not install whitenoise
to solve this you have to install whitenoise and django-heroku in Python:
pip install whitenoise
pip install django-heroku
and add this in your settings.py:
import django_heroku # import django-heroku
ALLOWED_HOSTS = ['*'] # add your host(s)
# Add whitenoise in MIDDLEWARE
MIDDLEWARE = [
...
'whitenoise.middleware.WhiteNoiseMiddleware', # add this
]
# Add your paths for static files
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' # add this
django_heroku.settings(locals()) # add this
With this you need to write:
heroku config:set DISABLE_COLLECTSTATIC=0
Of this way heroku will be able to identify your static file directories.
It seems that heroku need to have reference to static file directories obligatorily.

How to debug django staticfiles served with whitenoise, gunicorn, and heroku?

I've got a project that runs on Heroku from a Dockerfile and heroku.yml.
The site generally works, but I am having trouble with static files.
collectstatic is run when building the pack.
If I set DEBUG to True, it finds the files.
I'm trying to use whitenoise but not sure why it's not working. It sounds so simple so I'm sure it's something silly.
heroku.yml
setup:
addons:
- plan: heroku-postgresql
build:
docker:
web: Dockerfile
release:
image: web
command:
- python manage.py collectstatic --noinput
run:
web: gunicorn records_project.wsgi
settings.py
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
'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',
'django.contrib.sites.middleware.CurrentSiteMiddleware',
]
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'whitenoise.runserver_nostatic',
'django.contrib.staticfiles',
'django.contrib.sites',
... more stuff here...
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# for referencing files with a URL
STATIC_URL = '/static/'
# where to find static files when local
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),]
# location of satatic files for production
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# how Django should look for static file directories; below is default
STATICFILES_FINDERS = [
# defaults
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
]
# This gives me a 500 error
# STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
urls.py
urlpatterns here...
...
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Any chance you are referencing a static file (e.g., a CSS file or image) in your template that doesn't exist? I was having this same problem because I had the following in my base template:
<link rel="stylesheet" href="{% static 'css/styles.css' %}">
But no styles.css file in my css folder.
I had similar issue because static files, collected on release stage, were missing on run. So i changed my code to:
heroku.yml
setup:
addons:
- plan: heroku-postgresql
build:
docker:
web: Dockerfile
release:
image: web
command:
- chmod u+x entrypoint_heroku.sh
run:
web: ./entrypoint_heroku.sh
Dockerfile
FROM python:3.7
WORKDIR /usr/src/app
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
RUN apt-get update
RUN apt install -y netcat
RUN pip install pipenv
COPY Pipfile* /usr/src/app/
RUN pipenv install --system --dev
COPY . /usr/src/app/
RUN mkdir -p /storage/static/
entrypoint_heroku.sh
#!/bin/sh
python manage.py migrate --noinput
python manage.py collectstatic --noinput
gunicorn app.wsgi
settings.py
STATIC_URL = '/static/'
MEDIA_ROOT = '/storage/'
STATIC_ROOT = MEDIA_ROOT + 'static/'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Not the best solution. But it helped me to run server with Debug=False
For what it's worth, I never found a way to get WhiteNoise to serve those static files. I swear it's worked in the past with a similar set up, so that will remain a mystery.
I received a tip from Matt from justdjango.com that Heroku doesn't want to serve static files from that same server. Once I moved my static files over to an AWS S3 bucket, all was well.
I also faced this issue. Although successfully collecting static files on release stage, they weren't present when dyno was up (thus Django missing manifest errors).
This setup worked:
heroku.yml
build:
docker:
web: Dockerfile
run:
web: ./heroku_entrypoint.sh
Dockerfile
--- some code ---
RUN chmod +x heroku_entrypoint.sh
RUN mkdir -p /app/static/
--- other code ---
heroku_entrypoint.sh
python manage.py collectstatic --noinput
python manage.py migrate
gunicorn app.wsgi:application --bind 0.0.0.0:$PORT

Cannot load static files in production after trying numerous solutions

I have moved my django project from development to my production server. After deployment I cannot view static files on my pages.
I know that django does not serve static files once debug is turned off and have tried using whitenoise to serve my static files.
Attempt 1- WhiteNoise
These are the changes that I made to settings.py
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',
]
and wsgi.py:
from whitenoise.django import DjangoWhiteNoise
...
application = get_wsgi_application()
application = DjangoWhiteNoise(application)
and then running collectstatic. However my webpages still were not loading any of the static files.
Attempt 2- Apache- mod_wsgi
With the second attempt, I tried using apache+ mod_wsgi To be specific I connected to my VPS using terminal in cpanel installed apache2 and followed a tutorial.
sudo apt-get install apache2
created my conf file
sudo nano new_config.conf
added this to it
<VirtualHost *:80>
ServerName 127.0.0.1
ServerAlias localhost
Alias /static /var/gradientboostmvp/static/
WSGIScriptAlias / /var/gradientboostmvp/django_school/wsgi.py
<Directory /var/gradientboostmvp/>
Order deny,allow
Allow from all
</Directory>
DocumentRoot /var/gradientboostmvp
</VirtualHost>
enabled the newly created virtual host conf file
sudo a2ensite new_config.conf
sudo /etc/init.d/apache2 restart
added my WSGIPythonPath in apache2.config
WSGIPythonPath /var/gradientboostmvp
saved the changed, but still couldn't load my static files
Attempt 3- Import serve
I also had a similar question that was closed as a duplicate. I tried the solutions offered in the answers
from django.views.static import serve
...
urlpatterns = [
path('', classroom.home, name='home'),
path('about', classroom.about, name='about'),
path('courses', classroom.courses, name='courses'),
path('course_details', classroom.course_details, name='course_details'),
path('static',serve {'document_root':settings.STATIC_ROOT}),
Which then resulted in me getting an error message when I tried visiting my home page
Incomplete response received from application
Well, as you are using Apache to serve django, then why not use it serve static files as well. As per documetation, first you need to use collectstatic to store static files to a specific folder. For example in your settings if you have STATIC_ROOT specified as:
STATIC_ROOT = '/path/to/mysite.com/static/'
Then when you run collect static, the static files will be stored inside /path/to/mysite.com/static/ directory.
Then add that path as alias to apache:
Alias /static/ /path/to/mysite.com/static/

Why Django-Admin Panel did not show css and javascript in real vps?

I have django admin panel working on a vps ( Windows Server 2012 ) , Why it is not showing any css styles or boostrap ? it is showing just html and nothing else .
https://docs.djangoproject.com/en/2.1/howto/static-files/
During development, if you use django.contrib.staticfiles, this will
be done automatically by runserver when DEBUG is set to True (see
django.contrib.staticfiles.views.serve()).
So when you change DEBUG=False to move out of development, Django runserver will no longer automatically serve static files.
Here is an alternate method using http://whitenoise.evans.io/en/stable/django.html
whitenoise for serving staticfiles in deployment
1) pip install whitenoise
2) Add 'whitenoise' to installed_apps
3) Give STATIC_ROOT to a folder like:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
4) Run to collect staticfiles in STATIC_ROOT directory
python manage.py collectstatic
5)Add STATICFILES_STORAGE(optional)
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
6) Add in middleware before everything except 'django.middleware.security.SecurityMiddleware', like:
MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
...
]
7)Change to DEBUG=False in settings.py
More details here http://whitenoise.evans.io/en/stable/django.html

Django - Authentication using REMOTE_USER - How to test in dev server?

I want to use django.contrib.auth.middleware.RemoteUserMiddleware for authentication as outlined here:
https://docs.djangoproject.com/en/dev/howto/auth-remote-user/
Question is, how can I test this in a dev environment where there is no Apache? i.e. can I set REMOTE_USER somehow in local settings?
EDIT (adding settings)
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.RemoteUserBackend',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
...
)
Then I have this in my local_Settings:
os.environ['REMOTE_USER'] = "mmatyas"
I also tried the 'HTTP_REMOTE_USER' variant. Thanks!
The variable has to be set in the environment in which you start the dev server. usually it's just:
REMOTE_USER=myuser ./manage.py runserver
You can write some WSGI middleware and set it there, and then make sure the wsgi middleware wraps your django app in the wsgi stack. lots of tutorials around on writing wsgi middleware, it'll be a short one page of code. Easy-peasy-lemon-squeezy!
In your dev environment, you can set an environment variable in the same command prompt you use to start up your dev server.
Something like export REMOTE_USER="duncan" if on a Unixy machine.
You can also do this by editing your manage.py and setting os.environ['REMOTE_USER'] = "duncan"

Categories

Resources