1Using WhiteNoise with Django
2============================
3
4.. note:: To use WhiteNoise with a non-Django application see the
5   :doc:`generic WSGI documentation <base>`.
6
7This guide walks you through setting up a Django project with WhiteNoise.
8In most cases it shouldn't take more than a couple of lines of configuration.
9
10I mention Heroku in a few places as that was the initial use case which prompted me
11to create WhiteNoise, but there's nothing Heroku-specific about WhiteNoise and the
12instructions below should apply whatever your hosting platform.
13
141. Make sure *staticfiles* is configured correctly
15----------------------------------------------------
16
17If you're familiar with Django you'll know what to do. If you're just getting started
18with a new Django project then you'll need add the following to the bottom of your
19``settings.py`` file:
20
21.. code-block:: python
22
23   STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
24
25As part of deploying your application you'll need to run ``./manage.py collectstatic`` to
26put all your static files into ``STATIC_ROOT``. (If you're running on Heroku then
27this is done automatically for you.)
28
29Make sure you're using the static_ template tag to refer to your static files,
30rather that writing the URL directly. For example:
31
32.. code-block:: django
33
34   {% load static %}
35   <img src="{% static "images/hi.jpg" %}" alt="Hi!" />
36
37   <!-- DON'T WRITE THIS -->
38   <img src="/static/images/hi.jpg" alt="Hi!" />
39
40For further details see the Django `staticfiles
41<https://docs.djangoproject.com/en/stable/howto/static-files/>`_ guide.
42
43.. _static: https://docs.djangoproject.com/en/stable/ref/templates/builtins/#std:templatetag-static
44
45
46.. _django-middleware:
47
482. Enable WhiteNoise
49--------------------
50
51Edit your ``settings.py`` file and add WhiteNoise to the ``MIDDLEWARE`` list.
52The WhiteNoise middleware should be placed directly after the Django `SecurityMiddleware
53<https://docs.djangoproject.com/en/stable/ref/middleware/#module-django.middleware.security>`_
54(if you are using it) and before all other middleware:
55
56.. code-block:: python
57
58   MIDDLEWARE = [
59     'django.middleware.security.SecurityMiddleware',
60     'whitenoise.middleware.WhiteNoiseMiddleware',
61     # ...
62   ]
63
64That's it -- WhiteNoise will now serve your static files. However, to get the
65best performance you should proceed to step 3 below and enable compression and
66caching.
67
68.. note:: You might find other third-party middleware that suggests it should
69   be given highest priority at the top of the middleware list. Unless you
70   understand exactly what is happening you should ignore this advice and always
71   place ``WhiteNoiseMiddleware`` above other middleware. If you plan to have other
72   middleware run before WhiteNoise you should be aware of the
73   `request_finished bug <https://code.djangoproject.com/ticket/29069>`_ in
74   Django.
75
76
77.. _compression-and-caching:
78
793. Add compression and caching support
80--------------------------------------
81
82WhiteNoise comes with a storage backend which automatically takes care of
83compressing your files and creating unique names for each version so they can
84safely be cached forever. To use it, just add this to your ``settings.py``:
85
86.. code-block:: python
87
88   STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
89
90This combines automatic compression with the caching behaviour provided by
91Django's ManifestStaticFilesStorage_ backend. If you want to apply compression
92but don't want the caching behaviour then you can use:
93
94.. code-block:: python
95
96   STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
97
98.. note:: If you are having problems after switching to the WhiteNoise storage
99   backend please see the :ref:`troubleshooting guide <storage-troubleshoot>`.
100
101.. _ManifestStaticFilesStorage: https://docs.djangoproject.com/en/stable/ref/contrib/staticfiles/#manifeststaticfilesstorage
102
103If you need to compress files outside of the static files storage system you can
104use the supplied :ref:`command line utility <cli-utility>`
105
106
107.. _brotli-compression:
108
109Brotli compression
110++++++++++++++++++
111
112As well as the common gzip compression format, WhiteNoise supports the newer,
113more efficient `brotli <https://en.wikipedia.org/wiki/Brotli>`_ format. This
114helps reduce bandwidth and increase loading speed. To enable brotli
115compression you will need the `Brotli Python package <https://pypi.org/project/Brotli/>`_
116installed by running ``pip install whitenoise[brotli]``.
117
118Brotli is supported by `all major browsers <https://caniuse.com/#feat=brotli>`_
119(except IE11). WhiteNoise will only serve brotli data to browsers which request
120it so there are no compatibility issues with enabling brotli support.
121
122Also note that browsers will only request brotli data over an HTTPS connection.
123
124
125.. _cdn:
126
1274. Use a Content-Delivery Network
128---------------------------------
129
130The above steps will get you decent performance on moderate traffic sites, however
131for higher traffic sites, or sites where performance is a concern you should look
132at using a CDN.
133
134Because WhiteNoise sends appropriate cache headers with your static content, the CDN
135will be able to cache your files and serve them without needing to contact your
136application again.
137
138Below are instruction for setting up WhiteNoise with Amazon CloudFront, a popular
139choice of CDN. The process for other CDNs should look very similar though.
140
141Instructions for Amazon CloudFront
142++++++++++++++++++++++++++++++++++
143
144Go to CloudFront section of the AWS Web Console, and click "Create
145Distribution". Put your application's domain (without the http prefix) in the
146"Origin Domain Name" field and leave the rest of the settings as they are.
147
148It might take a few minutes for your distribution to become active. Once it's
149ready, copy the distribution domain name into your ``settings.py`` file so it
150looks something like this:
151
152.. code-block:: python
153
154   STATIC_HOST = 'https://d4663kmspf1sqa.cloudfront.net' if not DEBUG else ''
155   STATIC_URL = STATIC_HOST + '/static/'
156
157Or, even better, you can avoid hardcoding your CDN into your settings by doing something like this:
158
159.. code-block:: python
160
161   STATIC_HOST = os.environ.get('DJANGO_STATIC_HOST', '')
162   STATIC_URL = STATIC_HOST + '/static/'
163
164This way you can configure your CDN just by setting an environment variable.
165For apps on Heroku, you'd run this command
166
167.. code-block:: bash
168
169   heroku config:set DJANGO_STATIC_HOST=https://d4663kmspf1sqa.cloudfront.net
170
171
172.. note::
173
174    By default your entire site will be accessible via the CloudFront URL. It's
175    possible that this can cause SEO problems if these URLs start showing up in
176    search results.  You can restrict CloudFront to only proxy your static
177    files by following :ref:`these directions <restricting-cloudfront>`.
178
179
180.. _runserver-nostatic:
181
1825. Using WhiteNoise in development
183----------------------------------
184
185In development Django's ``runserver`` automatically takes over static file
186handling. In most cases this is fine, however this means that some of the improvements
187that WhiteNoise makes to static file handling won't be available in development and it
188opens up the possibility for differences in behaviour between development and production
189environments. For this reason it's a good idea to use WhiteNoise in development as well.
190
191You can disable Django's static file handling and allow WhiteNoise to take over
192simply by passing the ``--nostatic`` option to the ``runserver`` command, but
193you need to remember to add this option every time you call ``runserver``. An
194easier way is to edit your ``settings.py`` file and add
195``whitenoise.runserver_nostatic`` to the top of your ``INSTALLED_APPS`` list:
196
197.. code-block:: python
198
199   INSTALLED_APPS = [
200       'whitenoise.runserver_nostatic',
201       'django.contrib.staticfiles',
202       # ...
203   ]
204
205.. note::
206
207    In older versions of WhiteNoise (below v4.0) it was not possible to use
208    ``runserver_nostatic`` with  `Channels`_ as Channels provides its own
209    implementation of runserver. Newer versions of WhiteNoise do not have this
210    problem and will work with Channels or any other third-party app that
211    provides its own implementation of runserver.
212
213.. _Channels: https://channels.readthedocs.io/
214
215
216.. _index-files-django:
217
2186. Index Files
219--------------
220
221When the :any:`WHITENOISE_INDEX_FILE` option is enabled:
222
223* Visiting ``/example/`` will serve the file at ``/example/index.html``
224* Visiting ``/example`` will redirect (302) to ``/example/``
225* Visiting ``/example/index.html`` will redirect (302) to ``/example/``
226
227If you want to something other than ``index.html`` as the index file, then you
228can also set this option to an alternative filename.
229
230
231Available Settings
232------------------
233
234The WhiteNoiseMiddleware class takes all the same configuration options as the
235WhiteNoise base class, but rather than accepting keyword arguments to its
236constructor it uses Django settings. The setting names are just the keyword
237arguments upper-cased with a 'WHITENOISE\_' prefix.
238
239
240.. attribute:: WHITENOISE_ROOT
241
242    :default: ``None``
243
244    Absolute path to a directory of files which will be served at the root of
245    your application (ignored if not set).
246
247    Don't use this for the bulk of your static files because you won't benefit
248    from cache versioning, but it can be convenient for files like
249    ``robots.txt`` or ``favicon.ico`` which you want to serve at a specific
250    URL.
251
252.. attribute:: WHITENOISE_AUTOREFRESH
253
254    :default: ``settings.DEBUG``
255
256    Recheck the filesystem to see if any files have changed before responding.
257    This is designed to be used in development where it can be convenient to
258    pick up changes to static files without restarting the server. For both
259    performance and security reasons, this setting should not be used in
260    production.
261
262.. attribute:: WHITENOISE_USE_FINDERS
263
264    :default: ``settings.DEBUG``
265
266    Instead of only picking up files collected into ``STATIC_ROOT``, find and
267    serve files in their original directories using Django's "finders" API.
268    This is useful in development where it matches the behaviour of the old
269    ``runserver`` command. It's also possible to use this setting in
270    production, avoiding the need to run the ``collectstatic`` command during
271    the build, so long as you do not wish to use any of the caching and
272    compression features provided by the storage backends.
273
274.. attribute:: WHITENOISE_MAX_AGE
275
276    :default: ``60 if not settings.DEBUG else 0``
277
278    Time (in seconds) for which browsers and proxies should cache **non-versioned** files.
279
280    Versioned files (i.e. files which have been given a unique name like *base.a4ef2389.css* by
281    including a hash of their contents in the name) are detected automatically and set to be
282    cached forever.
283
284    The default is chosen to be short enough not to cause problems with stale versions but
285    long enough that, if you're running WhiteNoise behind a CDN, the CDN will still take
286    the majority of the strain during times of heavy load.
287
288
289.. attribute:: WHITENOISE_INDEX_FILE
290
291    :default: ``False``
292
293    If ``True`` enable :ref:`index file serving <index-files-django>`. If set to a non-empty
294    string, enable index files and use that string as the index file name.
295
296
297.. attribute:: WHITENOISE_MIMETYPES
298
299    :default: ``None``
300
301    A dictionary mapping file extensions (lowercase) to the mimetype for that
302    extension. For example: ::
303
304        {'.foo': 'application/x-foo'}
305
306    Note that WhiteNoise ships with its own default set of mimetypes and does
307    not use the system-supplied ones (e.g. ``/etc/mime.types``). This ensures
308    that it behaves consistently regardless of the environment in which it's
309    run.  View the defaults in the :file:`media_types.py
310    <whitenoise/media_types.py>` file.
311
312    In addition to file extensions, mimetypes can be specified by supplying the entire
313    filename, for example: ::
314
315        {'some-special-file': 'application/x-custom-type'}
316
317
318.. attribute:: WHITENOISE_CHARSET
319
320    :default: ``'utf-8'``
321
322    Charset to add as part of the ``Content-Type`` header for all files whose
323    mimetype allows a charset.
324
325
326.. attribute:: WHITENOISE_ALLOW_ALL_ORIGINS
327
328    :default: ``True``
329
330    Toggles whether to send an ``Access-Control-Allow-Origin: *`` header for all
331    static files.
332
333    This allows cross-origin requests for static files which means your static files
334    will continue to work as expected even if they are served via a CDN and therefore
335    on a different domain. Without this your static files will *mostly* work, but you
336    may have problems with fonts loading in Firefox, or accessing images in canvas
337    elements, or other mysterious things.
338
339    The W3C `explicitly state`__ that this behaviour is safe for publicly
340    accessible files.
341
342.. __: https://www.w3.org/TR/cors/#security
343
344
345.. attribute:: WHITENOISE_SKIP_COMPRESS_EXTENSIONS
346
347    :default: ``('jpg', 'jpeg', 'png', 'gif', 'webp','zip', 'gz', 'tgz', 'bz2', 'tbz', 'xz', 'br', 'swf', 'flv', 'woff', 'woff2')``
348
349    File extensions to skip when compressing.
350
351    Because the compression process will only create compressed files where
352    this results in an actual size saving, it would be safe to leave this list
353    empty and attempt to compress all files. However, for files which we're
354    confident won't benefit from compression, it speeds up the process if we
355    just skip over them.
356
357
358.. attribute:: WHITENOISE_ADD_HEADERS_FUNCTION
359
360    :default: ``None``
361
362    Reference to a function which is passed the headers object for each static file,
363    allowing it to modify them.
364
365    For example: ::
366
367        def force_download_pdfs(headers, path, url):
368            if path.endswith('.pdf'):
369                headers['Content-Disposition'] = 'attachment'
370
371        WHITENOISE_ADD_HEADERS_FUNCTION = force_download_pdfs
372
373    The function is passed:
374
375    headers
376      A `wsgiref.headers`__ instance (which you can treat just as a dict) containing
377      the headers for the current file
378
379    path
380      The absolute path to the local file
381
382    url
383      The host-relative URL of the file e.g. ``/static/styles/app.css``
384
385    The function should not return anything; changes should be made by modifying the
386    headers dictionary directly.
387
388.. __: https://docs.python.org/3/library/wsgiref.html#module-wsgiref.headers
389
390
391.. attribute:: WHITENOISE_IMMUTABLE_FILE_TEST
392
393    :default: See :file:`immutable_file_test <whitenoise/middleware.py#L121>` in source
394
395    Reference to function, or string.
396
397    If a reference to a function, this is passed the path and URL for each
398    static file and should return whether that file is immutable, i.e.
399    guaranteed not to change, and so can be safely cached forever. The default
400    is designed to work with Django's ManifestStaticFilesStorage backend, and
401    any derivatives of that, so you should only need to change this if you are
402    using a different system for versioning your static files.
403
404    If a string, this is treated as a regular expression and each file's URL is
405    matched against it.
406
407    Example: ::
408
409        def immutable_file_test(path, url):
410            # Match filename with 12 hex digits before the extension
411            # e.g. app.db8f2edc0c8a.js
412            return re.match(r'^.+\.[0-9a-f]{12}\..+$', url)
413
414        WHITENOISE_IMMUTABLE_FILE_TEST = immutable_file_test
415
416    The function is passed:
417
418    path
419      The absolute path to the local file
420
421    url
422      The host-relative URL of the file e.g. ``/static/styles/app.css``
423
424
425.. attribute:: WHITENOISE_STATIC_PREFIX
426
427    :default: Path component of ``settings.STATIC_URL`` (with
428              ``settings.FORCE_SCRIPT_NAME`` removed if set)
429
430    The URL prefix under which static files will be served.
431
432    Usually this can be determined automatically by using the path component of
433    ``STATIC_URL``. So if ``STATIC_URL`` is ``https://example.com/static/``
434    then ``WHITENOISE_STATIC_PREFIX`` will be ``/static/``.
435
436    If your application is not running at the root of the domain and
437    ``FORCE_SCRIPT_NAME`` is set then this value will be removed from the
438    ``STATIC_URL`` path first to give the correct prefix.
439
440    If your deployment is more complicated than this (for instance, if you are
441    using a CDN which is doing path rewriting) then you may need to configure
442    this value directly.
443
444
445.. attribute:: WHITENOISE_KEEP_ONLY_HASHED_FILES
446
447    :default: ``False``
448
449    Stores only files with hashed names in ``STATIC_ROOT``.
450
451    By default, Django's hashed static files system creates two copies of each
452    file in ``STATIC_ROOT``: one using the original name, e.g. ``app.js``, and
453    one using the hashed name, e.g. ``app.db8f2edc0c8a.js``. If WhiteNoise's
454    compression backend is being used this will create another two copies of
455    each of these files (using Gzip and Brotli compression) resulting in six
456    output files for each input file.
457
458    In some deployment scenarios it can be important to reduce the size of the
459    build artifact as much as possible.  This setting removes the "un-hashed"
460    version of the file (which should be not be referenced in any case) which
461    should reduce the space required for static files by half.
462
463    Note, this setting is only effective if the WhiteNoise storage backend is
464    being used.
465
466
467Additional Notes
468----------------
469
470
471Django Compressor
472+++++++++++++++++
473
474For performance and security reasons WhiteNoise does not check for new
475files after startup (unless using Django `DEBUG` mode). As such, all static
476files must be generated in advance. If you're using Django Compressor, this
477can be performed using its `offline compression`_ feature.
478
479.. _offline compression: https://django-compressor.readthedocs.io/en/latest/usage/#offline-compression
480
481--------------------------------------------------------------------------
482
483
484Serving Media Files
485+++++++++++++++++++
486
487WhiteNoise is not suitable for serving user-uploaded "media" files. For one
488thing, as described above, it only checks for static files at startup and so
489files added after the app starts won't be seen. More importantly though,
490serving user-uploaded files from the same domain as your main application is a
491security risk (this `blog post`_ from Google security describes the problem
492well). And in addition to that, using local disk to store and serve your user
493media makes it harder to scale your application across multiple machines.
494
495For all these reasons, it's much better to store files on a separate dedicated
496storage service and serve them to users from there. The `django-storages`_
497library provides many options e.g. Amazon S3, Azure Storage, and Rackspace
498CloudFiles.
499
500.. _blog post: https://security.googleblog.com/2012/08/content-hosting-for-modern-web.html
501.. _django-storages: https://django-storages.readthedocs.io/
502
503--------------------------------------------------------------------------
504
505
506.. _storage-troubleshoot:
507
508Troubleshooting the WhiteNoise Storage backend
509++++++++++++++++++++++++++++++++++++++++++++++
510
511If you're having problems with the WhiteNoise storage backend, the chances are
512they're due to the underlying Django storage engine. This is because WhiteNoise
513only adds a thin wrapper around Django's storage to add compression support,
514and because the compression code is very simple it generally doesn't cause
515problems.
516
517The most common issue is that there are CSS files which reference other files
518(usually images or fonts) which don't exist at that specified path. When Django
519attempts to rewrite these references it looks for the corresponding file and
520throws an error if it can't find it.
521
522To test whether the problems are due to WhiteNoise or not, try swapping the WhiteNoise
523storage backend for the Django one:
524
525.. code-block:: python
526
527   STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
528
529If the problems persist then your issue is with Django itself (try the docs_ or
530the `mailing list`_). If the problem only occurs with WhiteNoise then raise a
531ticket on the `issue tracker`_.
532
533.. _docs: https://docs.djangoproject.com/en/stable/ref/contrib/staticfiles/
534.. _mailing list: https://groups.google.com/d/forum/django-users
535.. _issue tracker: https://github.com/evansd/whitenoise/issues
536
537--------------------------------------------------------------------------
538
539
540.. _restricting-cloudfront:
541
542Restricting CloudFront to static files
543++++++++++++++++++++++++++++++++++++++
544
545The instructions for setting up CloudFront given above will result in the
546entire site being accessible via the CloudFront URL. It's possible that this
547can cause SEO problems if these URLs start showing up in search results.  You
548can restrict CloudFront to only proxy your static files by following these
549directions:
550
551
552 1. Go to your newly created distribution and click "*Distribution Settings*", then
553    the "*Behaviors*" tab, then "*Create Behavior*". Put ``static/*`` into the path pattern and
554    click "*Create*" to save.
555
556 2. Now select the ``Default (*)`` behaviour and click "*Edit*". Set "*Restrict Viewer Access*"
557    to "*Yes*" and then click "*Yes, Edit*" to save.
558
559 3. Check that the ``static/*`` pattern is first on the list, and the default one is second.
560    This will ensure that requests for static files are passed through but all others are blocked.
561
562
563Using other storage backends
564++++++++++++++++++++++++++++
565
566WhiteNoise will only work with storage backends that stores their files on the
567local filesystem in ``STATIC_ROOT``. It will not work with backends that store
568files remotely, for instance on Amazon S3.
569
570
571WhiteNoise makes my tests run slow!
572+++++++++++++++++++++++++++++++++++
573
574WhiteNoise is designed to do as much work as possible upfront when the
575application starts so that it can serve files as efficiently as possible while
576the application is running. This makes sense for long-running production
577processes, but you might find that the added startup time is a problem during
578test runs when application instances are frequently being created and
579destroyed.
580
581The simplest way to fix this is to make sure that during testing the
582``WHITENOISE_AUTOREFRESH`` setting is set to ``True``. (By default it is
583``True`` when ``DEBUG`` is enabled and ``False`` otherwise.) This stops
584WhiteNoise from scanning your static files on start up but other than that its
585behaviour should be exactly the same.
586
587It is also worth making sure you don't have unnecessary files in your
588``STATIC_ROOT`` directory.  In particular, be careful not to include a
589``node_modules`` directory which can contain a very large number of files and
590significantly slow down your application startup. If you need to include
591specific files from ``node_modules`` then you can create symlinks from within
592your static directory to just the files you need.
593
594
595Why do I get "ValueError: Missing staticfiles manifest entry for ..."?
596++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
597
598If you are seeing this error that you means you are referencing a static file in your
599templates (using something like ``{% static "foo" %}`` which doesn't exist, or
600at least isn't where Django expects it to be. If you don't understand why Django can't
601find the file you can use
602
603.. code-block:: sh
604
605   python manage.py findstatic --verbosity 2 foo
606
607which will show you all the paths which Django searches for the file "foo".
608
609If, for some reason, you want Django to silently ignore such errors you can subclass
610the storage backend and set the manifest_strict_ attribute to ``False``.
611
612.. _manifest_strict: https://docs.djangoproject.com/en/stable/ref/contrib/staticfiles/#django.contrib.staticfiles.storage.ManifestStaticFilesStorage.manifest_strict
613
614
615Using WhiteNoise with Webpack / Browserify / $LATEST_JS_THING
616+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
617
618A simple technique for integrating any frontend build system with Django is to
619use a directory layout like this:
620
621.. code-block:: sh
622
623   ./static_src
624625     $ ./node_modules/.bin/webpack
626627   ./static_build
628629     $ ./manage.py collectstatic
630631   ./static_root
632
633Here ``static_src`` contains all the source files (JS, CSS, etc) for your
634project. Your build tool (which can be Webpack, Browserify or whatever you
635choose) then processes these files and writes the output into ``static_build``.
636
637The path to the ``static_build`` directory is added to ``settings.py``:
638
639.. code-block:: python
640
641   STATICFILES_DIRS = [
642       os.path.join(BASE_DIR, 'static_build')
643   ]
644
645This means that Django can find the processed files, but doesn't need to know anything
646about the tool which produced them.
647
648The final ``manage.py collectstatic`` step writes "hash-versioned" and
649compressed copies of the static files into ``static_root`` ready for
650production.
651
652Note, both the ``static_build`` and ``static_root`` directories should be
653excluded from version control (e.g. through ``.gitignore``) and only the
654``static_src`` directory should be checked in.
655
656
657Deploying an application which is not at the root of the domain
658+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
659
660Sometimes Django apps are deployed at a particular prefix (or "subdirectory")
661on a domain e.g. http://example.com/my-app/ rather than just http://example.com.
662
663In this case you would normally use Django's `FORCE_SCRIPT_NAME
664<https://docs.djangoproject.com/en/1.11/ref/settings/#force-script-name>`_
665setting to tell the application where it is located. You would also need to
666ensure that ``STATIC_URL`` uses the correct prefix as well. For example:
667
668.. code-block:: python
669
670   FORCE_SCRIPT_NAME = '/my-app'
671   STATIC_URL = FORCE_SCRIPT_NAME + '/static/'
672
673If you have set these two values then WhiteNoise will automatically configure
674itself correctly. If you are doing something more complex you may need to set
675:any:`WHITENOISE_STATIC_PREFIX` explicitly yourself.
676