Django Setup Notes – Ubuntu, Nginx, uWSGI


Notes for getting Django running on Ubuntu 16.04… with Nginx, Supervisord, uWSGI in emperor mode and a bit of Postgres.

Start by setting up your Ubuntu environment.

Newish Python 3.6

add-apt-repository ppa:fkrull/deadsnakes
apt-get update
apt-get install python3.6
apt-get install python3.6-dev
apt-get install python-virtualenv


apt-get install postgresql postgresql-contrib
su - postgres
createdb myapp
createuser -P

You may need to dump a database and import it again…

pg_dump -U myuser myapp > myapp.db
psql myapp < myapp.db

SSL Cert Setup

Grab a free SSL cert…

service nginx stop
apt-get install letsencrypt
letsencrypt certonly --standalone -d -d
service nginx start


apt-get install nginx

This should give you a nice and secure HTTPS setup which also supports HTTP2…


server {
listen 443 ssl http2;
charset utf-8;
client_max_body_size 75M;

ssl on;
ssl_certificate /etc/letsencrypt/live/;
ssl_certificate_key /etc/letsencrypt/live/;

ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers On;

ssl_session_cache shared:SSL:128m;

add_header Strict-Transport-Security "max-age=31557600; includeSubDomains";
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Xss-Protection "1";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' *";
add_header Referrer-Policy origin-when-cross-origin;

ssl_stapling on;
ssl_stapling_verify on;

access_log on;

location /static {
alias /var/www/;

location / {
uwsgi_pass unix:///var/www/;
include /var/www/;


uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_ADDR $server_addr;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
uwsgi_param UWSGI_SCHEME $scheme;

Django Virtual Environment

cd /var/www
virtualenv -p /usr/bin/python3.6 env

cd /var/www/
source env/bin/activate

git clone api

Note: my Django app name is “api” here.

pip install -r api/requirements.txt

pip install Django
pip install uwsgi

Install uWSGI System-wide

Using the latest Python, install uWSGI in /usr/local/bin…

Make sure you are not in a virtual environment or run “deactivate”.

python3.6 -m pip install --upgrade pip
python3.6 -m pip install uwsgi

Supervisord to Manage uWSGI in Emperor mode

apt-get install supervisor


command=/usr/local/bin/uwsgi --emperor /etc/uwsgi/apps-enabled

Setup /etc/uwsgi

cd /etc
mkdir uwsgi
cd uwsgi
mkdir apps-available
mkdir apps-enabled
cd apps-available


uwsgi-socket = /var/www/myapp/api.sock
pythonpath = /var/www/myapp/api
virtualenv = /var/www/myapp/env
processes = 2
reload-on-rss = 150
module = api.wsgi
uid = www-data
gid = www-data

cd /etc/uwsgi/apps-enabled
ln -s ../apps-available/myapp.ini
service supervisor restart

You can now also edit / touch your myapp.ini to make uwsgi restart the worker processes.

Done. Test your setup.

Go make some tea and start coding.

More Notes

Let me know if something above can be done better.

Tune your Postgres database. Then su – postgres and run “pg_conftool show all” to see that your setting are up to date.

Tune your SSL setup.

You probably want 2x uwsgi processes for every CPU in your server.

Update: use pipenv

apt-get install python-pip
pip3 install pipenv
cd /home/fred/code
mkdir myproject
cd myproject
pipenv --three --python /usr/bin/python3.6
pipenv shell
python --version

to use:

su - www-data (or user which runs uwsgi)
pipenv shell