Friday, May 8, 2015

Django Gunicorn and Nginx

One of the few times I have had access to an actual machine which had to server django I have never been failed by the DUNG stack. Django-Unix-Nginx-Gunicorn.

Of course I have had to replace Unix with Linux. There is nothing like a bit of Mint fresh air. This tutorial is carried out on Linux Mint but should work fine for Ubuntu and the likes.

This tutorial assumes that you have pip and virtualenv set up and working. At the time of writing Django1.8 was the latest and Gunicorn 19.0

First things first. We have to set things up. Open up your beloved terminal and start typing.

  1. We have to create a directory for our tutorial. Let us call it test_django
    1. mkdir test_django
    2. cd test_django 
  2. Now we must create a virtualenv to work in and activate it. If you do not know what that is head over here.
    1. virtualenv -p python3 env
    2. source env/bin/activate
  3. Now we must install django and gunicorn.
    1. pip install django
    2. pip install gunicorn
  4. After waiting for the above commands to finish we create an empty django project. Do not forget the dot at the end of the command.
    1. django-admin startproject dung_test .
    2. python manage.py makemigrations
    3. python manage.py migrate
  5. Our directory now looks like this now.
    1. .
      |-- dung_test
      |   |-- __init__.py
      |   |-- settings.py
      |   |-- urls.py
      |   `-- wsgi.py
      `-- manage.py
  6. That done we now want to make sure that our dummy website is working. 
    1. python manage.py runserver
    2. Open up a browser and check localhost:8000/admin
    3. It should be the standard Django Administration login screen.
  7. To begin deploying the website with nginx and gunicorn we first have to install nginx.Issue the second command in case Nginx fails to start.
    1. sudo apt-get install nginx
    2. sudo service nginx start
  8. Once nginx is installed it will start automatically. You can check by navigating to "127.0.0.1" on your browser and it should say welcome to nginx.
  9. We now have to configure nginx to serve our website.
    1.  We navigate to /etc/nginx/sites-available and create a new file there. Let us call it dung_website.
    2. cd /etc/nginx/sites-available
    3. Open in sudo mode. sudo gedit dung_website
    4. Now insert the following text into the file.
    5. upstream app_server_djangoapp {
          server unix:/home/ghost/dev/temp/gunicorn_socket fail_timeout=0;
      }
      server {
          listen 0.0.0.0:80;
          server_name  .example.com;
       
          keepalive_timeout 5;
          # path for static files
          root /path/to/your/app/media;#make sure this exists
          location / {
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header Host $http_host;
              proxy_redirect off;
              if (!-f $request_filename) {
                  proxy_pass http://app_server_djangoapp;
                  break;
              }
          }
      }
    6. Remember to replace /home/ghost/dev/temp/gunicorn_socket with your own path. The temp folder is that one which contains the test_django folder.
    7. Save and exit. now navigate one step up and to sites-enabled and create a link to the file just created.
      1. cd ..
      2. cd sites-enabled 
      3. ln ../sites-available/dung_website
    8. Now reload nginx with sudo service nginx reload
  10. To configure Gunicorn nothing much is needed. Navigate to where your project was. In my case cd ~/dev/temp
    1. Now add "gunicorn" to the list of installed apps in the dung_test/settings.py folder. 
      1. INSTALLED_APPS = (
          'django.contrib.auth',
          ...
          'gunicorn',
          ...
        )
    2. We were earlier testing the website by running python manage.py runserver
    3. This will be replaced by gunicorn dung_test.wsgi:application --bind=unix:/home/ghost/dev/temp/gunicorn_socket --log-file=-
    4. The address given to bind is the same as written in the nginx server. The unix sockets are faster than using loopback. We could replace the unix:/path/to/socket with localhost:8000 in the nginx file and gunicorn command
  11.  With that done we can open our browser and navigate to localhost/admin to see the admin login page without the CSS. That is solved py running python manage.py collectstatic from the folder where manage.py is kept after setting up static files in the settings.py
  12. Your website can be accessed from other computers by typing in your IP address. To find your ip address run ifconfig in a terminal while connected to the network
With those steps one can conclude the setup of a Django website using Gunicorn and Nginx. As opposed to the Apache model of concurrency Nginx is a reverse proxy server. Gunicorn handles things one at a time and nginx keeps the traffic from overwhelming gunicorn.

The gunicorn documentation explains it much better. Hopefully this will help out some people.