Complete Guide to Deploy Django Applications on AWS Ubuntu Instance with uWSGI and Nginx
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
- Create a new directory named settings where your settings.py exists.
- Rename settings.py to base.py.
- 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
- Install Python. I am using Python 3.5.2 as Python 2 doesn’t support Django 2.0
- 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
- 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
- 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.