How to deploy Python/Flask with Heroku, Azure or AWS

All the steps needed to deploy a Flask application with any of these PaaS (and connect its database in the cloud).

Rinaldo Nani
Variance Digital
12 min readOct 8, 2022

--

Flask application deployed on Heroku, AWS Elastic Beanstalk and Azure

So you developed a fantastic Flask application that runs smoothly on your local machine. Now you want to go for the real thing: deploy the application online.

One way of going online with Flask is to use one of the several new PaaS infrastructures that enable developers to build, run, and operate applications entirely in the cloud — without dealing directly with hardware and OS configuration.

This article will show how to deploy your Flask app by choosing from three of the most well-known platforms: Heroku, AWS Elastic Beanstalk, and Microsoft Azure.

1. What is required

Before the deployment tasks, a few things are required, and we give them for granted. You should have the following:

  • Python 3.x and pip;
  • Git, which is excellent both for version control and remote deployment;
  • a file in the root folder of your Flask app, named requirements.txt, which lists all the required packages to run your application (created with pip freeze > requirements.txt);
  • gunicorn (or another Python WSGI HTTP Server) as one of your requirements.

If you are missing any of these things, please install it (and use it before going any further).

It is well known that Flask comes with a small server for debugging purposes, but a serious WSGI HTTP Server is needed for online deployment, and Gunicorn is a good choice.

We suppose that you have a standard Flask application ready to be deployed; and that this application uses its SQL database to save and retrieve data.

If you don’t have a deployable application at hand, you can get our “Minimal+DB” demo app from our public GitHub repository (to learn more about the “Minimal+DB” project, read the article in the box, and try it out directly).

The database engine supporting your Flask app can be any SQL/relational database; for our “Minimal+DB” demo, we use PostgreSQL (and yes, we use pgAdmin as well).

2. Using our “Minimal+DB” demo application

Skip this section if you have your own Flask application to deploy.

2.1 Clone the “Minimal+DB” GitHub repository

To deploy [a possibly modified version of] our demo “Minimal+DB application, you must have it on your computer first. So: fetch the code from GitHub.

git clone https://github.com/VarianceDigital/minimal-db

To run the app locally, you need to install its dependencies; before doing so, we suggest creating a virtual environment for the app (to avoid polluting your PC with the app’s packages). In short, one can set up a virtual environment in the root folder of the project and install the dependencies by running these commands in the terminal:

[On Windows]
py -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
[On Mac]
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

The “Minimal+DB” app uses a small dedicated database; this means that a PostgreSQL instance must also be operational to run the demo locally. To recreate the “Minimal+DB” database structure, use the 1-create-database.sql and 2-fill-database.sql script files (found in the /database scripts/ folder).

Now that you have the app to publish online, you can start the actual deployment. The procedure will be slightly different depending on the platform you choose.

We strongly suggest going through GitHub if you want to deploy with Heroku or Azure. Unfortunately, using GitHub with AWS Elastic Beanstalk is not straightforward; in this case, the best way is to upload the code directly by creating a zip file.

3. Take your code to GitHub (good for Heroku and Azure)

After creating a GitHub account and filling in the first screen (where you choose the name of your app, etc.), GitHub asks how to import the code. Choose the following option:

“Push an existing repository from the command line”

Then run the three commands you see on the screen:

git remote add origin [url_of_your_new_repository]
git branch -M main
git push -u origin main

Refresh the webpage of your repository… et voila! there is a complete copy of your code on GitHub.

Now we can deploy the app on Heroku (or on Azure).

4. Deployment with Heroku

4.1 What files Heroku expects in your Flask project

Before anything else, ensure that your Flask project's root folder contains the following two crucial files: Procfile (without extension) and runtime.txt. The Procfile contains the instructions to start gunicorn on the Heroku cloud server. For our “Minimal+DB”, the instruction is:

web: gunicorn "minimaldb:create_app()"

Make sure to customize your Procfile for your app!

The runtime.txt file indicates which Python version Heroku should use to run the Flask app. Please have a look at our’s take on this file.

4.2 Create a Heroku app

After registering on Heroku, create a new Heroku app: click “New” in the upper right corner of your private area on Heroku and select “Create a new app”.

On the next screen, add the name of your app and choose a geographic area.

You will now find yourself in the site section dedicated to the new app. Select “Deploy” in the menu and choose GitHub as the “Deploy Method.”

Immediately below, click on “Connect to GitHub” and enter your credentials. At this point, you can select your repository; once selected, enable Heroku’s automatic deployment.

For your very first deployment, click the “Deploy Branch” (the “main” branch is the default Git branch that will be deployed).

4.3 Database connection

Heroku offers an add-on for most famous database engines. Here we will show how easy it is to add a PostgreSQL Database to your Flask app on Heroku.

Take yourself to your application’s dashboard on Heroku. Then select “Resources” in the navigation menu, and search for “Heroku Postgres” in the search bar of the “Add-ons” section. Finally, choose your plan and proceed.

At this point, you need to do two more things:

  • connect the newly added database to your Flask project;
  • restore the database schema and data (at the start, the database will be empty).

Regarding the first step, you can retrieve the necessary variables (which are automatically added by Heroku to the online set of Config Vars when the Database is created) under Settings > Config Vars > Reveal Config Vars.

The “DATABASE_URL” config var is the connection string that contains everything you need to connect your Database to your app (or to external software such as pgAdmin).

The connection string will look something like this:

DATABASE_URL = postgres://user3123:passkja83kd8@ec2-117-21-174-214.compute-1.amazonaws.com:6212/db982398

Its elements constitute the values that must be assigned to the database object in the Python code. For example, if psycopg2 is used to connect to a PostgreSQL (as we do in our “Minimal+DB” code), one could assign the needed values inspired by this code snippet:

from urllib.parse import urlparseDATABASE_URL = ''
if 'DATABASE_URL' in os.environ:
DATABASE_URL = os.environ['DATABASE_URL']
if len(DATABASE_URL)>0:
url = urlparse(DATABASE_URL)
dbname = url.path[1:]
user = url.username
password = url.password
host = url.hostname
port = url.port
sslmode = 'require'
db = g._database = psycopg2.connect(
dbname=dbname,
user=user,
password=password,
host=host,
port=port,
sslmode=sslmode)

Note that this code uses the urllib library— included in Python — to decompose the connection string and retrieve the necessary values.

If you want to connect the database to an external tool such as pgAdmin, you will assign the elements of the “DATABASE_URL” config var to their respective variables. For the connection string seen above:

  • DBNAME = db982398
  • DBUSER = user3123
  • DBPASSWORD = passkja83kd8
  • DBHOST = ec2-117-21-174-214.compute-1.amazonaws.com

Of course, the newly created database is initially empty, so restore your data and schema! [See the README.md file in the /database scripts subfolder to restore the database for our “Minimal+DB” application].

4.4 Set other environment variables

If you have other Config Vars used by the Flask app, you must add them the same way the database vars were. For example, the “Minimal+DB” needs the SESSION_SECRET environment variable.

Do not miss any environment variable the app uses, or the app will not start.

5. Deployment with Azure App Service

If you don’t already have one, create a Microsoft Azure account. Azure will require you to set up a billing profile, called Azure Subscription, to be selected later when creating the app — and a Resource Group. You can learn more about these aspects here.

5.1 What file is Azure expecting in your Flask project

Make sure that the root folder of your Flask project contains a startup.sh file containing the instructions to start gunicorn on the Azure cloud server. In our demo code, the instruction is:

gunicorn --bind=0.0.0.0 --timeout 600 "minimaldb:create_app()"

Please, make sure you adapt the startup.sh to your app.

5.2 Create an Azure App Service

Once these aspects are settled, search and select “App Services” on your dashboard. Let’s click on “Create” — you will see a screen where one can:

  • enter the name of your app
  • choose the runtime stack (Python)
  • choose the operating system (Linux)
  • set the Azure Subscription and the Resource Group.

When done, proceed to the Deployment section. First, enable GitHub Actions, an automation framework that can build and deploy your app whenever a new commit is made in your repository.

Enter your details and continue to the following section (Networking), where you can select the “off” option. On Monitoring, enabling an application performance management or entering tags will not be required. Finally, select “Create” in the Review + Create section.

5.3 Database creation

To equip your Flask project with a Database (again, we will use PostgreSQL and pgAdmin), go to your dashboard and type “Azure Database for PostgreSQL servers” in the search bar. You will see a page like this. Click on “Create” to proceed.

Select the plan you prefer, and you will be on a configuration page; choose the setting you think best suits your project. When configuring it, you should assign the Database to the same Resource group as your App Service.

Please, note that server names, networking connectivity method and backup redundancy cannot be changed after the server is created.

Assigning the Database to the same Azure Region (the location where the server will be created) of the App Service is also preferable. Finally, click on “Review + create” to create the Database.

Now, you need to connect it to your app — and, of course, restore your data.

5.4 Database connection

Unlike Heroku, Azure does not independently add the environment variables needed to connect the Database to your application. The required values must be retrieved and manually assigned to the respective variables (in the Azure Application Settings.

Select “Configuration strings” in the side menu of your new server. You will find both a connection string for PostgreSQL (like the “DATABASE_URL” config var already seen before),

postgres://youradminusername{@yourservername.postgres.database.azure.com”>your_password}@yourservername.postgres.database.azure.com/postgres?sslmode=require

and one already “unpacked” for Python.

host=yourservername.postgres.database.azure.com port=5432 dbname={your_database} user=youradminusername password={your_password} sslmode=require

To connect the Database to the app, you only need to associate these values with the related environmental variables. Go back to your Azure App Service dashboard, select Settings > Configuration, and click “New application setting”.

Through this window,

you can set the individual required variables: DBNAME, DBHOST, DBUSER and DBPASSWORD. With the same elements, you can connect the Database to a tool such as pgAdmin.

Of course, the newly created database is initially empty, so restore your data and schema! [See the README.md file in the /database scripts subfolder to restore the database for our “Minimal+DB” application].

5.5 Other environment variables (“Application Settings”)

If you have other environment variables in your Flask app, you must add them as was done for the database variables. For example, as already mentioned, our “Minimal+DB” demo needs a SESSION_SECRET environment variable, which must also be added to the “Application Settings”.

Do not miss any environment variable the app uses, or the app will not start.

6. Deployment with AWS Elastic Beanstalk

Among the various ways to deploy an app with AWS, you may consider the “Elastic Beanstalk” service.

6.1 What file AWS Elastic Beanstalk is expecting in your Flask project

Ensure that your Flask project's root folder contains the application.py file: it allows Elastic Beanstalk to find your Flask application object easily. For our demo, the content of application.py is as follows:

from minimaldb import create_app
application = create_app()

Please, make sure to customize the application.py with the name of your Flask main folder and application object.

Unlike Heroku and Azure, AWS Elastic Beanstalk already provides for the use of gunicorn as a WSGI HTTP Server, so there is no need to include any related instructions in the application.py file.

6.2 Create a runtime environment in EB

You need an active AWS account to use the “Elastic Beanstalk” service. Once logged in to the AWS console, create a new runtime environment for the Flask application.

Click on the “Create a new environment” button: once on the next page (called Select environment tier), select Web server environment. In the first section of the page, you can enter a name for your app (and skip the tag section). Then, set a subdomain and a description for your environment.

Warning: The environment's name, subdomain and description cannot be changed later.

Select the “Managed platform” option and choose “Python” as your platform.

At this point, AWS asks us how to upload our code. Alas, the use of GitHub is not a readily available option. Therefore, an easy alternative is to create a zip file with all the code files (see below) and then directly upload the zip file.

6.3 What to exclude from your zip file

If your Flask project is similar to our “Minimal+DB” demo project, you should be careful about what to include in the deployable zip file.

First, you should delete the __pycache__ project’s subfolder, or at least not include it in the deployable zip file.

The zip archive should include all files and folders of your Flask’s project, EXCEPT the following:

  • .git hidden subfolder;
  • Procfile (EB creates Procfiles during its internal process, so it’s crucial not to include any interfering version of the file);
  • startup.sh or similar scripts;
  • the virtual environment folder, if you have one.

6.4 Database creation

In your EB environment, select “Configuration” in the sidebar menu; go to the end of the webpage. The Database entry is empty: press Edit to add a Database.

In the next screen, choose a Database type (PostgreSQL in our case) and set up its username and password. Then press “Apply”.

A brand new database will be created, and you will find it in the Amazon RDS section.

6.5 Database Connection Variables

One must pass the database connection variables via environment properties to connect the newly created database to the Flask application. The values of the connection variables that are to be assigned to the environmental properties can be found in the Amazon RDS section:
RDS > Databases > [MyDatabaseIdentifier].

Go to your EB environment Configuration > Software and add the necessary variables into the “Environment properties” section.

Our demo uses a PostgreSQL database instance, which needs specific environment properties:

  • DBNAME set from: RDS > Databases > [MyDatabaseIdentifier] > Configuration > DB Name;
  • DBUSER set from: RDS > Databases > [MyDatabaseIdentifier] > Instance > Availability > Master username;
  • DBPASSWORD: your password;
  • DBHOST set from: RDS > Databases > [MyDatabaseIdentifier] > Configuration > Endpoint).

For PostgreSQL, the port number is usually 5432; if the port is not set directly in your Flask code, you should also add the relative environment property for the port.

Remember to recreate the structure and data of the app’s database (e.g. with a backup/restore operation) in the newly created empty database. [See the README.md file in the /database scripts subfolder to restore the database for our “Minimal+DB” application].

You may want to access the AWS RDS database remotely using tools like pgAdmin; if you receive an error when connecting, try to solve the problem using the suggestions on this troubleshooting page.

6.6 Other environment variables (“Environment properties”)

If your code requires other environment variables, add them the same way the database variables were added. In our case, as seen, “Minimal+DB” needs to provide a value for a variable called SESSION_SECRET.

Do not miss any environment variable the app uses, or the app will not start.

7. Conclusions

We have gone through all the steps needed to deploy a Flask application with any of these platforms:

and we have seen how to create and connect the app’s database in the cloud.

We have effectively installed our Flask applications on each platform by following the same procedures described above. If anything is not clear enough, misleading or missing, don't hesitate to get in touch with us: we are eager to improve this living document.

--

--

Rinaldo Nani
Variance Digital

Algorithmist ▪ Software Engineer ▪ Project manager. I love maths and music + solving hard problems.