.. _`going-to-production`: Going to production =================== This section covers everything you need to know before going to production. Django ------ Checks ~~~~~~ Before going to production make sure you have checked everything: 1. Migrations are up-to-date 2. Static files are all present 3. There are no security or other ``django`` warnings Checking migrations, static files, and security is done inside ``ci.sh`` script. We check that there are no unapplied migrations: .. code :: bash python manage.py makemigrations --dry-run --check If you have forgotten to create a migration and changed the model, you will see an error on this line. We also check that static files can be collected: .. code :: bash DJANGO_ENV=production python manage.py collectstatic --no-input --dry-run However, this check does not cover all the cases. Sometimes ``ManifestStaticFilesStorage`` will fail on real cases, but will pass with ``--dry-run`` option. You can disable ``--dry-run`` option if you know what you are doing. Be careful with this option, when working with auto-uploading your static files to any kind of CDNs. That's how we check ``django`` warnings: .. code:: bash DJANGO_ENV=production python manage.py check --deploy --fail-level WARNING These warnings are raised by ``django`` when it detects any configuration issues. This command should give not warnings or errors. It is bundled into ``docker``, so the container will not work with any warnings. Static and media files ~~~~~~~~~~~~~~~~~~~~~~ We use ``/var/www/django`` folder to store our media and static files in production as ``/var/www/django/static`` and ``/var/www/django/media``. Docker uses these two folders as named volumes. And later these volumes are also mounted to ``caddy`` with ``ro`` mode so it possible to read their contents. To find the exact location of these files on your host you will need to do the following: .. code:: bash docker volume ls # to find volumes' names docker volume inspect VOLUME_NAME Sometimes storing your media files inside a container is not a good idea. Use ``CDN`` when you have a lot of user content or it is very important not to lose it. There are `helper libraries `_ to bind ``django`` and these services. If you don't need ``media`` files support, just remove the volumes. Migrations ~~~~~~~~~~ We do run migration in the ``gunicorn.sh`` by default. Why do we do this? Because that's probably the easiest way to do it. But it clearly has some disadvantages: - When scaling your container for multiple nodes you will have multiple threads running the same migrations. And it might be a problem since migrations do not guarantee that it will work this way. - You can perform some operations multiple times - Possible other evil things may happen So, what to do in this case? Well, you can do whatever it takes to run migrations in a single thread. For example, you can create a separate container to do just that. Other options are fine as well. Postgres -------- Sometimes using ``postgres`` inside a container `is not a good idea `_. So, what should be done in this case? First of all, move your database ``docker`` service definition inside ``docker-compose.override.yml``. Doing so will not affect development, but will remove database service from production. Next, you will need to specify `extra_hosts `_ to contain your ``postgresql`` address. Lastly, you would need to add new hosts to ``pg_hba.conf``. `Here `_ is a nice tutorial about this topic. Caddy ----- Let's Encrypt ~~~~~~~~~~~~~ We are using ``Caddy`` and ``Let's Encrypt`` for HTTPS. The Caddy webserver used in the default configuration will get you a valid certificate from ``Let's Encrypt`` and update it automatically. All you need to do to enable this is to make sure that your DNS records are pointing to the server Caddy runs on. Read more: `Automatic HTTPS `_ in Caddy docs. Caddyfile validation ~~~~~~~~~~~~~~~~~~~~ You can also run ``-validate`` command to validate ``Caddyfile`` contents. Here's it would look like: .. code:: bash docker compose -f docker-compose.yml -f docker/docker-compose.prod.yml \ run --rm caddy -validate This check is not included in the pipeline by default, because it is quite long to start all the machinery for this single check. Disabling HTTPS ~~~~~~~~~~~~~~~ You would need to `disable `_ ``https`` inside ``Caddy`` and in production settings for Django. Because Django itself also redirects to ``https``. See `docs `_. You would also need to disable ``manage.py check`` in ``docker/ci.sh``. Otherwise, your application won't start, it would not pass ``django``'s security checks. Disabling WWW subdomain ~~~~~~~~~~~~~~~~~~~~~~~ If you for some reason do not require ``www.`` subdomain, then delete ``www.{$DOMAIN_NAME}`` section from ``Caddyfile``. Third-Level domains ~~~~~~~~~~~~~~~~~~~ You have to disable ``www`` subdomain if your app works on third-level domains like: - ``kira.wemake.services`` - ``support.myapp.com`` Otherwise, ``Caddy`` will server redirects to ``www.example.yourdomain.com``. Further reading --------------- - Django's deployment `checklist `_