Complete Guide to Deploy Django Applications on AWS Ubuntu Instance with uWSGI and Nginx

Srijan Anand
5 min readMay 5, 2018

--

Note: This guide is in reference to the famous DigitalOcean guide (link below). I have tried to cover the most common issues during deployment. Some of the steps below might not be mandatory but they are considered as best practices.

Reference: How To Serve Django Applications with uWSGI and Nginx on Ubuntu 16.04

Prerequisites:

  • Linux experience is helpful but not mandatory.
  • An AWS ubuntu 16.04 instance with atleast one port opened.

Make your Django App Production Ready

  1. Create a new directory named settings where your settings.py exists.
  2. Rename settings.py to base.py.
  3. Now move base.py to settings directory and modify/add :-
ALLOWED_HOSTS = ['your_production_domain_or_ip', 'your_local_domain']

If you don’t care just allow all hosts :-

ALLOWED_HOSTS = ['*']

Install unipath and make the changes for BASE_DIR in this file. (This has to be done because our settings file (base.py) now lives a level deeper)

from unipath import Path

BASE_DIR = Path(__file__).ancestor(3)

4. Create two new files in this directory.

production.py

from .base import *

DEBUG = False

ALLOWED_HOSTS = ['your_production_domain_or_public_ip'] # or ['*']

local.py

from .base import *

DEBUG = True

ALLOWED_HOSTS = ['your_local_domain'] # or ['*']

5. Make sure you have an empty __init__.py file inside settings directory. This is important so that python can read settings directory as a python module.

6. Generate a requirements file from your project’s virtual environment in your project root directory.

pip freeze > requirements.txt

Note: If you are not using a virtual environment on your local machine you might want to look into pipreqs

7. Verify your directory structure as it should look somewhat like:-

my_project
|-my_app
|-my_project
| |
| |-settings
| | |-__init__.py
| | |-base.py
| | |-local.py
| | |-production.py
| |-urls.py
| |-wsgi.py
|-manage.py
|-requirements.txt

8. Now lets modify our environment parameter in manage.py. Replace “my_project.settings” with “my_project.settings.base”.

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_project.settings.base")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed " and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)

9. Also, modify the environment parameter in wsgi.py. This time modify the parameter as production. Do the same in your asgi.py file as well.

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_project.settings.production")

application = get_wsgi_application()

10. Now push your project on a remote repo like Github or Bitbucket.

Setup your Django App on AWS instance

  1. Install Python. I am using Python 3.5.2 as Python 2 doesn’t support Django 2.0
  2. Access your aws ubuntu instance on terminal and clone your django project repo.
git clone my_project/remote/link my_project

3. Install virtualenv package

sudo pip install virtualenv

4. Now lets create a custom Virtual Environment and install all the requirements inside it.

virtualenv my_project_venv

Note: If you are having problems because of python version conflict (which you will if you are using python 3 like me) then use:-

virtualenv -p python3 my_project_venv

Activate Virtual Environment

source my_project_venv/bin/activate

Install all the requirements inside my_project_venv

pip install -r my_project/requirements.txt

5. Make sure your desired port is enabled on your instance and you don’t have any firewall enabled on that port. Now lets run our project by :-

python my_project/manage.py runserver 0.0.0.0:8000

Visit your domain and verify your running project

http://server_domain_or_Public_IP:8000

Setup uWSGI Application Server

  1. Install Python Dev files as uWSGI is dependent on them.

For Python 2, type:

sudo apt-get install python-dev

For Python 3, type:

sudo apt-get install python3-dev

2. Now install uWSGI

sudo pip install uwsgi

3. Try running your project server with uWSGI

uwsgi --http :8000 --home /home/srijan/my_project_venv --chdir /home/srijan/my_project --module my_project.wsgi

4. Create uWSGI config ini file.

sudo mkdir -p /etc/uwsgi/sitessudo nano /etc/uwsgi/sites/my_project.ini

my_project.ini

[uwsgi]
project = my_project
uid = srijan
base = /home/%(uid)

chdir = %(base)/%(project)
home = %(base)/venv
module = %(project).wsgi:application

master = true
processes = 5

socket = %(base)/%(project).sock
chown-socket = %(uid):www-data
chmod-socket = 666
vacuum = true

Note: You can always hardcode any variable according to your project directory structure.

5. Now create a systemd Unit File for uWSGI. This will help uWSGI to automatically reboot whenever nginx or our instance is rebooted/restarted as well.

sudo nano /etc/systemd/system/uwsgi.service

uwsgi.service

[Unit]
Description=uWSGI Emperor service

[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown srijan:www-data /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target

Setup and Configure Nginx

  1. Install Nginx
sudo apt-get install nginx

2. Create Nginx config file

sudo nano /etc/nginx/sites-available/my_project

my_project

server {
listen 8000;
server_name server_domain_or_ip;

location = /favicon.ico {access_log off; log_not_found off; }

location = /static/ {
root /home/srijan/my_project;
}

location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass unix:///home/srijan/my_project.sock;
}
}

3. Link this config file to Nginx’s sites-enabled directory to enable them.

sudo ln -s /etc/nginx/sites-available/my_project /etc/nginx/sites-enabled/my_project

4. Verify your nginx config syntax

sudo nginx -t

5. After that restart Nginx service to load the new config

sudo systemctl restart nginx

6. Finally, start your uWSGI server

sudo systemctl start uwsgi

7. Also, enable both of the services to start automatically at boot

sudo systemctl enable nginxsudo systemctl enable uwsgi

8. If it doesn’t work, run your application server with my_project.ini file (important)

sudo uwsgi --ini /etc/uwsgi/sites/my_project.ini

9. If your application is not served you can easily check for errors. The above command returns a status log where the cause is clearly mentioned. Still its not a bad thing to check all file paths in my_project.ini

10. If you still are not able to see your application on your domain and getting “nginx bad gateway 502”, its time to check your error logs

uWSGI error logs

sudo journalctl -u uwsgi

Nginx error logs

sudo tail -F /var/log/nginx/error.log

11. If you modify any of the config files do not forget to type in

sudo systemctl daemon-reload

uWSGI and Nginx sure have made our lives easier for Django Deployment yet these features are highly customizable.

--

--