How to Deploy a Production Grade Flask application to an AWS EC2 Instance using GitHub Actions: Part Three.

Using nginx with a domain name to deploy the application.

Lyle Okoth
7 min readJun 8, 2022

This is the third article in a series that takes the reader through the process of deploying a production ready flask API to an AWS EC2 instance. In the previous article we:

  • Created a service that automatically starts our application when the EC2 server starts up.
  • Created a workflow that automatically pushes changes to our application to the development server and restarts the application.

In this article, we will accomplish two main tasks:

  • We will use nginx to route traffic to our server.
  • We will add a domain name to our server.

Step 1: Test that the application works.

Head on over to the EC2 server that hosts our application and start it up. Navigate to the instances dashboard, then select the checkbox next to the EC2 server, then on the Instance state drop-down, select Start instance:

Then on the command-line, use curl to test it out:

curl <instance-public-ip-address>:5000

You should get:

{
“hello”: “from template api auto-deployed with GitHub actions!”
}

Step 2: Test that changes are automatically deployed

For this, open up theflask-ec2-deployment/api/blueprints/default/views.py file and update it with (replace flask-ec2-deployment with your project’s name):

We just added ‘and being tested’. Then commit your code to the features branch. Once all the checks have passed, make a pull request, let all the checks pass then merge your code into the development branch.

My pipeline failed, due to an issue with my key pair. So when we turn off the AWS EC2 server, then bring it up later again, the AWS EC2 public instance name changes. So we need to update that value. On your instance dashboard, select the checkbox next to your EC2 name, then under the Details tab, you should be able to get the Public IPv4 DNS. Copy it:

Then head on over to GitHub and replace the previous value of HOST_NAME with this value. Then re-run the pipeline. Under the Actions tab in your GitHub account, select the failed Features workflow:

Then select the Re-run failed jobs from the Re-run jobs drop-down:

Let all the checks complete then confirm the merge. Once all the checks are complete you can test the changes. Then to test whether the deployed application was updated, just test the application response using curl:

curl <instance-public-ip-address>:5000 # use the value we just copied

You should get back:

{
“hello”: “from template api auto-deployed with GitHub actions and being tested!”
}

Step 3: Install and use nginx

Nginx is a fast production grade server that handles SSL really well. Our current server, gunicorn is not built for these tasks rather it is used to serve up simple APIs. So, let us go ahead and install nginx. Ssh into your EC2 instance:

ssh -i “ec2.pem” lyle@<instance-public-address>

Replace lyle with the user that you created and instance-public-address with your EC2 server’s public address the value that you used with the curl command). Then install nginx:

sudo apt install nginx -ysudo systemctl enable nginx # so that it starts up when server is startedsudo systemctl start nginx # start it upsudo systemctl status nginx # check whether it is running

Ensure that it is running and enabled:

To test out nginx, we need to enable HTTP and HTTPS traffic into our server. From the instance dashboard, select the checkbox next to the EC2 instance name, then under the Security tab click on the link under the Security groups:

Scroll down to the Inbound rules section, then select the Edit inbound rules button:

Click on the Add rule button:

Then add a HTTP rule from the Type drop-down, the Protocol and Port range will be auto-filled then under Source drop-down select Anywhere. Do the same, for the HTTPS rule. Then click on the Save rules button.

Now, test the nginx server by going to http://server-IP (server-IP is the instance public IP address obtained from the instance dashboard) and you will see:

Also notice the Not Secure label. We will address this later. For now, let us make nginx server up our website. Open up /etc/nginx/sites-available/default:

We want to update this config such that any traffic to the ‘/’ and any path after ‘/’ such as ‘/users’ to our server is redirected to our application. So delete the three lines within the curly brackets and replace them with:

The config file should look like this after the update:

Restart nginx:

sudo systemctl restart nginx

Now try out the http://server-IP and you will get:

To get rid of the pesky Not secure message on the site, we need to enable SSL. This requires a domain name as well as an elastic IP address from AWS.

Step 4: Purchase a domain

Head on over to Namecheap and create an account, then sign in. Then select the Domains tab:

and enter the domain you want i.e techwithlyle.com and then press the Search button:

If it’s available select Add to cart:

The rest of the steps are just to check out the item. You will need a credit card or PayPal account though to finish the purchase. In my case, I bought a domain called twyle.xyz and that is what we will use.

Step 5: Create an Elastic IP

To use the domain name we just purchased, we will need to point it tour our server IP address. However the default IP address issued out by amazon may change as you noticed earlier on when we had to update the HOST_NAME secret for our updates to be pushed to our EC2 instance. So to overcome this, we will create an elastic IP address that will not change over time. I have created a wonderful article on how to do this called How to Create an Elastic IP Address on AWS and Point Your Domain to it. Go through it an then come back to continue with this tutorial.

If you followed the steps outlined in the tutorial, you should be able to access the site using the domain name. Navigate to www.twyle.xyz and you should get back (replace twyle with your own domain name):

Step 6: Add SSL to our website

On the command-line (these are instructions from certbot)

ssh -i “ec2.pem” lyle@<instance-public-address> # ssh into the ec2sudo snap install core; sudo snap refresh core # update snapdsudo snap install --classic certbot # install certbotsudo ln -s /snap/bin/certbot /usr/bin/certbot # prepare the certbot commandsudo certbot --nginx # create and install an ssl certificate for nginx. 

Now if you navigate to dev.twyle.xyz you should get (I could not register the www.twyle.xyz domain since I registered that just a couple hours ago to a different server):

At this point, the Not secure message is gone.

Conclusion

In this tutorial, we accomplished the following:

  • We set up nginx to route HTTPS traffic to our server.
  • We then added a domain tour application for easier access from the internet.
  • We then used certbot to generate an SSL certificate for our site.

And that’s it for this tutorial.To make this application truly production ready, we still need to include a database as well as logging and monitoring. We still also have not set up the staging and production environments. In the next tutorial, we will set up a database and logging for our application.

I hope you enjoyed it and learnt something. Give it a clap or share it out and do not hesitate to reach out to me in-case of an issue. The code for this application is here flask-ec2-deployment. I am Lyle, a junior software engineer with a passion for developing, testing and deploying scalable services. You can find me on twitter, linkedin, github and here’s my portfolio. See you next time.

--

--

Lyle Okoth

Conversational AI Engineer | Building conversational AI agents that work with humans to automate various workflows.