Deploying Python Web Apps to the Cloud

Pushing your app to a cloud provider as a ‘production’ environment is a good way to show your work to other people, and for you to ensure that others can install it as you envisage. Whether you’re deploying a Flask or Django application some steps are the same.

First, select a provider. There are a range of them as shown here.

https://www.pythonanywhere.com – mysql or postgresql databases – run automated daily tasks https://help.pythonanywhere.com/pages/DeployExistingDjangoProject/

https://www.netlify.com

https://vercel.com

https://expo.dev range of dev/build options for React front-end apps

https://www.back4app.com

https://firebase.google.com -limited NoSQL database

https://render.com  – includes PostgreSQL free for 90 days

https://glitch.com – for Node.js and React based applications with SQLite

https://www.deta.sh deploy python,Node.js apps, plus a NoSQL type database

https://replit.com for editing and deploying applications across a range of languages – your work is PUBLIC on the free tier, so not good for coursework.

Second,  once you’ve picked one, try to deploy something simple as a test before you try to deploy any coursework. You might also find that you can only deploy one app under the free tier.

Deploying to PythonAnywhere

This is a short guide to point you in the right direction for deploying here.

First, create an account at https://www.pythonanywhere.com/ and look at the tour of things.

Second, set up an ssh key in a Console, and register it with your GitHub account.

Third, create a requirements.txt file for your application with the command:

pip freeze > requirements.txt
Edit the file to add any obvious libraries that might be missing such as Django, or Faker. If you have lines pointing to relative paths on your device, then run this command to remove them:
pip list --format=freeze > requirements.txt
Third, add the requirements.txt file to your Git repository and then make a new commit and push it to GitHub.
Fourth, you can now open a console  at python anywhere and clone your app into the filespace and follow the ‘deploy an existing Django app guide‘. You can also read my notes on this process, which also provide some details about continuous deployment to PythonAnywhere.
Fifth, as you work through this follow this rule: Edit the version on your device, then commit and push to GitHub, and then pull to PythonAnywhere. By doing this you’ll always have the correct version in your code.

 

Deploying to Heroku

NOTE: Heroku is no longer a free option by default, but might be useful for some of you.

You can find more details on Heroku for flask and Django deployments.

Heroku is an easy to use deployment environment that runs on top of Amazon Web Services.

You should deploy your app as soon as possible, even if it’s only ‘hello world’ at the start. By doing this early, there are fewer moving parts for you to worry about, and you can resolve any issues now. As a rule it always takes you longer than expected to deploy the first time for an app.

We’ll go through a simple application with an SQLite database as this is the easier version. Later, we’ll discuss how to deploy to a different database. SQLite is file based, so slow, and has other limitations, so is not ideal for production, but is fine for prototyping ideas as you start your application. You can move to Postgresql later.

Deploy to Heroku with Git

You need to have your application in a git repository in order to deploy it to Heroku. If you haven’t already done, this, then make your application a git repository.

Install Heroku to Your System

The easiest way to install Heroku (after you’ve created an account there) is with via a terminal with this command:

      curl https://cli-assets.heroku.com/install.sh | sh

This will download the CLI (command line interface)  as a standalone installation for you to use.

With this in place, now you should also add your public ssh key to Heroku, so that you don’t have to enter your username and password every time you want to push your code there.

Now you can use the command ‘heroku login -i’ to first login to Heroku from the command line (this will pop open a browser window for you to login, which you can then close again).

Now use ‘Heroku create’ from the command line inside your application to add Heroku for deployment. This will generate an ‘app’ on the Heroku platform, and then add it as a remote repository to your regular git config settings for this application.

Prepare Your App for Deployment

With Heroku added you now need to provide some details about your application before you can deploy it.

General Steps for Deployment

While you don’t need to run it locally, adding Gunicorn to your application now means that you ‘could’ run it locally, and you automatically have the correct version for running on Heroku too. You can’t use the server for either Flask or Django in production as these are too slow, and are less stable as well. Heroku has more options available, so these are the basics. So use Pip to install Gunicorn with the command:

    pip install gunicorn

Now we can add the other files that Heroku will also need to run your application.

Create a file called ‘runtime.txt and put your version of python in it, for example ‘python-3.7.0’ without the quotes. You should check that it matches the python versions used by Heroku.

We need a file that lists the libraries used in the application. We can generate that with this command:

    python3 -m pip freeze > requirements.txt

This will use pip to generate a list of libraries and write them to the ‘requirements.txt’ file, which is needed by Heroku to install these libraries for our application.

Create a file by the name ‘Procfile’ with no extension and put a line like this in it.

For Flask use this:

    web: gunicorn <app name>:app

Substitute <app name> for the name of your application. For example, if the webserver was in story.py then it would be web:unicorn story:app

For Django use this:

    web: gunicorn mysite.wsgi --log-file -

In this case, ‘mysite’ is the name of the application, so you may need to change this.

We can now add these new files to our Git repo, and then commit the changes to the repository. Use this command to do that:

    git push heroku main (or master)

You will need to use either main or master depending upon the settings of your repository. After you run this you’ll see a long list of code passing before you as the app is uploaded, unpacked, and then prepared for launching.

Django Specific Steps

Django needs to have you add some settings to the application before you move it to production.

Add the whitenoise library to handle static files such as CSS and images for your application. Install this with

    pip install whitenoise

Then open the settings.py file and add this line after the SecurityMiddleware one:

    'whitenoise.middleware.WhiteNoiseMiddleware',

In setttings.py also add the URL of your application on Heroku, the one with app-name.herokuapp.com to the ALLOWED_HOST list. Don’t include the trailing ‘/’ in the URL.

If you’re using Postgresql, then you’ll need to look further below for database details.

Expected Errors and How to Debug Them

You need to pull down the log files for your application in order to see what has gone wrong, as the applications will not be run in ‘debug’ mode as this is insecure. You can retrieve the logs with the command:

    heroku logs

With this running (or using the tail command too, ‘heroku logs -tail’ so that you see a stream of log files) you can try different things to see what is causing the problem. If your app is not deploying correctly, then read the text to see what might be causing the problem.

If you see an error, and fix the code, then you MUST create a new commit in your repo, which you can push to Heroku. If you run ‘push’ without creating a new repo, then you are pushing the old code.

Databases on Heroku

If you’re using SQLite, then all of the above will get your application up and started if you’re using Flask. If you’re using Django, then you need to follow a few more steps. If your database is SQLite, then it might have been uploaded to Heroku with the tables and data included. If not, then you need to run the migrations to create the tables, then you can do whatever is needed to add the data to the tables.

If you need to deploy your app to Postgresql, then you need to include this as an ‘Add-on’ in your Heroku settings so that it provisions a database for you. You can check database content and details by installing PgAdmin to manage your local instance, as well as your remote one. You will need to find the connection details to your Heroku Postgresql instance. Remember too, that if you’re using Postgresql, that your column name can’t start with a capital letter. If you do that, then they are seen as constants, and the columns are not found in queries.

Flask with Postgresql

This option will need to have you doing most of the work yourself in order to provision the database, and keep it up to date after you’ve created an instance on Heroku for you to use. You can do this with PgAdmin as noted already. PgAdmin will allow you to dump your schema and data locally, and then connect to the remote version and upload the schema and data to the remote system.

Django with Postgresql

As Django allows you to use manage.py to handle migrations and other commands, you can do much of the work via the command line. For example, instead, of ‘python3 manage.py migrate’, you can now use ‘heroku run python manage.py migrate’. This convention of adding ‘heroku run’ to the usual manage.py commands, makes life easier.

We need to add two other libraries for the database, dj-database-url for distinguishing local from remote databases, and the psycopg2-binary as the library for connecting to Postgresql. You can install both via pip with these commands:

    pip install dj-database-url

    pip install psycopg2-binary

The dj-database-url needs some configuration in the settings.py file as well. Add this to the file, along with an import statement at the top of the file.

# Heroku: Update database configuration from $DATABASE_URL.
import dj_database_url
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)

We use the binary version of psycopg2 as this is easier to install locally than the other version, which requires more libraries and other components, which make use of Postgresql. This also means that you don’t have to have Postgresql installed locally.

Add any of these libraries that you use to your requirements.txt file manually, or by re-running freeze.