How I deployed my Django app to Vultr VPS
Tags: django, vultr, webdev, nginx
Published: 2019-09-29 15:44:25

Having developed my Django app, it was time to deploy it so that it can be live, such a thrilling feeling to have my own hosted website online. - I did a couple of searches and decided to host with [vultr VPS](https://www.vultr.com/?ref=8253469). Let us jump to the whole process from setting up my server to actual running my website.

#Creating a New Instance

#####I chose cloud compute:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/20imkgv4hh5do7u5b600.png)

######Selecting the region for my server:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/8d5lcfwx8nfpy9zc1nxf.png)

######selecting server operating system:
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/w5zl5cjru3jb36tvl1kp.png)


######Selecting the size of the server:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/x4w4tdpt73kuvxklq6kt.png)
 
I chose to name the server Testserver for a practical purpose. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/jbfjeqqfq5y0wn40etqi.png)

######after creating  the server:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/kgwbuo9hrxtnibk6boxt.png)

after receiving the root password via email, I ssh into the server using the server IP Address.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/sxjk1whkeoe3g2z66ql2.png)

####Updating the server

#####First thing is to upgrade the server's packages:

 <code>apt-get update
       apt-get upgrade
</code>

######Creating Application User
It is always best practice not to work directly with the root user.so I created another user.

<code> adduser django</code>


since I am deploying a Django application, It is simple to use a simple name.
This is the output. There are few questions to be answered.
~~~
Adding user `django' ...
Adding new group `django' (1000) ...
Adding new user `django' (1000) with group `urban' ...
Creating home directory `/home/django' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for urban
Enter the new value, or press ENTER for the default
  Full Name []:
  Room Number []:
  Work Phone []:
  Home Phone []:
  Other []:
Is the information correct? [Y/n]
~~~

Adding the user to sudoers to be able to perform root functions:
<code>gpassword -a django sudo</code>

Now log in to the new user account.

##Installing the necessary Dependencies:

#####Supervisor
This will be used to start the Django application server and manage it.

<code>sudo apt-get install supervisor</code>

######Starting and enabling the supervisor:

<code>
sudo systemctl enable supervisor
sudo systemctl start supervisor
</code>

#####PostgreSQL 

Installing the dependencies to be used by Postgresql and Django

<code>sudo apt-get install build-essential libpq-dev python-dev</code>

######Installing PostgreSQL server:

<code>sudo apt-get -y install postgresql postgresql-contrib</code>

######Creating and Configuring PostgreSQL database:

#####Switch users:

<code>su - postgres</code>

Creating a db user and database:

<code>
createuser django_project
createdb prod --owner django_project
psql -c "ALTER USER u_urban WITH PASSWORD '!@#fs_877#$cdfd@@'"
</code>

######exit the postgreSQL user:
<code>exit</code>

####Install and Configure Virtualenv

I used python3 that is already installed in ubuntu 16.04

######First, install pip3:

<code>sudo apt-get install python3-pip</code>

######Using pip install virtualenv:

<code>pip3 install virtualenv</code>

######Then create virtualenv:

<code>python3 -m venv django_env</code>

######Activating it:
cd to the virtualenvdirectory <code>cd django_env</code>

<code>source bin/activate</code>

I used GitHub to store my Django website, so I cloned it from the git repository.

<code>git clone https://github.com/ndemo-richard/django_project.git</code>

cd into project directory and install project dependencies:

<code>pip install -r requirements.txt</code>

changing the database credentials in the settings.py file in the project root directory:

~~~
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'prod',
        'USER': 'django_project',
        'PASSWORD': '!@#fs_877#$cdfd@@',
        'HOST': 'localhost',
        'PORT': '',
    }
}
~~~

#####migrating the database:
<code>python manage.py migrate</code>

#####collect project static files:
<code>python manage.py collectstatic</code>

####Install and configure Gunicorn

<code>pip install gunicorn</code>

create a file named gunicorn inside bin directory

<code> vi bin/gunicorn</code> 
add this to the empty file:

~~~
#!/bin/bash

NAME="django_project"
DIR=/home/django/django_project
USER=django
GROUP=django
WORKERS=3
BIND=unix:/home/django/run/gunicorn.sock
DJANGO_SETTINGS_MODULE=django_project.settings
DJANGO_WSGI_MODULE=django_project.wsgi
LOG_LEVEL=error

cd $DIR
source ../bin/activate

export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DIR:$PYTHONPATH

exec ../bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $WORKERS \
  --user=$USER \
  --group=$GROUP \
  --bind=$BIND \
  --log-level=$LOG_LEVEL \
  --log-file=-
~~~

make the file executable

<code>chmod u+x bin/gunicorn</code>

create directory for the UNIX socket file:

<code> mkdir run</code>

#####Configure Supervisor

 first, create a directory for log files:

<code>mkdir logs</code>

######Create an empty log file inside the log directory:

<code>touch logs/gunicorn-error.log</code>

create a new supervisor config file:

<code>sudo vi /etc/supervisor/conf.d/django_project.conf</code>

django_project.conf

~~~
[program:django_project]
<code>
command=/home/django/django_project/bin/gunicorn
user=urban
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/home/django/logs/gunicorn-error.log
~~~

Reread the config file:

<code>
sudo supervisorctl reread
sudo supervisorctl update
</code>

Check the status:
<code>
sudo supervisorctl status django_project
django_project                      RUNNING   pid 42173, uptime 0:00:13
</code>


##NGINX

Installing Nginx web server, this will be used to run the Django application behind a proxy server

<code>sudo apt-get install nginx</code>

create new config file inside /etc/nginx/sites-available/:

<code>sudo vim /etc/nginx/sites-available/django_project</code>

/etc/nginx/sites-available/djago_project

~~~
upstream app_server {
    server unix:/home/urban/run/gunicorn.sock fail_timeout=0;
}

server {
    listen 80;

    # add here the ip address of your server
    # or a domain pointing to that ip (like example.com or www.example.com)
    server_name 68.152.87.135;

    keepalive_timeout 5;
    client_max_body_size 4G;

    access_log /home/urban/logs/nginx-access.log;
    error_log /home/urban/logs/nginx-error.log;

    location /static/ {
        alias /home/urban/static/;
    }

    # checks for static file, if not found proxy to app
    location / {
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app_server;
    }
}
~~~

creating a symbolic link:
<code>
sudo ln -s /etc/nginx/sites-available/django_project /etc/nginx/sites-enabled/django_project
</code>

Remove the default nginx website:
<code>sudo rm /etc/nginx/sites-enabled/default</code>

Restart nginx:
<code>sudo service nginx restart</code>

Now we are good to go. My website is online.