Analytics Vidhya
Published in

Analytics Vidhya

How to deploy Django application on AWS Ubuntu EC2 with Nginx and uWSGI — A Practical Guide

I have done many Django related blogs in the past. One thing I have not discussed is how to take a Django project to the production. In this article, I would like to discuss this subject. To deploy a project to a production environment, there are many approaches. First, what is your host/server environment? Second, you must select which Web Server (HTTP) you will be using, and lastly you need to pick a WSGI server because Django is a Python Web Framework. In this article, I am going to illustrate one of the solutions by using AWS Ubuntu EC2 + Nginx + uWSGI.

To start with AWS, you can create an AWS account to enjoy some free tier products that include the server that we will deploy Django project on. AWS likes to call these servers EC2 instances.

Link to AWS free tier:

https://aws.amazon.com/free/

In a nutshell, the whole tech stacks and dependencies are listed as below.

  • Ubuntu 20.04
  • Nginx
  • uWSGI
  • Python 3.8
  • Django 2.2.24
  • Theming library — AdminLTE

The following diagram illustrates the system topology of the above stack.

In this article, I am going to use the sample project here which is a copy of the project I mentioned in my previous post “Django and AdminLTE”. Let’s get started.

Step 1: Provision an EC2 instance

Open the Amazon EC2 console at https://console.aws.amazon.com/ec2/. From the console dashboard, click Launch Instances.

On Step1: Choose an Amazon Machine Image (AMI) page,

  1. Search by “ubuntu”.
  2. From the results of Quick Start tab, choose 64-bit (x86) and select Ubuntu Server 20.04 LTS (HVM), SSD Volume Type.

On Step2: Choose an Instance Type page,

  1. Choose instance type that is marked as Free tier eligible
  2. Click Review and Launch.

We will be directed to Step 7. Don’t worry about the other steps. Leave them default setups.

On Step 7: Review Instance Launch page, our instance will be running Ubuntu Server 20.04. It will have 1 CPUs, 1 GB memory and 8 GB storage. Click Launch.

On Select an existing key pair or create a new key pair modal:

  1. Choose Create a new key pair
  2. Choose RSA key pair type
  3. Type in key pair name. For example, my_demo_key.
  4. Click Download Key Pair. A my_demo_key.pem file should be downloaded on your local machine. Make sure you safely store this key file.
  5. Click Launch Instances.

Wait a few seconds. We should see the page below once the instance is ready. Click View Instances.

On Instances page, the instance that we just launched should be displayed.

  1. Type a name that is easy to remember. For example, my_demo_server.
  2. Take a note of its public IPv4 address. For example, 54.193.19.108.
  3. Take a note of its security group name. For example by default, launch-wizard-1.

At this point, a new instance is launched.

To connect instance and make instance public, we need to alter security group.

  1. Open Security Groups page that is under Network & Security section.
  2. Click Security group ID of launch-wizard-1 group.
  3. On launch-wizard-1 page, click Edit inbound rules.
  4. On Edit inbound rules page,

4.1. Add SSH type rule. Source is My IP.

4.2. Add HTTP type rule. Source is Anywhere-IPv4.

4.3. Add HTTP type rule. Source is Anywhere-IPv6.

4.4. Add HTTPS type rule. Source is Anywhere-IPv4.

4.5. Add HTTPS type rule. Source is Anywhere-IPv6.

Step 2: Alter settings.py

Open mysite/settings.py file, alter variables as the following.

ALLOWED_HOSTS = ['54.193.19.108']
STATIC_ROOT = '/var/www/mysite/assets/'

Step 3: Upload codebase on EC2 instance

There are many SFTP clients. In this tutorial, let’s use WinSCP which works for Microsoft Windows.

  1. Set up connection and click Login. You need to use my_demo_key.pem key file to config Advanced >> SSH >> Authentication >> Private key file.
  2. Create a project_codebase directory in /home/ubuntu/ directory.
  3. Upload codebase content from local machine to the directory we just created.

Step 4: Configure EC2 instance

There are a few approaches that you can connect server. Please see walkthroughs on AWS document here. Since we use WinSCP in the last step, we can connect server through Commands menu >> Open in PuTTY.

We should see a new window like the following.

Install Python 3.8 by running command as below.

sudo apt update
sudo apt-get install python3.8 python3.8-dev python3.8-distutils python3.8-venv

Install virtual environment by running command as below.

python3.8 -m venv /home/ubuntu/venv/

Install gcc by running command as below. This is optional. It helps if you run into error due to the missing of gcc.

sudo apt-get install gcc

Install wheel and uwsgi under virtual environment by running commands as below.

source /home/ubuntu/venv/bin/activate
pip install wheel
pip install uwsgi

Install the other libraries that are required for this Django project. Then deactivate virtual environment.

pip install -r /home/ubuntu/project_codebase/requirements.txt

Create uwsgi_params file. The path and content are as below.

nano /home/ubuntu/uwsgi_params

Content:

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 REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;

Create /run/uwsgi/ folder by running commands as below.

sudo mkdir /run/uwsgi/
sudo chown ubuntu:ubuntu /run/uwsgi/

Install Nginx by running command as below.

sudo apt-get install nginx

Create mysite.nginx.conf file in the following path and fill in the content as below.

sudo nano /etc/nginx/sites-available/mysite.nginx.conf

Content:

upstream django {
server unix:///run/uwsgi/mysite.sock;
}
server {
listen 80;
server_name 54.193.19.108;
charset utf-8;
location = /favicon.ico { access_log off; log_not_found off; }
location /static {
alias /var/www/mysite/assets/;
}
location / {
uwsgi_pass django;
include /home/ubuntu/uwsgi_params;
}
}

Note that server_name is the IPv4 address of EC2 instance.

Create symbolic link to mysite.nginx.conf file so that Nginx process can find out. Restart Nginx to reflect the change.

sudo ln -s /etc/nginx/sites-available/mysite.nginx.conf /etc/nginx/sites-enabled/
sudo systemctl restart nginx

At this point, we should be able to launch Django project under virtual environment by running the commands as below.

uwsgi --socket /run/uwsgi/mysite.sock --chdir /home/ubuntu/project_codebase/ --module mysite.wsgi --chmod-socket=666

The following logs should be printed.

We should be able to browse this site and see the page as below. Apparently css, image, and javascript are not loaded yet. Because we have not collected static file.

Create mysite static folder by running the following commands.

sudo mkdir /var/www/mysite
sudo chmod 777 /var/www/mysite

Collect static file under virtual environment by running following commands.

python /home/ubuntu/project_codebase/manage.py collectstatic

We should see the following messages.

Create uwsgi folder by running the following command.

sudo mkdir -p /etc/uwsgi/sites

Create uwsgi log folder by running the following command.

sudo mkdir /var/log/uwsgi/
sudo chmod 666 /var/log/uwsgi/

Create uwsgi myproject.ini file. The path and content should look like the below.

sudo nano /etc/uwsgi/sites/myproject.ini

Content:

[uwsgi]
chdir = /home/ubuntu/project_codebase/
module = mysite.wsgi
home = /home/ubuntu/venv/
master = true
processes = 10
socket = /run/uwsgi/mysite.sock
chmod-socket = 666
vacuum = true
logto = /var/log/uwsgi/%n.log
logfile-chown = %(uid):%(uid)
logfile-chmod = 666

Reboot server by running the command as below. Instance will be rebooted in few minutes. Reconnect afterwards.

sudo reboot

Create uwsgi.service file. The file path and content should look like the below.

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

Content:

[Unit]
Description=uWSGI Emperor service
[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown ubuntu:www-data /run/uwsgi'
ExecStart=/home/ubuntu/venv/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
[Install]
WantedBy=multi-user.target

Check configuration syntax by running this command.

sudo nginx -t

It should show the following messages if everything is configured correctly.

Start nginx and uwsgi

sudo systemctl restart nginx
sudo systemctl start uwsgi

If this goes well, you can enable both services to start automatically at boot by typing:

sudo systemctl enable nginx
sudo systemctl enable uwsgi

We should be able to browse site again and see fully loaded page as below.

Conclusion

Congratulations. You have launched Django project on a cloud server. To illustrate the key components, I added the file/directory path into the following diagram.

Hope this article frees your frustrations on deployment. For sure, you need to refine each component to boost performance. It’s a bit too much for this tutorial to dig further. Please don’t hesitate to leave your comments.

Again, the sample project I use in this article is uploaded on GitHub. The link is as below.

https://github.com/slow999/DjangoAndAWSEC2Deployment

If you are interested in a video tutorial, please check out my video as below.

Thanks for reading. Stay tuned.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store