How to serve static files to AWS when deploying Django app (`python manage.py collectstatic` didn't work)?
Solution 1
There is definitive guide about deploying a django app to AWS Elastic Beanstalk from RealPython - here it is. It has whole section about static files and how to configure it with eb and you don't need to know anything about nginx/apache etc.
Basically you should define container_commands
in your eb config, these commands will be executed after application deploy is finished. For example migrate
and collectstatic
, so this is an example of such section in eb config file:
container_commands:
01_migrate:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py migrate --noinput"
leader_only: true
02_collectstatic:
command: "source /opt/python/run/venv/bin/activate && python iotd/manage.py collectstatic --noinput"
option_settings:
"aws:elasticbeanstalk:application:environment":
DJANGO_SETTINGS_MODULE: "iotd.settings"
"PYTHONPATH": "/opt/python/current/app/iotd:$PYTHONPATH"
"ALLOWED_HOSTS": ".elasticbeanstalk.com"
"aws:elasticbeanstalk:container:python":
WSGIPath: iotd/iotd/wsgi.py
NumProcesses: 3
NumThreads: 20
"aws:elasticbeanstalk:container:python:staticfiles":
"/static/": "www/static/"
Pay attention to aws:elasticbeanstalk:container:python:staticfiles
part.
And also you should define this part in your django settings file:
STATIC_ROOT = os.path.join(BASE_DIR, "..", "www", "static")
STATIC_URL = '/static/'
I copied this example almost entirely from article above, you should really check it, it's awesome.
UPD: how to debug missing staticfiles. I usually do this (it involves sshing to your eb instance):
- Make sure that
django.contrib.staticfiles
is included in myINSTALLED_APPS
. - Check in browser console url to missing file e.g.
/static/js/somefile.js
- Make sure in my django settings
STATIC_URL
is the same e.g./static/
. - Check actual value in
STATIC_ROOT
and check that this folder actually contains your static files in production server. - Check that my eb config is pointing to correct folder (under your
option_settings
section in config)
Also you can try to collect static into /static
dir on your production server (it's where eb looks for them by default). If all of a sudden it starts working - it means that your setting failed to override default one and you should check where else it was defined.
I hope these steps will help you to find right direction.
Solution 2
This is what worked for me.
Remove any staticfiles directives from .config
files. Find Static Files section under the Software Configuration. The left column is each of your /static/
url. The right is your static folder relative to your parent directory.
Make sure your STATIC_ROOT
setting matches the value on the right. Don't forget the trailing /
.
Pasting my settings anyway.
STATIC_URL = '/static/'
STATICFILES_DIRS = ('assets',)
STATIC_ROOT = os.path.join(BASE_DIR, '..', 'www', 'static')
And this is what my folder structure looks like relative to the settings files
project/
├── __init__.py
├── settings
│ ├── base.py
│ ├── __init__.py
│ ├── local.py
│ ├── production.py
wsgi.py
, urls.py
are located in project
folder. www
folder is one level above project
folder.
Hope this saves your Sunday at least.
SilentDev
Updated on June 07, 2022Comments
-
SilentDev almost 2 years
Yesterday, I created this post: DjangoRestFramework browsable api looks different locally vs when deployed on server?
Basically, when I did
python manage.py runserver
, this showed up:But after I deployed it to AWS (
eb deploy
), this is what I see when I access the site:The answer to the post above mentioned that it is because my static files were missing. So I searched how to deploy static files on AWS and came across this tutorial: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-django.html#python-django-update-app
Under the "Create a Site Administrator" section, it mentions that in order to serve static files, I must first define
STATIC_ROOT
insettings.py
(so I did:STATIC_ROOT = os.path.join(BASE_DIR, "ebdjangoapp/static/")
) and then I dideb deploy
. However, the site still looks the same as the 2nd image (without static files). I then tried doingpython manage.py collectstatic
(this created the static folder with therest_framework
directory inside it, containing thecss
files etc.) and then dideb deploy
again but the site stil looks the same as the 2nd image.How come the static files still aren't showing up?
Note, I searched around and came across this post: Django app deployment not loading static files and the answer says:
"You then need to serve
settings.STATIC_ROOT
atsettings.STATIC_URL
via your web server of choice, very commonly nginx as a reverse proxy behind your Apache-mod_wsgi app server."But I have no idea how web servers (nginx, reverse proxy, Apache-mod_wsgi) works. I have a Django app I run locally with
python manage.py runserver
, and I have AWS elastic beanstalk. I deploy my Django app to AWS by doingeb deploy
. What steps do I need to take in order for the static files to appear on deployment (assuming I don't know how to configure nginx, reverse proxy etc.).? -
SilentDev about 7 yearsThanks for the link. So I edited
settings.py
so thatSTATIC_ROOT
andSTATIC_URL
is what you mentioned. I then created a file called02_python.config
inside the.ebextensions
folder and copy pasted exactly what you have posted here. I changeiotd
toebdjango
(name of my project.. my app name isebdjangoapp
). I then changedpython ebjango/manage.py collectstatic --noinput
topython manage.py collectstatic --noinput
(since the python path leads toebdjango
already). But it still doesn't work (server still looks like the 2nd image I posted). Any idea how to debug this issue? -
valignatev about 7 yearsAnswer updated with possible debugging steps, hope it'll help.
-
SilentDev about 7 yearsThe update helped a lot! Now, when I let
STATIC_ROOT = os.path.join(BASE_DIR, "static")
and not mentionstaticfiles
in myoption_settings
config file, it works (default location, as you mentioned)! When I give an absolute or relative path to"aws:elasticbeanstalk:container:python:staticfiles"
inoption_settings
, it works as well. But when I changeSTATIC_ROOT
toos.path.join(BASE_DIR, "..", "www", "static")
and do"/static/": "www/static/"
in myoption_settings
, it gives a 404 for static files. When I let it equal"/static/": "../www/static/"
, it gives a 403 for static. -
SilentDev about 7 yearsI'll mark you're answer as correct when the bounty is about to finish, but for now, any idea why it gives a 403 when I let
STATIC_ROOT
equalos.path.join(BASE_DIR, "..", "www", "static")
? (it does create aebdjango/../www/static/
folder which has therest_framework
staticfiles). -
valignatev about 7 years403 means that some internal web server doesn't have access to this folder. Easiest way to fix it is give this access, but you have to know actual username of this server and it's not convenient. By the way, I consider you use eb instance for static file only as the matter of initial tutorial. Next step would be use S3 bucket for this :)
-
abautista over 4 yearsHello Manu, I am trying to implement your solution but I am unable to find the Static files section under the software configuration. How did you enable the virtual paths?
-
w_hile almost 4 yearsNote: When using Amazon Linux 2, the namespace is aws:elasticbeanstalk:environment:proxy:staticfiles. See the ELB docs.
-
Devin Venable over 3 yearsYour answer is good but may not be clear enough. 1. STATIC_ROOT is your target directory, when collectstatic will pull found static files. I recommend giving a name like 'static_build' for this value. 2. Run collect static locally and commit all files in static_build to your source tree. 3. Set STATIC FILES value per Virtual Path in AWS or via .ebextensions/django.config. This requires less configuration than trying to configure the server to run collectstatic each time it deploys.