
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
Postgres
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 www.myapp.com -d myapp.com
service nginx start
Nginx
apt-get install nginx
This should give you a nice and secure HTTPS setup which also supports HTTP2…
/etc/nginx/sites-available/myapp.com
server {
server_name www.myapp.com;
listen 443 ssl http2;
charset utf-8;
client_max_body_size 75M;
ssl on;
ssl_certificate /etc/letsencrypt/live/www.myapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.myapp.com/privkey.pem;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers On;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
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' *.google-analytics.com";
add_header Referrer-Policy origin-when-cross-origin;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
access_log on;
location /static {
alias /var/www/www.myapp.com/api/static;
}
location / {
uwsgi_pass unix:///var/www/www.myapp.com/api.sock;
include /var/www/www.myapp.com/uwsgi_params;
}
}
/var/www/myapp/uwsgi_params
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
mkdir www.myapp.com
virtualenv -p /usr/bin/python3.6 env
cd /var/www/www.myapp.com
source env/bin/activate
git clone https://github.com/myco/myapp.git 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
/etc/supervisor/conf.d/uwsgi.conf
[program:uwsgi]
command=/usr/local/bin/uwsgi --emperor /etc/uwsgi/apps-enabled
autostart=true
autorestart=true
redirect_stderr=true
stopsignal=QUIT
stdout_logfile=/var/log/uwsgi.log
Setup /etc/uwsgi
cd /etc
mkdir uwsgi
cd uwsgi
mkdir apps-available
mkdir apps-enabled
cd apps-available
/etc/uwsgi/apps-available/myapp.ini
[uwsgi]
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