MikeJamesHamm

Student, Developer, Technology Advocate
Welcome to my personal website



Guide: Setting up an HTTPS secured Django website

on Jan. 5, 2017, 7:41 p.m.

Unfortunately, setting up your own web-server for a Django website can be very frustrating. For example, initially configuring this website took me around 15 hours of tinkering to finally be at a point where I could even begin migrating my Django project files. That is why I made this guide of how I setup my website! DigitalOcean is a great hosting service but unfortunately there is only one-click installs for Python 2.7 Django and Ubuntu 14.04. If you're like me, I always like to use the most current version of any program or language I use. There are a few guides on the web for this sort of thing already but I still had to figure out a ton on my own. Some things you are going to need to get started is a domain name and an empty DigitalOcean Ubuntu 16.04 web-server. Purchasing the server is as easy as going to the DigitalOcean website and purchasing a droplet. It is very easy to setup and they have a wide-variety of price ranges. If you wanted to purchase a server for a few minutes to complete this guide it would cost you a couple of cents. Here is an example of the server options I chose.

The first thing you are going to want to do is SSH into your DigitalOcean web-server. On Linux or OSx operating systems that is as easy as opening the application, "terminal", and entering in the following command. If you are using Windows you are most likely going to need to download an application to do that. I would recommend downloading Putty. Note: be sure to subsitute in your server's IP address. You can find your IP address in the droplets section here.


ssh root@192.34.56.81

When attempting to SSH into your new server you may get a message like this. Type yes and continue.

Next we are going to install the necessary packages to build our website.


sudo apt-get update
sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx

Now we are going to need to setup a database to store our information. Django projects come with an SQLite database but I prefer to use Postresql. Be sure to plug in your own values in the project and username fields. I would also recommend randomly generating a password for your database with a website like this.


sudo -u postgres psql
CREATE DATABASE myproject;
CREATE USER myprojectuser WITH PASSWORD '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

The next thing to do is setup a folder where we can put all of our websites project files. After the next commands you should be in the directory, "/home/myproject/".


sudo pip3 install virtualenv
cd /home/
mkdir myproject
cd myproject

Now we are going to setup our own virtual enviroment. This is very useful when dealing with project dependencies in Python. For example, if you wanted to host two websites on the same server you could have two different virtual enviroments to handle each of the projects dependencies. That way if you need version 2.0 of module X for one site and 1.5 on another you can have both installed. Whenever you are installing packages with a virtualenv make sure to type pip and not pip3.


virtualenv myprojectenv
source myprojectenv/bin/activate
pip install django gunicorn psycopg2

And now we are ready to create our Django project. You should be in the directory, "/home/myproject/", when entering the following commands.


django-admin.py startproject myproject .
vim myproject/settings.py

Next we will need to update our Django project settings. You should update the DATABASES variable with the correct Postgresql information we generated earlier. Also, at the end of the file make sure to add the STATIC_ROOT variable. STATIC_ROOT will just represent the location of all of your static files for your Django project.


DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'myproject',
'USER': 'myprojectuser',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '',
}
}

...
...
...

STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

After that is all setup, we should change directories to our Django project. Make sure you are in the same directory as the manage.py file and enter in the following commands. There are various commands that you can use of the manage.py file and most are neccessary to continue developing your website. Become familiar with it. Now we are going to setup our Gunicorn service file.


cd /home/myproject
./manage.py makemigrations
./manage.py migrate
./manage.py createsuperuser
./manage.py collectstatic
deactivate
sudo vim /etc/systemd/system/gunicorn.service

Once Vim is open, enter the following information.


[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=root
Group=www-data
WorkingDirectory=/home/myproject
ExecStart=/home/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:/home/myproject/myproject.sock myproject.wsgi:application

[Install]
WantedBy=multi-user.target

Now we are ready to start gunicorn!


sudo systemctl start gunicorn
sudo systemctl enable gunicorn

Assuming you want to secure your website with HTTPS, continue with the following commands. I would highly recommend doing this as many websites now get a security warning from your browser if the site is only HTTP. We will be using LetsEncrypt, a free open-source project for generating HTTPS certificates.


cd /home/myproject
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
service nginx stop
./letsencrypt-auto certonly --standalone -d example.com

Next we are going to configure our Nginx virtual server. Now open the file with vim.


sudo vim /etc/nginx/sites-available/myproject

Basically this file is telling the server where our certificates are located, the location of our project files, and any redirects we will want to have. For example, since our site is secured with HTTPS, we want to redirect any HTTP requests to be HTTPS. I also like to redirect any url with www. inside of it to just the plain URL. You can configure and play around with this file any way you want.


server {
listen 443 ssl;
server_name example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/myproject;
}

location / {
include proxy_params;
proxy_pass http://unix:/home/myproject/myproject.sock;
}
}

server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl;
server_name www.example.com;
return 301 http://example.com$request_uri;
}

server {
listen 80;
server_name www.example.com;
return 301 http://example.com$request_uri;
}

Now you are ready to point your domain to your DigitalOcean server. All you need to do is go to your website registrar and edit the DNS settings. Point your settings to the digital ocean name servers (something like ns1.digitalocean.com) and now your domain will be ready to use. Make sure to also setup an A-record with your droplet by hovering over the droplet and clicking "add a domain". Now your ready to restart your server and begin working on your site!


service nginx restart




The code listed above may or may not be the "best" solution. Please be advised that this is just the way I did it. There are normally thousands of different ways to solve the same programming problem. Find an error? Let me know in the contact form below.




Contact Me

Feel free to email me feedback, suggestions, notes, or to just say hello!