How to Deploy your Flask app to AWS Elastic Beanstalk
Three years ago, I was a new developer trying (and failing) to deploy my simple Python Flask application to Amazon Web Services' (AWS) Elastic Beanstalk. In the process, I reviewed this documentation from the makers of Flask on how get started making simple Flask apps, this documentation from AWS on Elastic Beanstalk, and this blog post on using the two together. All were helpful, but I was so new to development that even with these and other resources, I found the process horribly frustrating, and I ran into one maddening error after another.
These days when I deploy my Flask apps to Elastic Beanstalk, I still run into some of the same hurdles that I encountered back then. Fortunately, over time I've learned how to power through each error more quickly. In an effort to continue making this process easier for myself, and to assist others who may still be struggling, I've created the following step-by-step guide on deploying Flask apps to AWS Elastic Beanstalk. A few notes about this guide:
- Depending on your comfort level with the language and tools presented here, it will take you at least an hour to complete this tutorial from start to finish.
- I use Python 2.7 throughout this tutorial. If you are using a different version of Python, you may need to make adjustments accordingly.
- Be sure to check out the icons throughout this post for screenshots that will help you confirm that you're seeing what you're supposed to be seeing in each step.
With that, let's get started!
Step 0: Create a virtual environment!
Ok, to be fair, you can totally deploy a Flask application without using a virtual environment. However, I feel so strongly that you should run your app in a virtual environment that I'm including this as a step in this tutorial. Every time I've tried to deploy a Flask app to Elastic Beanstalk outside of the safety of a virtual environment, I've encountered at least one vexing error that ate up valuable time, the most recent of which was this one —an error about about the Python six package that I didn't even know was needed for what I was trying to accomplish. Believe me, you do not want to spend time debugging this or similar errors that can easily be avoided by using a virtual environment. To spin up a virtual environment:
$ pip install awscli
Collecting awscli Using cached https://files.pythonhosted.org/packages/22/13/5c2df72102ab95f13a0b2ad470500327765e163d6867afd6421316fa6692/awscli-1.16.81-py2.py3-none-any.whl Collecting s3transfer<0.2.0,>=0.1.12 (from awscli) Using cached https://files.pythonhosted.org/packages/d7/14/2a0004d487464d120c9fb85313a75cd3d71a7506955be458eebfe19a6b1d/s3transfer-0.1.13-py2.py3-none-any.whl Collecting botocore==1.12.71 (from awscli) Using cached https://files.pythonhosted.org/packages/50/c0/cd4f8bec8a10876f0ce34f0cf264fda04e09df41d1a473a43f890c71fffa/botocore-1.12.71-py2.py3-none-any.whl Collecting rsa<=3.5.0,>=3.1.2 (from awscli) Using cached https://files.pythonhosted.org/packages/e1/ae/baedc9cb175552e95f3395c43055a6a5e125ae4d48a1d7a924baca83e92e/rsa-3.4.2-py2.py3-none-any.whl Collecting colorama<=0.3.9,>=0.2.5 (from awscli) Using cached https://files.pythonhosted.org/packages/db/c8/7dcf9dbcb22429512708fe3a547f8b6101c0d02137acbd892505aee57adf/colorama-0.3.9-py2.py3-none-any.whl Requirement already satisfied: docutils>=0.10 in /Library/Python/2.7/site-packages (from awscli) (0.14) Collecting PyYAML<=3.13,>=3.10 (from awscli) Requirement already satisfied: futures<4.0.0,>=2.2.0; python_version == "2.6" or python_version == "2.7" in /Library/Python/2.7/site-packages (from s3transfer<0.2.0,>=0.1.12->awscli) (3.2.0) Requirement already satisfied: jmespath<1.0.0,>=0.7.1 in /Library/Python/2.7/site-packages (from botocore==1.12.71->awscli) (0.9.3) Collecting python-dateutil<3.0.0,>=2.1; python_version >= "2.7" (from botocore==1.12.71->awscli) Using cached https://files.pythonhosted.org/packages/74/68/d87d9b36af36f44254a8d512cbfc48369103a3b9e474be9bdfe536abfc45/python_dateutil-2.7.5-py2.py3-none-any.whl Collecting urllib3<1.25,>=1.20; python_version == "2.7" (from botocore==1.12.71->awscli) Using cached https://files.pythonhosted.org/packages/62/00/ee1d7de624db8ba7090d1226aebefab96a2c71cd5cfa7629d6ad3f61b79e/urllib3-1.24.1-py2.py3-none-any.whl Collecting pyasn1>=0.1.3 (from rsa<=3.5.0,>=3.1.2->awscli) Using cached https://files.pythonhosted.org/packages/7b/7c/c9386b82a25115cccf1903441bba3cbadcfae7b678a20167347fa8ded34c/pyasn1-0.4.5-py2.py3-none-any.whl Collecting six>=1.5 (from python-dateutil<3.0.0,>=2.1; python_version >= "2.7"->botocore==1.12.71->awscli) Using cached https://files.pythonhosted.org/packages/73/fb/00a976f728d0d1fecfe898238ce23f502a721c0ac0ecfedb80e0d88c64e9/six-1.12.0-py2.py3-none-any.whl matplotlib 1.3.1 requires nose, which is not installed. matplotlib 1.3.1 requires tornado, which is not installed. Installing collected packages: six, python-dateutil, urllib3, botocore, s3transfer, pyasn1, rsa, colorama, PyYAML, awscli Found existing installation: six 1.4.1 Cannot uninstall 'six'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.
Install pip, if you haven't already.
Pip is a package manager for Python that makes it quick and easy to install Python
packages. There are a few different ways to install pip, as documented
here, but the easiest way
is, arguably, to just run:
$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python get-pip.py
If you run the above command and get an error about how you need to run it with sudo, just change the command to:
$ sudo curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python get-pip.py
Install virtualenv, if you
haven't already. Virtualenv is a package that allows you to create virtual
environments. Once you have pip installed, you can install virtualenv by running the
following on the command line:
$ pip install virtualenv
Now that you have virtualenv installed, you can create a new virtual environment by
$ virtualenv name_of_env
Be sure to replace
name_of_envwith whatever you actually want to call your virtual environment. In this example, I call my virtual environment
Activate your virtual environment by running
$ source flask_app_env/bin/activate.
Be sure to replace
flask_app_envwith whatever you named your virtual environment. You will know if you are in your virtual environment (as opposed to just in a general directory on your computer) when you see the name of the virtual environment that you created in front of your cursor, as seen here:
Virtual Environment Activation
Now you're ready to start building your Flask app! Within your virtual environment of course.
Step 1: Make a Flask app!
If you're a true beginner, just getting a Flask app up and running locally might be a project in and of itself, even before you attempt to deploy it to Elastic Beanstalk. Fortunately, there are lots of great tutorials like this one from the makers of Flask that will walk you through making your first app step by step.
Since this blog is a Flask app too, if you don't want to go through the trouble of making
an app from scratch right now, you can clone the repo for this blog and just use that. You
can find my blog here. If this
is your first time cloning a repo, and you need assistance, check out
reference. If you do choose to clone my repo, be sure to install all
of the requirements in the requirements file in the repo. If you don't, the app won't run.
To install all of the requirements in my project's requirements file, after you've
successfully cloned my repo locally, within the highest level directory of the project, run:
$ pip install -r requirements.txt
Regardless of how you make/acquire your Flask application, ensure the following for a smooth deployment to Elastic Beanstalk:
Flask is installed inside of your virtual environment. To install Flask inside of
your virtual environment, run
$ pip install Flaskon the command line. If Flask is already installed, you'll see a message confirming that it's already installed.
The app's application file is named
application.py(as opposed to, say,
app.py). This is the file that contains all of the routes for your app. The first line in this file is likely something like:
from flask import Flask, render_template
Flask(__name__)is assigned to
application(as opposed to, say,
"__name__"is assigned to
application.py, as seen at the bottom of this file.
Once you have your application and it has all of the attributes detailed above, I strongly
advise running your app locally before you go any further, to identify any issues that
could be harder to debug further in the process. To run your Flask app locally,
cd into your application's
Main directory. Then, on the command
$ export FLASK_APP=application.py, followed by
$ flask run. Then, in your desired browser,
http://127.0.0.1:5000. At this point, you should see your app in
the browser. If you see an error instead, go back and review what you may have missed when
creating or cloning the app.
Step 2: Make an AWS Account and Create a New User!
One note about AWS accounts if this is your first time creating one: If you're just deploying a simple Flask application (like the one you may have cloned from my GitHub repo) to Elastic Beanstalk, then AWS will only charge you $1.00 per month for the first year. However, after that first year, AWS will charge you upwards of $10 per month.
To create your first AWS account (which will be awesomely cheap for the first year, depending on everything that you choose to use it for):
- Create an account here. Note that you may be asked to enter a credit card to create a new account. If you are not asked for a credit card, then I strongly suggest proactively adding one to your newly created account, as the deployment will just fail later in the process if you don't have a credit card linked to your account. Instructions on adding a credit card to your AWS account can be found here.
Once you've created and logged into your new account, navigate to the search bar on the
main landing page, type in "iam", and select the option presented in the dropdown:
On the resulting page, select "Users" from the left hand panel, and click on the blue
"Add User" button towards the top of the page:
Enter your desired username (in the screenshot, I use my name, "Alyse"), and be sure to
select the "Programmatic Access" type from the two access type options. Once complete,
select the blue "Next: Permissions" button in the lower right hand corner of the page:
Assign "Programmatic Access"
Enter your desired group name. In the screenshot, I use the
group name "Admins". Then, select the "Administrator Access" group from the list of
available policies. Once done, select the blue "Create group" button in the lower right
hand corner of the page:
Assign "Administrator Access"
The resulting screen will confirm that you are adding your newly created user to the
"Admins" user group:
Add User to Group
Continue clicking the blue "Next" buttons on the lower, right hand corner of each page
until you get to the final confirmation page that the user has been successfully
created with permissions:
Step 3: Deploy to AWS!
Even though we created a user and permissions via the AWS UI, from here, will use the command line for the actual deployment. You'll want to do all of this from within your virtual environment. Again, you know if you are in your virtual environment when you see the name of your virtual environment in front of your cursor, as seen here:
To deploy your Flask app to Elastic Beanstalk:
Install AWS command line tools if you haven't already. These can be installed by
$ pip install awsebcli --upgradevia the command line.
cdto into your application's top level directory. This will likely be one directory level above your
Maindirectory. This is important. If you don't run everything from your top level directory, when you go to deploy your application, you will encounter errors not covered in this tutorial.
In your application's top level directory, run
eb init. This initializes Elastic Beanstalk. It will also create a git-ignored directory in your
Maindirectory. Do not delete or move this directory. If you do, your deploy will fail.
After you run
eb init, you'll be prompted to enter your default region. This is effectively AWS asking you where you want your servers to be physically located. If you hit enter, AWS will choose for you. Or, you can enter the number associated with your preferred region. If this is your first time doing this, I'd suggest just letting AWS decide for you. Since I live and work in New York City, I always enter a 1 here because I like manually confirming that the servers that I get are the ones that are physically closest to me:
eb initand Region Selection
You'll be prompted to create a name for your application. I use the name
'first_flask_app', but you can call it whatever you want:
Name the Application
Next, you'll be asked to confirm if you're using Python, and if so, which version.
Enter the appropriate responses based on what you're using. You may also be asked if
you want to set up CodeCommit, and/or if you want to use SSH for your instances. I
suggest entering 'n' for all of this for now, just to keep it simple. You can make
Language, Version, and SSH preference
Next, you'll be asked to enter a keypair for your application. If this is your first
time doing this, no options will be listed and you'll want to select the default of
creating a new keypair. If you've done this before, you'll have the option of creating
a new keypair, or selecting a keypair that you've made in the past. Regardless, for our
purposes, enter whatever number is needed to create a new keypair. You'll also be
prompted to enter a passphrase, which you can do, but I never bother with.
Now, we have to set up the environment name and DNS for our app by running
eb create. You'll be prompted to enter an environment name, DNS name, and load balancer type. It's fine to use defaults for all of this. Once you finish stepping through the prompts, you'll see some output in the terminal while Elastic Beanstalk deploys the application. It generally takes between 5 and 20 minutes to deploy, and the console output stops when complete.
Once complete, sign back into the AWS UI, navigate to the search bar on the main
landing page, type in "elastic beanstalk", and select the option presented in the
Elastic Beanstalk Search
In the Elastic Beanstalk dashboard, in the left hand panel, select the 'Configuration'
option. On the resulting page, in the 'Software' box in the upper left hand corner,
select the 'Modify' text towards the bottom of this box.
Elastic Beanstalk Configuration
On the resulting page, update the value of WSGIPath to
Main/application.py, and update the value of Directory to
After you've made the changes above, your application will update again. This update
will take another 2-10 min. Once complete, navigate back to the main Elastic Beanstalk
dashboard. Towards the top of the page, you'll see a 'URL'. If everything has completed
successfully, click on this URL to be directed to your site:
Elastic Beanstalk Landing Page with app URL
That's it! You've just successfully deployed your Flask application to Elastic Beanstalk!
That was a lot, but now that you have it deployed and out into the world, updating it is
easy. Every time you want to deploy your latest changes to Elastic Beanstalk, simply run
eb deploy command that you ran earlier. Happy Pythoning!