DEV Community

Cover image for Deploy  Django + MySql Application into AWS EC2 instance with nginx and SSL
Ruhan Khandakar
Ruhan Khandakar

Posted on

Deploy Django + MySql Application into AWS EC2 instance with nginx and SSL

All the version used in this tutorial

  • Python 3.8.X
  • Django 3.2.2
  • gunicorn 20.1.0
  • MySQL 8.0.20 (RDS)

EC2 Setup

  • Create EC2 instance (Screenshots attached below), during this instance creation. we'll have to download pem/cer file. It'll be used later to access this instance from the terminal via SSH aws_ec2
  • To connect the instance, Follow how to connect to instance guide from the EC2 dashboard.
  • After login into our instance, run the following commands to update our instance -> sudo apt update; sudo apt upgrade -y.
  • In order to use pip3 and venv we have to install some packages -> sudo apt install python3-pip python3-venv
  • Let's create one virutal env -> python3 -m venv env. And activate it -> source env/bin/activate.
  • Now we have to install gunicorndetails (make sure you're in the virtual environment) -pip3 install gunicorn.

Note: if your project has a MySQL database, you have to install some other packages
sudo apt install python3-dev default-libmysqlclient-dev build-essential libssl-dev

  • Now let us pull the repository and install all the dependencies. After this do the necessary migrations.
  • Let us install nginxdetails -> sudo apt install nginx -y. now you can check with sudo nginx.
  • Before starting the nginx setup we have to change our instance's security groups (Check below screenshots)
    ec2_security_group

  • Now let us do a little test, we're going to start our application by gunicorn (what is it? will discuss it in later.) -gunicorn --bind 0.0.0.0:8000 courier_allocation.wsgi:application, after running this we'll see something like 👇🏻
    Screenshot 2021-05-09 at 4.57.28 PM
    and now we can access our application from our instance IP address, like this ec2-XX-XX-XX-XX.ap-south-1.compute.amazonaws.com:8000.

  • But now if we close our terminal then we won't be able to access our application.

  • Now we have to do some setup so that our application can run in the background. Here, we'll use supervisordetails. To install this package we have to run sudo apt install -y supervisor.

  • After installation, we have to create one supervisor config file. For this follow the below steps.

  1. First go to cd /etc/supervisor/conf.d/
  2. Here we'll create one config file -> sudo touch gunicorn.conf
  3. In this conf file paste the below code.
    [program:gunicorn]
    directory=/home/ubuntu/PROJECT_FOLDER
    command=/home/ubuntu/env/bin/gunicorn --workers 3 --bind unix:/home/ubuntu/PROJECT_FOLDER/app.sock DJANGO_PROJECT_FOLDER.wsgi:application
    autostart=true
    autorestart=true
    stderr_logfile=/home/ubuntu/logs/gunicorn.err.log
    stdout_logfile=/home/ubuntu/logs/gunicorn.out.log
    [group:guni]
    programs:gunicorn

  • Now we have to run some commands
  1. sudo supervisorctl reread -> Output - guni: available
  2. sudo supervisorctl update -> Output - guni: added process group
  3. sudo supervisorctl status -> Output - guni:gunicorn RUNNING pid 20199, uptime 0:00:17

  • Now let's do the nginxdetails configuration
  1. First we have to go to - cd /etc/nginx/sites-available/.
  2. Here we need to create one config file - sudo touch django.conf (you can choose any file name). Paste the below code inside your newly created file
    # Nginx Configuration for sample Django application
    ######################################################
    server {
        listen 80;
        server_name ec2-XX-XX-XX-XX.ap-south-1.compute.amazonaws.com;
        location / {
            include proxy_params;
            proxy_pass http://unix:/home/ubuntu/PROJECT_FOLDER/app.sock;
        }
    }
Enter fullscreen mode Exit fullscreen mode
  1. After this run - sudo ln django.conf /etc/nginx/sites-enabled/
  2. now let's test - sudo nginx -t - Output -> nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
  3. Sometime you might get this error -> nginx: [emerg] could not build server_names_hash, you should increase server_names_hash_bucket_size: 64. To fix this we have to add server_names_hash_bucket_size 128; at the top of your http block (located in /etc/nginx/nginx.conf).
  4. Now we have to restart our nginx service -> sudo service nginx restart.
  5. Our nginxdetails is up and running 😁. You can directly access your app from Public IP Address (EC2)

Note: Still a lot of configuration is left, like cache, route multiple ports, load balancer etc. Will discuss it in a different post. 🙂


SSL Setup

* Requirements: domain address which is mapped to your Instance Public IP.

  • Setup SSL certificate with certbot is quite easy. We just need to install some packages and a little bit of setup
  1. Install packages - sudo apt install certbot python3-certbot-nginx
  • Before we generate the certificate, we have to add our domain name in our django.conf
  1. Change existing server_name to - server_name test.domain.com; (if you want to map multiple domains then use as space separate like this - server_name test.domain.com testing.domain.com;)
  • After setup is done, run the below two commands
  1. sudo certbot certonly --nginx
  2. sudo certbot certonly --nginx
  • Now we have to restart our nginx - sudo service nginx restart
  • Now you can visit your secure website 😊.

Django Static File issue Fix after deployment (production)

You might notice that in production, CSS/JS/Images/Fonts files are not working for /admin.
This is because of the Static folder issue. In the local development environment Django use Python HTTPServer, and it automatically handles Static files. But in production our server is running through nginx, that's why we have to do little setup. Let's do the setup.

  • First, we have to create one static folder in our root directory.
  • Now inside our project main settings.py we just need to add one line of code

STATIC_ROOT = BASE_DIR / 'static/'

  • Now run this command python3 manage.py collectstatic3. With this command, Django will copy all static assets into your Root Static Folder. In our case, it's the Static folder.

  • Now one setup is left, which is nginx,

Go to your nginx django.conf file and add the below code after the location code block

location /static/ {
               autoindex on;
               alias /home/ubuntu/PROJECT_FOLDER/static/;
}
  • Now restart nginx server - sudo service nginx restart.

nginx

Nginx, pronounced like “engine-ex”, is an open-source web server that, since its initial success as a web server, is now also used as a reverse proxy, HTTP cache, and load balancer.

Nginx is built to offer low memory usage and high concurrency. Rather than creating new processes for each web request, Nginx uses an asynchronous, event-driven approach where requests are handled in a single thread.

With Nginx, one master process can control multiple worker processes. The master maintains the worker processes, while the workers do the actual processing. Because Nginx is asynchronous, each request can be executed by the worker concurrently without blocking other requests. more info

gunicorn:

Gunicorn is a stand-alone WSGI web application server that offers a lot of functionality. It natively supports various frameworks with its adapters, making it an extremely easy to use drop-in replacement for many development servers that are used during development.

supervisor:

At some point you'll likely find yourself writing a script that needs to run all the time - a "long running script". These are scripts that shouldn't fail if there's an error or ones that should restart when the system reboots.

To accomplish this, we need something to watch these scripts. Such tools are process watchers. They watch processes and restart them if they fail, and ensure they start on system boot.

And Supervisord is a simple and popular choice for doing these tasks and monitoring our process

collectstatic

Using the collectstatic command, Django looks for all static files in your apps and collects them into a single location that can easily be served in production, i.e. the STATIC_ROOT. In our case, we are telling Django that when we run python3 manage.py collectstatic, gather all static files into a folder called static in our project root directory.

That's it for this article. I hope you found it useful. Feel free to drop your comments below and like the post.

Top comments (2)

Collapse
 
s_mosta profile image
Sergio Morstabilini

Hi there, thanks for the tutorial.
Just a quick note:

After setup is done, run the below two commands
sudo certbot certonly --nginx
sudo certbot certonly --nginx
Enter fullscreen mode Exit fullscreen mode

The commands are equal.

Collapse
 
maorkavod profile image
maorkavod • Edited

Personally, I don't use AWS EC2 to host my websites.

AWS Lightsail is a service that is built for small sites & is super easy to maintain. Additionally, Lightsail is a lot cheaper than EC2.