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

Create the Development Environment.

Lyle Okoth
9 min readJun 5, 2022

In these series of article, I will take you through the process of deploying a production ready application to AWS using the EC2 service. We will do the following:

  • Create EC2 instances for deploying the development, staging and production versions of the application.
  • Set up a development workflow that includes a features branch, a development, staging, release and production branches.
  • Create Elastic IP address on AWS.
  • Purchase a domain on Namecheap and associate it with our Flask application using AWS Route 53 service.
  • Use nginx and gunicorn to deploy the Flask application on the EC2 instances.
  • Use GitHub Actions to automate the deployment of our application.

Introduction

In this article, we will do the following:

  • Create the local development environment.
  • Create, test and deploy a simple flask application locally.
  • Create an EC2 instance with Ubuntu and manually deploy the application.

Step 1: Create the local development environment

We will use an existing application template to build our application. Head on over to the api-v3 template repo and click the Use this template button. Give your application a suitable name and description (mine is called flask-ec2-deployment) , create it then clone it in order to work on it locally.

Step 2: Create, test and deploy a simple flask application locally.

Once cloned, navigate into the project directory then launch it:

cd flask-ec2-deployment #navigate to the project directorypython3 -m venv venv # create a virtual environmentsource venv/bin/activate # activate the virtual environmentmake all # Command that installs dependencies and launches the app

The make all command does the following:

  • Updates the package manager, pip.
  • Installs the project development requirements.
  • Installs the project runtime requirements.
  • Installs the pre-commit hooks that will be used for code quality checks at every commit.
  • Creates an initial tag.
  • Runs the unit tests.
  • Runs the application.

In a different terminal, check for the application output:

curl http://localhost:5000

You should get:

{“hello”:”from template api”}

To push the code to github, you will need to create a separate branch, since one of the pre-commit hooks prevents us from pushing code to the development, staging or release branch. You can modify it to include the main branch as well. Here we assume that you are using the development branch as your main branch.

git checkout -b featuresgit add .git commit -m “feat: created the initial project layout.” # ensure that your commit message starts with feat or fix to avoid commitizen, one of the pre-commit hooks, from raising an error

This command may fail, due to one or more of the pre-commit hooks installed. Just run the git add and git commit commands again. If the errors persist, try and correct them or simply comment out the pre-commit hook raising the error in the .pre-commit-config.yml file. The push your code and tags to GitHub:

git push -u origin featuresgit push origin v0.0.1 # push the tag to github. v0.0.1 is the initial tag created.

On your GitHub account make a pull request and merge the features branch into the development branch.

Step 3: Create an EC2 instance with Ubuntu.

Let us create an EC2 instance on AWS that will host our application. Log into your AWS account then on the search bar at the top, search for EC2 then click on EC2:

Then click on the Instances button on the left panel:

Then select the Launch instances button:

In the resulting page, in the Name and tags section, give it a good name, mine is simply called EC2:

In the Application and OS Images (Amazon Machine Image) Info section select Ubuntu:

Click on the drop-down, underneath the Free tier eligible label then select Ubuntu Server 20.04 LTS (HVM) SSD Volume Type:

Under the Instance type, go with the default value of t2.micro:

In the Key pair (login) section, enter the key-pair name and click on the Create new key pair link;

In the resulting window, under the Key pair name, enter a suitable name, leave the other values as they are and click on the Create key pair button. The key pair will automatically be downloaded; we will later use this key to log into the created server instance.

Under the Network settings, click on the Edit button:

Scroll down to the Inbound security groups rules:

We will allows HTTP traffic to port 5000, used by our Flask application as well as ssh traffic used by us to log remotely into this server. First let us configure ssh; under Type drop-down select ssh, the Protocol is auto-filled as TCP, the Port range is auto-filed as 22, for Source type drop-down select Anywhere.

Click the Add security group rule button:

Under Type drop-down, select Custom TCP, then in the Port range enter 5000, the Protocol is auto-filled as TCP, and in Source type drop-down select Anywhere:

Leave the Configure storage section with the defaults:

Then click on the Launch instance button. Then go to your created instance:

You should see your created instance called EC2:

Step 4: Log into your EC2 instance.

Click on the checkbox next to your newly created EC2 instance then select the Connect button:

The instructions on how to connect to your EC2 instance will be displayed:

On the command-line navigate to the downloads folder (in an Ubuntu machine) or wherever the key file was downloaded into:

chmod 400 ec2.pemssh -i “ec2.pem” ubuntu@<your-instance-hostname>

You should be logged in as the ubuntu user.

Step 5: Deploy your application on the AWS EC2 instance.

First let us update the server:

sudo apt update && sudo apt upgrade -y

Ensure that pyhon3 is installed:

python3 --version

At the time of writing this article, it was 3.8.10. Next, we install the python package manager:

sudo apt install python3-pip -y

And then let us install the python3 virtual environment package:

sudo apt install python3-venv -y

Then we create a user account, separate from the root account for security purposes:

sudo adduser lyle # create the usersudo usermod -aG sudo lyle # give them admin privileges

Next, let us add the public key to our newly created user’s account so that we can ssh into the account:

su — lyle # log into the newly created account

Create a .ssh directory in the lyle home directory and change its file permissions to 700 (only the owner can read, write, or open the directory).

mkdir .sshchmod 700 .ssh

Create a file named authorized_keys in the .ssh directory and change its file permissions to 600 (only the owner can read or write to the file).

touch .ssh/authorized_keyschmod 600 .ssh/authorized_keys

Open the authorized_keys file using your favorite text editor (such as vim or nano).

sudo nano .ssh/authorized_keys

Then open a new terminal on your local computer, navigate to the folder where the ‘ec2.pem’ file was downloaded and issue the following command (the aim is to generate a public key for the newly created account):

ssh-keygen -y -f ec2.pem

Then copy the generated value into the .ssh/authorized_keys file then save and close the file. Now to log into the newly created account from the local computer:

ssh -i “ec2.pem” lyle@<your-instance-hostname>

Then let us deploy the application. We will simply clone the application repository, install the dependencies and run the application. While still logged in as the newly created user, issue the following commands:

git clone https://github.com/twyle/flask-ec2-deployment # use your own project github linkcd flask-ec2-deployment # cd into your own project directorypython3 -m venv venv # create a virtual environmentsource venv/bin/activate # activate the virtual environmentmake install # install the project dependenciesmake run # execute the application

To see the application run, you need the EC2 instance public IP address. On your AWS account, on the instances page, select the checkbox next to the instance name in this case EC2 then on the details section you should be able to see the public IP address:

Copy it then use it with the curl command to view your application output; at a terminal on your local computer:

curl <copied-ip-adress>:5000

You should get:

{“hello”:”from template api”}

And with that we have manually deployed a Flask application to an EC2 instance. The next step is to automate the deployment from github. That will be part of the next tutorial.

When you are done, remember to shut down the EC2 instance. On the instance page, select the checkbox next to the EC2 instance then on the Instance state drop-down select Stop instance:

. In the resulting page just select the Stop button.

Conclusion

In this article we did the following:

  • Created a Flask application using a template, then tested it and deployed it locally.
  • We then committed the application code to a features branch then merged the code into the development branch.
  • We then created an EC2 instance on AWS that runs Ubuntu 20.04 server and allows ssh traffic on port 22 and HTTP traffic on port 5000.
  • We then updated the created server, installed python and venv then created a separate non-root user account for our application.
  • We finally pulled the application code from our GitHub account, then launched the application and tested that it worked.

In the next tutorial, we will automated the deployment process such that any changes made to the development branch automatically show up in the application. We will also automate the application launch, such that each time the server is started, the application starts up also.

That’s it for this article. 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.