DEV Community

Akash Shivram
Akash Shivram

Posted on

Setting up Django, Gunicorn and Nginx in Vagrant virtual machine

This post explains setting up a Django app deployed by Gunicorn behind Nginx server in a Ubuntu 16.04 virtual machine set up via Vagrant.

These are broader steps that you would need to take:

  1. Setting up an Ubuntu 16.04 VM using Vagrant.
  2. Setting up python and virtual environment.
  3. Setting up Gunicorn systemd file.
  4. Setting up Nginx to proxy pass Gunicorn.

1. Creating an Ubuntu 16.04 VM using Vagrant

Installing Vagrant is pretty simple step.

But first you would need to install Virtual Box or any other VM provider. Virtual Box is popular choice and even easier option amongst the providers to install.
Just go to the Virtual Box's downloads page and select respective host depending on your system's operating system.

If you select OSX host, a .dmg package is downloaded, open it and follow steps. While installing in OSX if you get an error something like Your Instalation Failed, follow this blog to troubleshoot.

Once Virtual Box is installed you can move on to installing Vagrant.

Go to Vagrant's download page and download installation image as per your OS.

Check if vagrant is installed. Open terminal and type vargant. The output should be something like this:

$ vagrant
Usage: vagrant [options] <command> [<args>]

    -v, --version                    Print the version and exit.
    -h, --help                       Print this help.

#...

Once installation is complete, open terminal shell and go to directory where you want to setup your virtual machine. For example, create directory called virtualmachines/,here you would have all the virtual machines you want to setup. So, for Ubuntu 16.04, create a directory ubuntu16_04/. Go inside the directory

mkdir ./virtualmachines && cd virtualmachines
mkdir ubuntu16_04 && cd ubuntu16_04

Now is the time create a VM box. You can create a VM from scratch using command:

$ vagrant init hashicorp/xenial64

or setup a base image of OS called a box by executing command:

$ vagrant box add hashicorp/xenial64

If you want to install any other flavour of Ubuntu replace xenial with the flavour's first name. 64 in xenial64 means the guest OS would be a 64-bit OS. You can find the list of available OS here.

If you execute ls command, you would find a file called VagrantFile present in the directory. This is the source file that is used to configure the VM. Every time that you want to start the VM, the configurations would be set as per this file.

Make sure to un-comment line declaring forwarded_port for guest and host OS.
The guest is your virtual machine and the host is your local machine.
Also, if it is commented, un-comment this block:

config.vm.provider "virtualbox" do |vb|
    vb.gui = false
    vb.memory = 2048
    vb.cpus = 2

and specify vb.gui, vb.memory and vb.cpus.
You can find sample VagrantFile in this gist.

Now to start the VM run :

$ vagrant up

This would boot your environment, and in less than a minute you would have Ubuntu running in a virtual machine. There would be no output visible, as Vagrant runs the VM without UI. To access Ubuntu you would require ssh. Run:

$ vagrant ssh

This would start a full-fledged SSH session.

2. Setting up python and virtual environment for Django app

Now that you are inside Ubuntu, it is time to install all necessary packages/modules.

Install python and pip using command

$ sudo apt install python python-pip

This would install python2.7. For python3 use:

$ sudo apt install pyhton3 python-pip3

Now install virtualenv:

$ pip install virtualenv

Create a directory called webapps/, this is going to contain all the Django projects created henceforth. You can directly clone your git repository here or start a project (remember to create a directory inside which you should start your project).
Such that your webapps/ directory tree looks like this :

 * webapps/
 | 
 ---- * your_project_parent_directory
      |
      ---- * your_project
           |
           ---- * your_app
           ---- * your_project
                |
                ---- * your_project.wsgi

Your project should have virtualenv set up and activated. Make sure you have a .wsgi file in it. Change directory and get inside your project.

3. Setting up Gunicorn systemd file

Now its time to install Gunicorn:

$ pip install gunicorn

Once gunicorn is installed, run command:

$ gunicorn <your_project_name>.wsgi:application --bind 0.0.0.0:8000

If the server starts, your gunicorn setup is working. Though there is a robust way of gunicorn interacting with django project.

Create and open a systemd service file for Gunicorn with sudo privileges in your text editor:

$ sudo nano /etc/systemd/system/gunicorn.service

Your gunicorn.service file should look something like this:

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

[Service]
WorkingDirectory=/home/vagrant/webapps/your_project_parent_dir/project_name
ExecStart=/home/vagrant/webapps/your_project_parent_dir/env/bin/gunicorn --access-logfile - --bind \ 
unix:/home/vagrant/webapps/your_project_parent_dir/your_project/your_project.sock \
your_project.wsgi:application

[Install]
WantedBy=multi-user.target

The [Unit] and [Install] remain as they are. In the WorkingDirectory, you need to provide absolute path to your project. In ExecStart, you specify command to run gunicorn, but instead using gunicorn command directly, you need to specify which gunicorn, hence, you provide the path to gunicorn, if it is installed globally, you would need to specify the absolute path to global command file, like /usr/local/bin/gunicorn followed by parameters --access-logfile and --bind, after unix: specify absolute path to your_project.sock
Now we would have to start this service.

Run command:

$ sudo systemctl start gunicorn

Check status of the service:

$ sudo systemctl status gunicorn

You can confirm that the operation was successful by checking for the socket file.

$ ls your_project_parent_dir/your_project/

You should find a file called your_project.sock here.

If not, check for the service configurations or status of it.
To check for errors look up in the journal:

$ sudo journalctl -u gunicorn

Other reasons could be :

  • The owner is root and not sudo.
  • The WorkingDirectory path does not point to the project directory.
  • The path given for configuration for gunicorn service in ExceStart directive is incorrect. Check these:
    • The path to the gunicorn binary points to the actual location of the binary within the virtual environment.
    • The --bind directive defines a file to create within a directory that Gunicorn can access.
    • The your_project.wsgi should be immediate child to your_project directory.

Remember a reload of daemon service would be required if the file is edited :

$ sudo systemctl daemon-reload
$ sudo systemctl restart gunicorn

4. Setting up nginx

Install Nginx in your guest, type this command in terminal:

sudo apt-get install nginx

Check if nginx is successfully installed:

$ nginx

You should not see command not found error.

Now we need to create and start a new server block in /etc/nginx/sites-available.

$ sudo nano /etc/nginx/sites-available/you_project

Here specify something like this:

server {
    listen 8000;
    server_name 0.0.0.0;
    location = /favicon.ico { access_log off; log_not_found off; }
    location / {
        include proxy_params;
        proxy_pass http://unix:/home/vagrant/webapps/project-name/project-name.sock;
    }
}

The argument to listen is the port of guest that would be exposed, you should mention this port in forwarded_port and map it to some host port in VagrantFile.
The server_name is the IP location or DNS location of your server, here it is localhost so we provide server_name as 0.0.0.0.
In proxy_pass after unix: specify absolute path to your_project.sock file.

If you have static files you would need to add these extra lines

location /static/ {
        root /home/vagrant/webapps/your_project_parent_dir/your_project;
    }

inside server object.

Save and close the file when you are finished. Now, you can enable the file by linking it to the sites-enabled directory:

$ sudo ln -s /etc/nginx/sites-available/your_project /etc/nginx/sites-enabled/

Test your nginx for syntax errors:

$ sudo nginx -t

If the test is ok, you would require to restart the nginx now and check its status.

$ sudo systemctl restart nginx
$ sudo systemctl status nginx

You are all set. Hit 0.0.0.0:host_port on browser to view your Django projects app page.

References:

Discussion (0)