Deploying Django on AWS ec2 ubuntu Instance with Uwsgi and Nginx
You need a Linux based system, I use Ubuntu 18.04 for this tutorial
Setup your Django App
Step 1: Access your AWS Ubuntu instance on terminal
ssh ubuntu@your-aws-instance-public-ip -i key.pem
Step 2: After logging in, let’s get all the required stuff installed.
sudo apt-get update
sudo apt-get install python-dev
sudo apt-get install python-pip
For Python 3,
sudo apt-get install python3-dev
sudo apt-get install python3-pip
Step 3: CLone of your Django project repo.
git clone <project_link>
Step 4: Install a virtualenv package
sudo pip install virtualenv
Step 5: Let’s start the virtualenv and enter it.
virtualenv venv
source venv/bin/activate
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 venv
Step 6: Go to your project path & Install all the requirements
cd your_project
pip install -r requirements.txt
Step 7: Install all the requirements
pip install -r requirements.txt
Step 8. To test if this installation worked, we need to do a runserver on port 8000 (make that this port is open to the public: you can do this by adding an inbound rule for port 8000 on the security group for your EC2 Instance) and open it in the browser.
python manage.py runserver 0.0.0.0:8000
Visit your domain and verify your running project
http://<public IP>:8000
Setup uWSGI
Now we’ve got a Django app project that runs inside the virtualenv. We need Uwsgi to serve Django to the web instead of runserver command.
deactivate
Step 1: Now install uWSGI
sudo pip install uwsgi
Step 2: Try running your project server with uWSGI
uwsgi --http :8000 --home /home/ubuntu/venv/ --chdir /home/ubuntu/<your_project> --module <your_project_name>.wsgi
Now if you fire up http://<public IP>:8000, your Django website should show up in the browser.
Step 3: Create uWSGI config ini file.
sudo mkdir -p /etc/uwsgi/sites
sudo nano /etc/uwsgi/sites/<your_project_name>.ini
project_name.ini
[uwsgi]
project = <project_name>
uid = ubuntu
base = /home/ubuntuchdir = /home/ubuntu/<Project_name>
home = /home/ubuntu/venv
module = <Project_name>.wsgi:application#master = true
processes = 25
harakiri = 300
http-timeout = 240
socket-timeout = 240
worker-reload-mercy = 240
reload-mercy = 240
mule-reload-mercy = 240
socket = /run/uwsgi/<Project_name>.sock
chown-socket = ubuntu:ubuntu
chmod-socket = 664
logto = /home/ubuntu/<Project_name>/uwsgi.log
You can test if this works by running the following command.
uwsgi --ini /etc/uwsgi/sites/<Project_name>.ini
Step 4: 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 ubuntu:ubuntu /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all[Install]
WantedBy=multi-user.target
The service will execute this line everytime it comes up and make sure it is up. You could even fire it up on the terminal to see that it runs the server for you. The only special thing here is the –emperor. The emperor mode checks a particular folder (in our case, sites) for .ini files and fires each of them (our <project_name>.ini is sitting there) making it useful if we have multiple websites.
/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
Now let’s systemd to run our service.
sudo systemctl restart uwsgi
Setup Nginx
Step 1: Install Nginx
sudo apt-get install nginx
Step 2: Create Nginx config file
sudo nano /etc/nginx/sites-available/<project_name>
my_project
server {
listen 80;
return 301 https://$host$request_uri;
}server{
listen 443 ssl ;
server_name <DOMAIN NAME>;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000" always;
#location = /favicon.ico {access_log off; log_not_found off; }
ssl_certificate <.pem file path>;
ssl_certificate_key <.key file path>;
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/<project_name>.sock;
uwsgi_read_timeout 600;
# when a client closes the connection then keep the channel to uwsgi open. Otherwise uwsgi throws an IOError
uwsgi_ignore_client_abort on;
}
}
step 3: Link this config file to Nginx’s sites-enabled directory to enable them.
sudo ln -s /etc/nginx/sites-available/<project_name> /etc/nginx/sites-enabled/<project_name>
Step 4: Verify your nginx config syntax
sudo nginx -t
Step 5: After that restart Nginx service to load the new config
sudo systemctl restart nginx
Step 6: enable both of the services to start automatically at boot
sudo systemctl enable nginx
sudo systemctl enable uwsgi
Step 7: If you are not able to see your application on your domain and getting “nginx bad gateway 502”, then check your error logs
uWSGI error logs
sudo journalctl -u uwsgi
Nginx error logs
sudo tail -f /var/log/nginx/error.log
You could run into 400 or 502 errors when trying to serve if you’re running with DEBUG = False and have not set ALLOWED_HOSTS in settings.
You need to have allowed hosts configured to allow those domains. You could allow everything,
ALLOWED_HOST = ['*'] #INCASE you want allow every host but this may turn out to be unsafe
Or allow the domains we configured in the nginx conf,
ALLOWED_HOST = ['yourdomain.com','www.yourdomain.com','your-ec2-public-ip']
Step 8. If you modify any of the config files do not forget to type in
sudo systemctl daemon-reload
And finally, we’re live with our django website.