Deploying a Flask application on AWS

An end-to-end example using Amazon’s Elastic Beanstalk and RDS

Flask is awesome. It’s the easiest way to learn web development. Start small, and then you can quickly add any upgrades you need — email, databases, forms, etc.

Amazon Web Services is fantastic. There are a ton of cloud platforms out there, but none are more flexible than AWS. It seems like you can do anything on Amazon — host websites, create scalable databases, send emails, text messages, stream live video from your home — the possibilities are endless.

The two seem like a natural fit. Create a killer Flask app, and push it to AWS. Easy, right?

But there are a surprising lack of examples on the web. The official documentation is recommended, but lacks visuals which can help beginners.

Don’t get me wrong, there are some good blog posts that help with common stumbling blocks. But I couldn’t find an end-to-end example for deploying a Flask application to AWS.

So here’s a step-by-step tutorial that will launch your Flask application to AWS Elastic Beanstalk. It also uses AWS RDS for a database backend.

Let’s dive in:

Step 0: Create an AWS account

What are you waiting for? Sign up!

Note: AWS requires a credit card for registration. But our example will exist entirely on the AWS Free Tier, so you won’t be charged.

Step 1: Download the Flask example code

Clone the Github repo: https://github.com/inkjet/flask-aws-tutorial

We’re going to deploy a simple app that reads and writes from a database using Flask-SQLAchemy. Dig into the code if you’d like — it should run locally if you run python application.py (after you set you the environment in Step 4).

Step 2: Set up your Flask environment

In the directory where the example code exists, create a Python virtual environment.

$ virtualenv flask-aws

$ source flask-aws/bin/activate

Then install the packages needed for this demo with:

$ pip install -r requirements.txt

(Note the PyMySQL package requires the SQL Development headers. If you’re on Linux, you’ll have to do a “sudo apt-get install libsqlite3-dev” on Ubuntu or “yum install libsqlite3-devel” on RedHat.)

Step 3: Create a MySQL database using AWS RDS

If you’ve followed the excellent Miguel Grinberg tutorial (buy his book, too), he creates a local database for his tutorial. To make things more interesting, we’ll host our database on AWS using RDS.

(Note: if you want to skip this step and use a local database file, uncomment the local DB line in config.py and proceed to Step 4.)

On the AWS console, go to Services > RDS.

Next, click “Launch a DB Instance”

Select “MySql Community Edition”

Select “No” for multi-AZ deployment — this will keep us in the Free Tier.

Select “DB Instance Class” as db.t2.micro (keeps us in the Free Tier), “Multi-AZ Deployment” as “no” (they’re really pushing that, right?), and set up your DB instance name, user name, and password. Below is what I chose. Make sure to write down your password!

For the advanced DB settings, leave the security group is “default” (we’ll come back to that later) and set the Database Name to whatever you’d like. Everything else can stay as-is. This is what I chose:

Click “Launch DB Instance” then “View DB Instances.” And then sit back and wait. And wait. It took about 5 minutes for my DB instance to spin up. Go have something to eat.

When your database is finally ready, the status will be “available” and you’ll see this:

Step 3.5: Modify the permissions on your DB

For the longest time, this tripped me every time when attempting to spin up a new DB. AWS locks down all new compute instances by default — any new database, EC2 instance, etc. — they’ll all be cut off from external access unless you specifically allow it. Good for security purposes, but a pain if you forget.

Go to your AWS dashboard, click “EC2” and you’ll see the screen below. Click “Security Groups”:

Click “Create a Security Group.” Now you can modify who can access your DB. You can restrict it to your computer (AWS can detect your IP range), or you can open inbound traffic to everyone. I like to live on the edge, so I let everyone access it (0.0.0.0), like so:

Name this group something you’ll remember (like “rds_access”), and then click “Create.”

Now go back to your database and click “Instance Actions > Modify”:

Scroll down to “Network and Security” and change it to the security group we just created.

Click “Apply Immediately” advance to the next screen, and then “Modify DB Instance.”

Whew, now we’re done with setting up the DB. Now let’s populate it.

Step 4: Add tables to your DB instance

Hey, we finally touch some Python code! Let’s edit the URI for the for the DB so your Flask code can access it.

First, go to your AWS console, RDS, and click on “DB Instances” Copy the “Endpoint” string — this is the URL to your AWS DB:

Edit the config.py file to include the username, password, and db name you entered earlier, in the format:

SQLALCHEMY_DATABASE_URI = ‘mysql+pymysql://<db_user>:<db_password>@<endpoint>/<db_url>’

(Ignore this if you’re using a local database.)

Now create the tables in your (currently) empty database by running

$ python db_create.py

Step 4.5 (Optional) Play with the Flask App

You can check out the site before you deploy it. Now that your environment is set up, run the app by

$ python application.py

And you can see it in your browser at http://0.0.0.0:5000

Step 5: Set up Elastic Beanstalk Environment

Amazon has made deployment easy with their Elastic Beanstalk Command Line Interface (EBCLI). It’s available on PyPi, so in your virtual environment type:

$ pip install awsebcli

Once that finishes installing, we can initialize and deploy our Flask app. We could do this using our AWS root access. However, let’s follow AWS Best Practices and create a new user for this demo. This will keep our master ID and secret key (which you should have stored somewhere) safe.

To create a new user, go to the AWS Console and select Identity and Access Management (IAM):

Next, select “Create New Users”:

We’ll only need one user for this demo, and we’ll call him/her “flaskdemo”:

Click “Create” and the user is established.

IMPORTANT: You need to click “Show User Security Credentials” and copy down the ID and Secret Key for this user. We’ll need this to connect via the EBCLI interface.

We’ve created a user, but they have no permissions (just like our database). Let’s grant this user admin access. In the IAM window, select “Groups” and then “Create New Group”:

In the next screen, type “admin” as the group name:

Click “Next” and you’ll see a list of preconfigured Admin accounts with varying degrees of access:

Many of these policies are specialized for specific AWS services. For simplicity choose the first one, “AdministratorAccess” and click “Next Step”.

Click “Create Group” and the admin group is now available.

But we’re not done yet. The final step (and one that I sometimes forget) is to assign this group to our user. So back in the IAM main page, select “Users”, and then click the “User Actions” drop down:

Click “Add User to Groups” and we’ll see our “admin” group:

Click “Next” and we’ve created an admin.

Now let’s finally initialize our Elastic Beanstalk environment. In your command window, type:

$ eb init

You’ll see:

Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-southeast-1 : Asia Pacific (Singapore)
7) ap-southeast-2 : Asia Pacific (Sydney)
8) ap-northeast-1 : Asia Pacific (Tokyo)
9) sa-east-1 : South America (Sao Paulo)
(default is 3): 1

Chose the location closest to you (mine is Northern Virginia). Next you’ll be prompted for the AWS ID and Secret Key for the user “flaskdemo” you saved somewhere:

You have not yet set up your credentials or your credentials are incorrect
You must provide your credentials.
(aws-access-id): <enter the 20 digit AWS ID>
(aws-secret-key): <enter the 40 digit AWS secret key>

Next you’ll see:

Select an application to use
1) [ Create new Application ]
(default is 1): 1

Next we create the environment name. Hit “Enter” to use the default values:

Enter Application Name
(default is “flask-aws-tutorial”):
Application flask-aws-tutorial has been created.

Now the EBCLI just wants to make sure we’re using Python:

It appears you are using Python. Is this correct?
(y/n): y

Select your Python version. I’m a fan of 2.7 and wrote this example using it, but feel free to choose 3 if that’s your preference:

Select a platform version.
1) Python 3.4
2) Python 2.7
3) Python
4) Python 3.4 (Preconfigured — Docker)
(default is 1): 2

You have the option of creating an SSH connection to this instance. We won’t need to use it, so I recommend “no.” (If you need to ssh into this instance later, you can change the preferences of your EC2 instance from the AWS console later.)

Do you want to set up SSH for your instances?
(y/n): n

Okay, now we’re all set up. Time to deploy this bad boy.

Step 6: Deploy our Flask Application

We’re so close, but we can’t push the existing Python code to Elastic Beanstalk just yet. As savvy users have pointed out, you’ve updated the config.py file with your new RDS endpoint and those changes need to be commited to the git repository you cloned. Fortunately this is a simple process. At your command line, type:

$ git add config.py

$ git commit -m “Updated RDS endpoint”

$ git push

Now your code is staged and ready for deployment. (And if you’ve modified any other files, do a “git add” on them too.)

From the command line, type:

$ eb create

Now we have to create an environment name and DNS CNAME for our app. The domain name is the most important — it will show up in the URL as http://<dns cname>.elasticbeanstalk.com. It has to be unique, or the command line will make your choose another:

Enter Environment Name
(default is flask-aws-tutorial-dev):
Enter DNS CNAME prefix
(default is flask-aws-tutorial-dev): thisisacoolflaskapp

Once you’ve selected a unique DNS CNAME, you’ll see status updates as the app is deployed. They’ll look like this:

WARNING: You have uncommitted changes.
Creating application version archive “c1bf”.
Uploading flask-aws-tutorial/c1bf.zip to S3. This may take a while.
Upload Complete.
Environment details for: flask-aws-tutorial-dev Application name: flask-aws-tutorial Region: us-east-1 Deployed Version: c1bf Environment ID: e-a2ppnms3xj Platform: 64bit Amazon Linux 2015.03 v1.4.1 running Python 2.7 Tier: WebServer-Standard CNAME: thisisacoolflaskapp.elasticbeanstalk.com Updated: 2015–05–28 16:20:28.363000+00:00
Printing Status:
INFO: createEnvironment is starting.
INFO: Using elasticbeanstalk-us-east-1–611827146380 as Amazon S3 storage bucket for environment data.
INFO: Created load balancer named: awseb-e-a-AWSEBLoa-1DZU2FYBGSE55

Etc…

When the uploading finishes, you’ll see:
INFO: Application available at thisisacoolflaskapp.elasticbeanstalk.com.
INFO: Successfully launched environment: flask-aws-tutorial-dev

Point your web browser to that URL and you’ll see your Flask app live!

Step 7: Check out the app

The Flask app in this example allows you to read and write to your RDS database. First you can write strings:

Click “Submit” and you’ll see:

After submitting a few, you can view the most recent n submissions, where n is a number between 1 and 9:

And that’s it. Hopefully this helps you get off and running with AWS.

Finally, making updates to your site is easy. Whenever you update a file, simply type

$ eb deploy

when your new changes are ready. You can add images, email support, register your site with a .com (I recommend AWS Route 53 if you’re going to stay within AWS), and so much more.

Congrats on your first AWS site, and good luck!