TL;DR
I used nginx as the http server. I removed the configuration associated with static files in nginx, so the static file requests are passed to the wsgi layer (gunicorn) and are handled by Whitenoise. So you can follow any 'nginx + gunicorn + django' deployment instructions/tutorials, which are easily available with a simple google search.
This post cleared it up for me: Deploying your Django static files to AWS (Part 2).
Long Answer
As mentioned before there are many tutorials about deploying Django + Whitenoise applications on Heroku. As pointed out in the comments:
Heroku, which has its own proxy layer in the front end, and is therefore not at all relevant.
Without verifying this statement, I thought this must be true. gunicorn is not a full fledged webserver. In fact gunicorn creators strongly recommend using it behind a proxy server (Eg. Nginx). See docs.
I was confused because I always thought of Nginx as just a reverse proxy. Functioning as a reverse proxy for static assets is just one of the functions of nginx. It provides a lot more features like buffering slow clients, which gunicorn does not, which helps prevent denial-of-service attacks.
I knew this already. It would have been foolish to not use nginx or any other webserver.
Whitenoise is just there to set proper caching headers for static files and enable compression using gzip/brotli. When used with whitenoise.storage.CompressedManifestStaticFilesStorage
, it will automatically generate versioned static files. Eg. /static/js/app.49ec9402.js
if you have put your file in the template as {%statis%} 'js/app.js'
. A versioned file will have max-age set to 10 years i.e. cached forever.
If you are not deploying on Heroku you will still need a web server like Nginx. So you can follow any 'nginx + gunicorn + django' deployment instructions/tutorials, which are easily available with a simple google search. One of which is Deploying your Django static files to AWS (Part 2), which helped me get this issue sorted out.