Deploying Django with nginx and gunicorn

Assumption

Server – Ubuntu 14.04 with non-root user and sudo access (user django in this example)

Setup django project

Clone/copy your django project in home directory. in this example I am putting it in /home/django/myproject (myproject is django project directory)

Install virtualenv –

To keep python dependencies for different projects separate we use tool called virtualenv. It create virtual environment for your project and keeps all dependencies required by it in separate place. This helps us to use different versions of packages in different projects without any effect on global python site-packages.

To install virtual environment type below command on console and hit return key –

$ pip install virtualenv

Now virtualenv is installed, lets see how create virtual environment.

Create new virtualenv

Go to your project directory. And run below command.

$ virtualenv

Here is the name of the environment. It can be anything of your choice. virtualenv will create folder named in current directory where Python executable, pip and all packages installed will be saved.

Which python executable to use ? – Currently there are 2 main virsions of python python2 and python3. While creating the virtualenv you can give path of python executable of your choice.

$ virtualenv -p /usr/bin/python3.4

If path is not provided global python interpreter will be used. We have created virtual environment with python3.4. To start using it we need to activate it.

$ source /bin/activate

Here is the name of virtual environment. After this you can install required dependencies in this vrtualenv. I am assuming that all project dependencies are in requirements.txt file which is general practice.

pip install -r requirements.txt

Create DB and configure it in settings.py file –  After all the dependencies are installed you can create the DB and configure it in settings.py file.

Run migrations – Assuming that all your migrations are tracked using git or any other VCS, You can apply them directly to DB by running command –

python manage.py migrate

After this load fixtures if any by running loaddata command

python manage.py loaddata

Now at this step your django project is setup on server and running. Lets move to gunicorn part –

Install gunicorn – install gunicorn if its not already done through requirements.txt

pip install gunicorn

Mozilla circus – circus is used to supervise the gunicorn workers and make sure gunicorn is up and running. Install it using below command.

pip install circus

Create circus.ini configuration file – Below is sample circus.ini configuration file. Create it in /home/django directory with below contents. Check comments for more info.

[circus]
 check_delay = 5
 endpoint = tcp://127.0.0.1:5555
 pubsub_endpoint = tcp://127.0.0.1:5556
 statsd = true

[watcher:myproject]
 working_dir = /home/django/myproject   # your project directory

# gunicorn command and arguments myproject.wsgi is wsgi file for django app
 cmd = gunicorn
 args = -w 3 -t 60 --pythonpath=. -b 127.0.0.1:8000 myproject.wsgi
 uid = django
 numprocesses = 1
 autostart = true
 send_hup = true
 stdout_stream.class = FileStream
 stdout_stream.filename = /home/django/logs/gunicorn.stdout.log
 stdout_stream.max_bytes = 10485760
 stdout_stream.backup_count = 4
 stderr_stream.class = FileStream
 stderr_stream.filename = /home/django/logs/gunicorn.stderr.log
 stderr_stream.max_bytes = 10485760
 stderr_stream.backup_count = 4

[env:myproject]

# IMP - add your virtual envirnments bin directory path here
 PATH = /home/django/myproject//bin:$PATH
 TERM=rxvt-256color
 SHELL=/bin/bash
 USER=django
 LANG=en_US.UTF-8
 HOME=/home/django

# site packages path of your virtual env
 PYTHONPATH=/home/django/myproject//lib/python3.4/site-packages

Create ubuntu service for circus to make sure circus is up and running on server startup – Create a file in /etc/init with name circus.conf and copy below contents in it. Make sure path to circus.ini is correct.

start on filesystem and net-device-up IFACE=lo
 stop on runlevel [016]

respawn
 exec /usr/local/bin/circusd /home/django/circus.ini

At this point your django project should be running on port 8000. Now lets install nginx and reverse proxy it to gunicorn for dynamic content. All the static content like django media files and static files will be served by nginx directly. This will reduce the load on gunicorn.

sudo apt-get install nginx

Create virtual host file for site in  /etc/nginx/sites-available directory. I am naming it as my-django-site. Put below contents in the file.

server {
 listen 80 default_server;
 server_name _;

 large_client_header_buffers 4 32k;
 client_max_body_size 50M;
 charset utf-8;
 
 # make sure you have created these directories

 access_log /home/django/logs/nginx.access.log;
 error_log /home/django/logs/nginx.error.log; 

 # Main site
 location / {
 proxy_set_header Host $http_host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Scheme $scheme;
 proxy_set_header X-Forwarded-Proto $scheme;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_pass http://127.0.0.1:8000;
 proxy_redirect off;
 }

 # Django admin access (/admin/)
 location /admin {
 proxy_set_header Host $http_host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Scheme $scheme;
 proxy_set_header X-Forwarded-Proto $scheme;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_pass http://127.0.0.1:8000$request_uri;
 proxy_redirect off;
 }

 # Static files
 location /static {
 alias /home/django/myproject/static;
 }

 # Media files
 location /media {
 alias /home/django/myproject/media;
 }
}

Create symlink to site in etc/nginx/sites-enabled

sudo ln -s /etc/nginx/sites-available/my-django-site /etc/nginx/sites-enabled/my-django-site.

Now restart nginx and your site will be available at http://www.example.com. Make sure port 80 is open and accessible externally.

One thought on “Deploying Django with nginx and gunicorn

Leave a comment