Deploying a Flask App

This page describes how to deploy a Flask app on an Azure (or other Linux) virtual machine.

Note

Before completing this, create an Azure VM and set up SSL on it.

When you're all done, your Flask app will be managed and run by the Apache web server. Apache is a production-grade web server that handles HTTPS and many other things for your Flask app. The web server built in to Flask is sufficient for development and testing, but is not well-suited to production deployments on the public Internet.

Overview

The steps you will need to perform:

  1. Create a virtual environment
  2. Clone your application's source code from GitHub
  3. Configure settings and directory paths
  4. Configure Apache to load or connect to your application

Create a Virtual Environment

Create a virtual environment on your virtual machine. This will be easiest if you use sudo to launch a shell, rather than individual commands:

$ sudo -s
[sudo] password for michael:
# virtualenv -p /usr/bin/python3.4 /opt/flaskapp-venv
# source /opt/flaskapp-venv/bin/activate
Running virtualenv with interpreter /usr/bin/python3.4
Using base prefix '/usr'
New python executable in /opt/flaskapp-venv/bin/python3.4
Also creating executable in /opt/flaskapp-venv/bin/python
Installing setuptools, pip...done.
(flaskapp-venv)# pip install Flask Flask-Script Flask-SQLAlchemy bcrypt

Clone application source code from GitHub

$ sudo git clone https://git.txstate.edu/cs3320/animals.git /srv/animals

Set up configuration and data paths

Create a directory, data, that can hold your data and be written by the Apache process:

$ sudo mkdir /srv/animals/data
$ sudo chown www-data /srv/animals/data

Create a settings file, /srv/animals/settings.py, for your application:

SECRET_KEY = '<secret key here>'
# Path to SQLite database (note 4 slashes)
SQLALCHEMY_DATABASE_URI = 'sqlite:////srv/animals/data/animals.db'

Deploying with mod_proxy

With this method, we run the Flask application as a standalone server. Apache will forward HTTP requests and websocket connections to it.

Installing Dependencies

$ sudo -s
[sudo] password for michael:
# source /opt/flaskapp-venv/bin/activate
(flaskapp-venv)# pip install Flask-SocketIO eventlet

Starting the Server

First, we need to create a configuration file so that systemd can start and manage our server. Create the following file as /etc/systemd/system/myapp.service:

[Unit]
Description=the web application server
# we need a network
After=network.target

[Service]
# process starts, doesn't exit unless failing
Type=simple
# start manage.py with virtualenv
ExecStart=/opt/flaskapp-venv/bin/python3 /srv/myapp/manage.py socketserver
# start in its directory
WorkingDirectory=/srv/chat
# run as web user
User=www-data
Group=www-data

[Install]
# start with default stuff when we enable automatic startup
WantedBy=default.target

Then start the server:

# systemctl daemon-reload
# systemctl start myapp.service
# systemctl status myapp.service
● myapp.service - the myapp application server
   Loaded: loaded (/etc/systemd/system/myapp.service; disabled)
   Active: active (running) since Thu 2016-04-28 16:58:06 UTC; 4h 35min ago
 Main PID: 15826 (python3)
   CGroup: /system.slice/myapp.service
           └─15826 /opt/flaskapp-venv/bin/python3 /srv/myapp/manage.py socketserver

Make sure the service is running!

To make it start automatically when the VM boots, enable it:

# systemctl enable myapp.service

Configuring Apache

Next, we will configure Apache to pass incoming requests on to our application server. Put the following in /etc/apache2/sites-available/myapp.conf:

ProxyPass /socket.io/ ws://localhost:5000/socket.io/
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/

Then enable the site and required Apache modules, and reload Apache:

# a2ensite myapp
# a2enmod proxy_http proxy_wstunnel
# systemctl restart apache

Then visit your site and make sure it works!

Deploying with WSGI

Note

This method does not work with Socket.IO.

Apache and Flask communicate over a protocol called WSGI, the Web Server Gateway Interface.

More information on connecting Flask and Apache is available in the Flask mod_wsgi documentation.

WSGI

The first thing to do is create a small WSGI bootstrap script. This can live in your Git repository, and should be named something like myapp.wsgi. It should contain the following:

import sys, os.path
sys.path.insert(0, os.path.dirname(__file__))
from myapp import app as application

Change myapp to your application's main module (the one that pulls in the views & API files).

That's all you need for that file!

Configure Apache to load the application

Create a file /etc/apache2/sites-available/flaskapp.conf containing the following lines:

# Use our virtual environment
WSGIPythonHome /opt/flaskapp-venv

# Map the application to a URL
WSGIScriptAlias / /srv/animals/animals.wsgi

# Allow access to animals
<Directory /srv/animals>
  Options -Indexes
  Require all granted
</Directory>

You can edit the file with the command

sudo nano /etc/apache2/sites-available/flaskapp.conf

Then enable the site and restart Apache:

$ sudo a2ensite flaskapp
$ sudo systemctl restart apache2

The site should now be available, at e.g. https://txst-cs3320-demo.westus.cloudapp.azure.com.

Hint

If your resources, such as Pure, aren't being loaded when you visit the site over HTTPS, make sure that all your CDN resources use HTTPS instead of HTTP.

Also, Yahoo!'s CDN doesn't support HTTPS. Instead, use jsDelivr:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/pure/0.6.0/pure-min.css">

Hint

If you have problems (500, 400, etc.), look at the file /var/log/apache2/error.log.