Django Gunicorn Setup

Gunicorn is a “Python WSGI HTTP Server for UNIX”. It is absolutely stupid simple to setup and get running.

I will be using the following for this guide:

  • Django 1.8
  • Debian 8 (jessie)

Gunicorn Installation

  1. Install.

    pip3 install gunicorn

  2. Create a blank WSGI file inside your project folder (where manage.py resides). This is where you can configure Gunicorn options instead of passing arguments to it.

    touch PROJECT.wsgi

  3. Start gunicorn.

    gunicorn --threads=COUNT PROJECT.wsgi:application

That’s it. You now have a Gunicorn WSGI server running on port 8000. Now I recommend that you place an nginx proxy in front of this to handle file caching rather than letting the Gunicorn/Python server hand out static content (CSS, Javascript, images, etc.). Even the documentation recommends this.

The Gunicorn docs recommend setting the thread count to 2x to 3x the core count of the server.

Running Gunicorn aaS (systemd)

After install Gunicorn and testing it out, you’ll probably want to set it up as a service so it can be started automatically on boot.

  1. Create a new user.

    adduser django

    Give it an extremely long and random password. You won’t be logging into this user.

  2. Move your Django project into /home/django/. This is now where your project will reside.

  3. Change the ownership of your project files.

    chown -R django:django /home/django/

    Update the static files path in nginx if you have one set.

  4. Create the Gunicorn systemd service file.

    nano /etc/systemd/system/gunicorn.service

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [Unit]
    Description=gunicorn daemon
    Requires=gunicorn.socket
    After=network.target
    [Service]
    Environment=PYTHONHASHSEED=random
    PIDFile=/run/gunicorn/pid
    User=django
    Group=django
    WorkingDirectory=/home/django/PROJECT
    ExecStart=/usr/local/bin/gunicorn --pid /run/gunicorn/pid django.wsgi:application
    ExecReload=/bin/kill -s HUP $MAINPID
    ExecStop=/bin/kill -s TERM $MAINPID
    PrivateTmp=true
    [Install]
    WantedBy=multi-user.target
  5. Create the Gunicorn systemd socket file.

    nano /etc/systemd/system/gunicorn.socket

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [Unit]
    Description=gunicorn socket
    [Socket]
    ListenStream=/run/gunicorn/socket
    ListenStream=0.0.0.0:9000
    ListenStream=[::]:8000
    [Install]
    WantedBy=sockets.target
  6. Change the permissions so the pid file can be created.
    chown -R django:django /run/gunicorn

  7. Start the services.

    1
    2
    systemctl start gunicorn.socket
    systemctl start gunicorn.service
  8. Enable the services to be started on boot if there were no problems.

    1
    2
    systemctl enable gunicorn.socket
    systemctl enable gunicorn.service

Final Tasks

  1. Update any cronjobs for Django to the new user.
  2. Change file permissions of the static files if you are not running nginx as the django user/group.

I had one small issue with Redis where the user had no permission to access /var/run/redis.sock. This was easily solved by using TCP sockets instead of Unix sockets.