Deploying Django app on Ubuntu at digitalocean + SSL certificate 🇬🇧¶
It can be quite frustrating/challenging for django newbies to deploy their app because a bunch of new concepts should be known in order to play the game with confidence. This tutorial gives you all the basics and further reference. The structure of the project can be seen in the following screenshot: the project my_blog
is itself located in the blog
folder.
Deployment in a nutshell¶
You need
a web server (often Nginx or apache) to handle http requests
an application server called gunicorn to serve your django app (the middle layer)
a django app
a database management system (often mysql or postgresql) to store information.
sometimes a firewall system to block some requests
Step by step¶
A server/droplet on digitalocean with often a Linux system as Ubuntu¶
Note, some tutorials said that a password would be sent to your email. This is outdated, remember, for an easy start, to choose the password method and set your password as follows. The 5$ plan is largely sufficient for personal use.
A regular user with some root privileges¶
For our purpose you just need the following steps:
First connect to the server using ssh, on Mac you are good to go already on Windows you can use PuTTy
, see the reference
ref https://www.digitalocean.com/docs/droplets/how-to/connect-with-ssh/
ssh root@your_server_ip
The server ip can be seen here
Then add a regular user with root privileges
ref https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-16-04
adduser sammy # add a user
usermod -aG sudo sammy # give sammy root privileges
Now log out and log in this regular user
ssh sammy@your_server_ip
Update apt-get to install the most recent packages¶
Here we install pip, postgresql (database tool) and nginx (web server). In simple terms, nginx
is the server who takes http requests, another common server is apache
.
sudo apt-get update
sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx
Set up the database¶
First log into postgresql
sudo -u postgres psql
Then create a database, user and password.
CREATE DATABASE yourproject; # replace yourproject with your database name
CREATE USER myprojectuser WITH PASSWORD 'password'; # set username and password
ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
ALTER ROLE myprojectuser SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
\q # quit
Add the database setting set up in step 4 into your Settings.py
on your local computer¶
if DEBUG:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'yourdatabasename',
'USER': 'yourdatabaseuser',
'PASSWORD': 'yourdatabasepassword',
'HOST': 'localhost',
'PORT': '',
}
}
Set up a virtual environment for Python¶
sudo -H pip3 install --upgrade pip
sudo -H pip3 install virtualenv
Since my website’s source code is hosted on github I will use git to clone the project into the folder blog
.
Run pip freeze > requirements.txt
on your local computer then use pip install -r requirements.txt
to install dependencies for your app. Remember to run pip install psycopg2-binary gunicorn
to have these two packages in the requirements.txt
.
Also add your service ip in ALLOWED_HOSTS
of your globalsettings.py
Update your git repository, be sure to have uploaded the most recent requirements.txt
. Then get the repository on the server by running:
git clone yourrepository blog
cd blog
git config credential.helper store # remember your username and password
And then create a virtualenv named env
and activate it
virtualenv env
source env/bin/activate
pip install -r requirements.txt
Run migrate¶
python manage.py makemigrations
python manage.py migrate
Test on 8000 port with and without gunicorn¶
sudo ufw allow 8000 # allow 8000 in the firewall
python manage.py runserver 0.0.0.0:8000
Go to http://server_domain_or_IP:8000, it’s very important to use http since you haven’t set ssl certificate (no https support)
Now test the gunicorn. Gunicorn is an application server
which serves your django app.
gunicorn --bind 0.0.0.0:8000 my_blog.wsgi
Set up Gunicorn service file¶
I use vim here, but you are free to use some more beginner-friendly editor like nano. The gunicorn service file is to ensure that gunicorn is run automatically in background to serve django
sudo vim /etc/systemd/system/gunicorn.service
An example service file using sammy as user looks as follows:
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/blog
ExecStart=/home/sammy/blog/env/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/sammy/my_blog.sock my_blog.wsgi:application
[Install]
WantedBy=multi-user.target
Now, start gunicorn!
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
Set Nginx¶
sudo vim /etc/nginx/sites-available/blog
An example setting looks as following
server {
server_name 142.93.110.76;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/sammy/blog;
}
location /media/ {
root /home/sammy/media;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/sammy/my_blog.sock;
}
}
Make a symbolic link to make your setting available to nginx
sudo ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled
Test and start your Nginx server, you are good to go!
sudo nginx -t
sudo systemctl restart nginx
# stop 8000 port in the firewall
sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'
Add a ssl certificate to make https available¶
Almost nobody uses http these days. Let’s now see how to secure our site by adding a ssl certificate!
To have a more solid grasp on ssl certificate, see reference here.
sudo apt install certbot python3-certbot-nginx # install some useful packages
sudo vim /etc/nginx/sites-available/blog
Change the server_name line, example:
server_name 142.93.110.76 nlpinpython.com www.nlpinpython.com;
Restart Nginx and allow https in the firewall:
sudo systemctl reload nginx
sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'
Get a ssl certificat
sudo certbot --nginx -d nlpinpython.com -d www.nlpinpython.com
At the last step, select redirect
Congratulations to make it this far.
Most useful commands:¶
# set up nginx
sudo vim /etc/nginx/sites-available/blog
# set up gunicorn
sudo vim /etc/systemd/system/gunicorn.service
# restart gunicorn after change
sudo systemctl restart gunicorn
# restart nginx
sudo systemctl restart nginx
Export your database for backup:
sudo -i -u postgres -W
pg_dump dbname > dbexport.pgsql
Supplementary references:
about firewall https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-ubuntu-18-04
about postgresql backup https://www.digitalocean.com/community/tutorials/how-to-backup-postgresql-databases-on-an-ubuntu-vps
general instructions https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-20-04