Deployment
@dokku @deploy @production @server
This section covers how to deploy the website onto a VPS. There are a few different options here, from manually configuring Apache and WSGI, to using a PaaS like Heroku and Dokku.
Deploying with Dokku
Dokku is nice because once set up, you just push updates to the repo on your server and it all happens pretty automatically. However setting it up is a pain in the ass.
Also, the bible: https://cheat.readthedocs.io/en/latest/django/dokku.html
TIPS:
- Make sure your migrations are in your repo. Do not exclude them
- You can open a bash shell to the running container by doing: dokku enter <appname> where appname is your DOKKU app name, NOT THE LOCAL DJANGO NAME
- Run any command using dokku run <appname> <command> e.g. dokku run mtnpak python manage.py collectstatic
- You can see a live view of the dokku logs by doing on the server: dokku logs <appname> --tail
- Setting up the PostgreSQL database is kind of a pain. Make sure your settings.py is correct
1) Installing Dokku
Installing is pretty easy, You can check on the official repo, or just follow these instructions:
$ wget https://raw.githubusercontent.com/dokku/dokku/v0.21.4/bootstrap.sh
$ sudo DOKKU_TAG=v0.21.4 bash bootstrap.sh
Replace the value for DOKKU_TAG with the current version
2) Adding SSH keys and allowing host
You need to now visit the ip address of your remote machine in a browser, and in the Dokku form, paste your SSH public key.
Then you must allow the dokku user to log in via ssh:
$ sudo nano /etc/ssh/sshd_config
# Add the dokku user to the following line
AllowUsers faaiz dokku
Finally, as of writing this (August 2020) Dokku is weird in that it does not correctly set up the keys. I think this has something to do with the fact that I already use the same key for the faaiz user when I set up the VPS. Either way, you need to first check if dokku has any keys, then use dokku to add them if not:
# Check if there are any keys
$ dokku ssh-keys:list
# Chances are you'll get an error like:
/home/dokku/.ssh/authorized_keys line 1 failed ssh-keygen check.
# or
No public keys found
# So what you need to do now, is delete that authorized_key file for the dokku user if there is one, copy your public key to some location on the server, and point dokku to it. You can pick your own key name
$ sudo dokku ssh-keys:add <name_for_key> /path/to/key
# Example of what I did
$ sudo dokku ssh-keys:add fa0 /home/faaiz/fa0-ssh-key
Now you can test if this worked by seeing if you can SSH as the dokku user:
$ ssh dokku@<your_server>
# Example: I've set up my sshd_config to use port 333 for ssh, and use the hostname fa1
$ ssh dokku@fa1
# Output should be a bunch of dokku related help messages, then connection closes automatically. If this happens, then your SSH is working.
3) Creating Dokku app and PostgreSQL database
Create a Dokku app and install the plugin for postgres
# Create app
$ dokku apps:create <appname>
# install postgres plugin
$ sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git
# create a db
dokku postgres:create <dbname>
# link db to app
dokku postgres:link <dbname> <appname>
4) Configure domains and add repository
In your server running Dokku, you want to add your domains for some reason (I don't understand this, since I do my domain stuff on Vultr DNS) but in any case, this is how they want you to do it:
Then you need to go to your local machine and add your remote repository. You will push to this when you want to deploy the website.
IMPORTANT: If you are using a subdomain, make sure to add .domain.tld to your Django ALLOWED_HOSTS to tell it to accept serving from a subdomain. Otherwise it will not. You also need to add domain.tld without the . if you are just trying to serve it from the root domain.
5) Add the correct buildpacks
You need a buildpack for python and for GDAL. For some reason, the documented way doesn't work for me. What I need to do is create a file called .buildpacks in the root of my local project repo, and add to the contents:
https://github.com/heroku/heroku-buildpack-python.git
6) Set up the Procfile
In the root of your local project directory, create a file called Procfile and add to its contents:
# This is the WSGI setting for Gunicorn. Make sure 'MTNPAK.wgsi' is the path to your wsgi.py in dot form, i.e. '/' replaced by '.'
web: gunicorn MTNPAK.wsgi:application
# This runs commands during deploy: make migrations, migrate db, and then load the grades fixture data
release: python manage.py makemigrations; python manage.py migrate --noinput; python manage.py loaddata grades.json
Load whatever else fixtures you need here.
7) Create your Django superuser
Easy enough. Once container is running, do:
dokku run <appname> python manage.py createsuperuser
8) Set up persistent storage for media
http://dokku.viewdocs.io/dokku/advanced-usage/persistent-storage/
IMPORTANT:
Django settings configurations as follows:
MEDIA_URL = '/media/'
Then, on the server, you want to create a folder for your app in:
$ sudo chown -R 32767:32767 /var/lib/dokku/data/storage/<appname>
$ dokku ps:rebuild <appname>
9) Configure Whitenoise to serve static files
DO NOT DO THIS ON HIGH TRAFFIC WEBSITES
http://whitenoise.evans.io/en/stable/django.html
This is a cheap (free) option to let Django serve static files. Obviously, you need to pip3 install whitenoise first and foremost. Then follow the steps below and make changes in settings.py.
You need to make sure that STATIC_ROOT is properly configured in your settings.py :
Then run manage.py collectstatic to collect all your static files to the staticfiles folder
Then add 'whitenoise.middleware.WhiteNoiseMiddleware' to your middleware (should be second in line behind SecurityMiddleware
Add STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' for compression and caching OR
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage' for just compression.
Then, you need to make it such that whitenoise serves static files even when you are using your runserver in development. Do this by adding the following to the TOP of your INSTALLED_APPS :
10) Add SSL certificates
https://github.com/dokku/dokku-letsencrypt
First, install the letsencrypt plugin:
DEPLOY WITH 'git push dokku master:mater'