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 624 ↓ 625 $ ./node_modules/.bin/webpack 626 ↓ 627 ./static_build 628 ↓ 629 $ ./manage.py collectstatic 630 ↓ 631 ./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