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:
Migrations are up-to-date
Static files are all present
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:
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:
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:
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:
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:
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