How to Deploy the Flask/Django App on AWS EC2 with Gunicorn + Ngnix With Free SSL Certificate ( The ultimate production ready guide)

Abhishek Meena
14 min readMay 25, 2019

Hey, everyone from last two months I was working on my flask project for my organisation, and previously we deployed it on Heroku, but it’s not flexible, so we need a better alternative.

So I did research and decided to deploy it on AWS, but when I began this journey I faced many problems, but finally, I got success, but during this time I realised that there is no ultimate guide for production-ready deployment of WSGI apps over AWS with SSL, front-end reverse proxy and load balancing.

So, This guide will walk you through that how you can deploy a Flask/Django based microframework application on Ubuntu 18.04. This guide gives you everything you need to get up and running your WSGI application

Introduction

This guide will walk you through that how you can deploy a Flask/Django based microframework application on Ubuntu 18.04. This guide gives you everything you need to get up and running your WSGI application

What’s Covered

1. Setting up a new Amazon EC2 instance

2. Configuring EC2 and cloning our flask/Django project

3. How to set up the Gunicorn application server

4. How to launch the application

5. Configuring Nginx to act as a front-end reverse proxy

6. How to Point Domain to Amazon Web Services (AWS) EC2 Instance

7. Getting a free SSL certificate

8. Setting up your Load Balancer

9. Pointing your Domain to the Load Balancer

Prerequisites

Before starting this guide, you should have

  • Please go to AWS and register for an AWS account, in case you already have one make sure you have verified it and added a payment method.
  • A flask/Django framework based application and managed by git repository and make sure your repository is pushed to the remote origin and for more information how Git works, please visit Introduction to Git and GitHub and for developing a flask application step by step I’ll personally recommend this guide The Flask Mega-Tutorial
  • A domain name configured to point to your server. You can purchase one from AWS | Route 53 or get one for free on Freenom.

Step-1 Setting up a new AWS EC2 instance

This part is easy. Log on to the Amazon console and under services click EC2. Click on the launch instance button. It looks like this:

Then you have to select which AMI (Amazon Machine Image) you want. This is the OS the instance will use. Typically you’ll wish to a Linux instance, but you might want something different depending on your needs. I’m going to choose Ubuntu Server 18.04 LTS

Click select and then select your instance type. This is to configure how much RAM your server will have, how much processing power, the size, and kind. I go with the defaults. Keeps things easy.

Selecting an existing key pair or creating a new key pair. Click select and then select your instance type. This is to configure how much RAM your server will have, how much processing power, the size, and kind. I go with the defaults. Keeps things easy.

Finally, review all settings and configuration related to your instance and if everything is okay, then launch it.

Step-2 Configuring EC2 and cloning our flask/Django project

First of all, we need to install pip, which is a package distribution manager in python. AWS Ubuntu Server 18.04 LTS comes along with python3, but we need to install pip separately by the following command:

Then we also need to install dependency for creating a virtual environment in python virtualenv by the following command

Now we need to create and virtual environment and then need to activate it.

Now we will clone our remote repository from GitHub which contain our WSGI application files.

note: if your application repository is private it will ask you for your GitHub/BigBucket credentials

Once, our repository is cloned, we need to switch to the root folder of our application and install all dependencies for the project which is listed in requirements.txt through simple pip command as follows:

Step-3 How to set up the Gunicorn application server

We can do this by only passing it the name of our entry point. This is constructed as the name of the module (minus the .py extension), plus the name of the callable within the application. In our case, this is myproject:app.

We’ll also specify the number of workers, threads, interface and port to bind to so that the application will be started on a publicly available interface with more flexibility:

Now we will configure security group’s inbound rules so we can access port 8000 from our browser through instance external ipv4 address and we will also add HTTP, HTTPS and all traffic rule because we will use them further and we will also allow them to be accessed from anywhere.

Visit your server’s IP address with 8000 appended to the end in your web browser again:

http://your_server_ip:8000

You should see your application’s output: When you have confirmed that it’s functioning correctly, press CTRL+C in your terminal window.

We’re now done with our virtual environment so that we can deactivate it

deactivate

Unit File for Serving Gunicorn as an automated service

Any Python commands will now use the system’s Python environment again.

Next, let’s create a systemd service unit file. Creating a systemd unit file will allow Ubuntu’s init system to automatically start Gunicorn and serve the Flask application whenever the server boots.

Create a unit file ending in .service within the /etc/systemd/system directory to begin:

#Unit File

• Inside, we’ll start with the [Unit] section, which is used to specify metadata and dependencies. Let’s put a description of our service here and tell the init system only to start this after the networking target has been reached

• Next, let’s open up the [Service] section. This will specify the user and group that we want the process to run under. Let’s give our regular user account ownership of the process since it owns all of the relevant files. Let’s also give group ownership to the www-data group so that Nginx can communicate easily with the Gunicorn processes. Remember to replace the username here with your username

• Next, let’s map out the working directory and set the PATH environmental variable so that the init system knows that the executables for the process are located within our virtual environment. Let’s also specify the command to start the service.

• Finally, let’s add a [Install] section. This will tell systemd what to link this service to if we enable it to start at boot. We want this service to start when the regular multi-user system is up and running:

Systemd requires that we give the full path to the Gunicorn executable, which is installed within our virtual environment.

Remember to replace the username and project paths with your information

Our file will look something like this:

With that, our systemd service file is complete. Save and close it now.

We can now start the Gunicorn service we created and enable it so that it starts at boot

Step 5- Configuring Nginx to act as a front-end reverse proxy

Now first thing first we will install Ngnix service on our machine and to do so we will use the following set of commands.

Our Gunicorn application server should now be up and running, waiting for requests on the socket file in the project directory. Let’s now configure Nginx to pass web requests to that socket by making some small additions to its configuration file.

Begin by creating a new server block configuration file in Nginx’s sites-available directory. Let’s call this myproject to keep in line with the rest of the guide

#Server block file

  • Open up a server block and tell Nginx to listen on the default port 80. Let’s also tell it to use this block for requests for our server’s domain name
  • Next, let’s add a location block that matches every request. Within this block, we’ll include the proxy_params file that specifies some general proxying parameters that need to be set. We’ll then pass the requests to the socket we defined using the proxy pass directive.
  • Port and server name can be multiple, we are using port 80 for HTTP request and port 433 for https request, and when we have multiple domain/server name, we can use various server_name.

Finally, our server block file will look like this

Save and close the file when you’re finished.

To enable the Nginx server block configuration you’ve just created, link the file to the sites-enabled directory:

To enable the Nginx server block configuration you’ve just created, link the file to the sites-enabled directory:

With the file in that directory, you can test for syntax errors:

If this returns without indicating any issues, restart the Nginx process to read the new configuration

You should now be able to navigate to your server’s domain name in your web browser

http://your_domain

You should see your application’s output:

Step-6 How to Point Domain to Amazon Web Services (AWS) EC2 Instance

  1. Open the Amazon Route 53 console at https://console.aws.amazon.com/route53/.
  2. If you are new to Amazon Route 53, you see a welcome page; choose to Get Started Now for DNS Management. Otherwise, choose Hosted Zones in the navigation pane.
  3. Choose Create Hosted Zone.
  4. For Domain Name, type your domain name.
  5. Choose to Create.
  6. Click the Hosted Zone, edit recordset.
  7. Click on create a recordset and create A type recordset
  8. In the value, add IPV4 address of your EC2 instance
  9. Change your DNS file to point to the IPv4 address
  10. Go to your domain purchased console (This would be in something like GoDaddy). And click on DNS Management and scroll down and add custom nameservers obtain from Route 53
  11. Wait for some time it will take 5–10 minutes to transfer your DNS management to route53
  12. Add www. Extension of your domain name as an alias to your domain name to do to create a new A type record and click Yes on alias and select your main domain recordset

Now try again with your domain name just like:

http://your_domain

Step 7 getting a free SSL certificate and its configuration

We’ll do this using ACM, AWS’s certificate manager. Click on services, search ACM and click on Certificate Manager.

Click Request a Certificate. You want a Public Certificate. Click on Request a Certificate and add all your domain names to the box. This should only include the main domain (also referred to as the naked domain) aka mypage.com and not things like mypage.com/blah if you have other versions like www.mypage.com or blog.mypage.com add those too and click next.

Now AWS needs to verify you are the owner of that domain. Select DNS Validation if you have access to the DNS settings (this would be through Route53, Namecheap, GoDaddy or any other domain name provider) or Email Validation if you do not. DNS validation is better and faster. If you are using Route 53 (which I recommend), then the remaining setup is very easy since AWS can add the required records for you to the DNS settings. Otherwise, you will have to copy and paste them in. Save your changes, and then you should then see something like this

If you are using Route 53 an additional button will be available offering to add the CNAME Records to your DNS (shown below). Click it for each version of the domain (the www and non-www version and any other subdomains you added in the previous step). Otherwise, copy the name and value and add it as a CNAME record to your DNS settings. Each version requires its record, so be sure to add all of them to your DNS settings.

Once AWS verifies everything, the validation status will update to say Success in green. This may take some time (0–30+ minus but typically around 5) so don’t worry if it doesn’t happen immediately.

Step-8 Setting up your Load Balancer

Before setting up a load balancer, first, we need to create a Target Groups, also on the left side of the EC2 settings and just below Load Balancers, and create a new target group.

Give it a name and use HTTP as the protocol with a port value of 80 (the same as the port your actual server is listening on).

Select it, click on Targets in the bottom panel and then edit. You’re going to select your EC2 instance in the bottom and then click Add to registered and be sure the port is 80 and then Save. It should now appear in the top part as a registered target.

#load balancer

Now we need to configure the load balancer. This is also found in the left side panel in EC2. A load balancer makes it easy to evenly distribute traffic to your site to the multiple servers that are running it. We won’t be making use of this aspect (since we only have one instance running), but that is its main function. Open up its page and click Create Load Balancer.

We’ll be using the first option, HTTP and HTTPS. Click and give it a name. Under Load Balancer Protocol we’ll want to add HTTP and HTTPS as options. The HTTP option should be set to use port 80 and the HTTPS option port 443. Choose some availability zones (2 are required at a minimum). The setup should then look like this:

Once this is done click next.

This is where you connect the SSL certificate to the Load Balancer. Select Choose a Certificate from ACM and the cert you just made from the drop-down menu. The default security policy is good to go.

See, not to bad and we’re almost done.

Now select security group which will define ports and inbound rules to the load balancer I’ll recommend using security group of your EC2 instance because we pre-configured it earlier

Now we need to select the target group that we created earlier before creating the load balancer

Finally, now you have to review and cross-check all parameter and when you think everything is perfect click on submit and if everything went successful you will see something like this.

now we need to redirect HTTP port to HTTPS, for that go to listeners and click on view/edit option on HTTP/80

Click on + icon next Rules (top-left) then click on Insert Rule.

Click on Insert Rule
Enter your old domain in IF section and select Redirect to… in THEN section
Enter details of the new domain in THEN section

Here we are setting up redirection for http://www.myolddomain.com to https://www.mynewdomain.com, if you want setup direction to a HTTP site then change it appropriately.

We can also use the above procedure for following commonly used redirects:

http://mynewdomain.com to http://www.mynewdomain.com or https://www.mynewdomain.com

http://www.mynewdomain.com to https://www.mynewdomain.com

Path-based redirection

We can also redirect a particular path of one domain to other using Path condition as shown in the above picture.

You can follow the above steps to add more site redirection rules to HTTP listener.

Click on HTTP: 443-View/edit rules to add HTTPS site redirections

To add HTTPS site redirection rules, click on View/edit rules for HTTP : 443 (HTTPS) listener in ALB Listeners tab and follow the same steps as HTTP listener.

Use CNAME of the ALB to configure your site(s) DNS settings

Use the DNS (CNAME) of the ALB to configure the DNS settings of the sites for which you want the redirection to happen.

Step-9 Pointing your Domain to the Load Balancer

The last and final step is to update the DNS records for your site to now point to the load balancer.

Go to Route 53 in the console and open up the settings for your Domain.

If you don’t have them already, you’ll need to add two A records. If you already do have them, you’ll need to update them.

For type, select A record and then just below it you’ll see a yes or no option for Alias. Choose Yes.

Then click on the textbook to the right of Alias Target and select the load balancer you just made from the list.

AND THAT’S IT!!!

When a request comes into your domain (whether it be HTTP or https), Route 53 will direct it to the load balancer which will use the target group to send it to the EC2 instance.

If you run into any problems google the service you were working with (ACM, EC2, Route53, etc.)or drop a comment below.

THANKYOU!

If you like this blog, please do share with your friends and help more people and if you have any questions or queries please do let me know in the comment section I’ll try my best to get back to you as soon as possible

--

--