How to run a Flask app behind Apache + 4th Pi Giveaway

Published on: May 11, 2019

Welcome to another Raspberry Pi Tutorial! In the last tutorial, I showed you How to run a Flask App on a Raspberry Pi In today's tutorial, we will take another step run a Flask app behind an Apache web server. Why? In the next tutorial, we'll use a simple web app to make an AJAX request to turn on and off an LED from a browser. A flask app runs on port 5000 and if we serve the web page through Flask, then it's fine, but no one wants to go to a website with a Port number. So because of that, we will run the Flask app behind Apache so that we can simpley hit our Pi's IP address and control our LED. There are ways to enable Flask to accept CORS requests and resources for that are easy to find. If there's enough interest, I can create a separate tutorial covering that. 

I showed you how to turn on an LED using two different libraries in a previous tutorial. At the end of this mini-series, we'll turn our LED on and off with our browser. 

Some of the steps in this tutorial are repeats because I quickly go over how to set up your virtual environment and run a Flask app again. So feel free to skim through these. 

To get started, let's install our venv where our Apache is installed by doing these commands:

cd /var/www

This will take us to our Apache's www folder. Then let's create a simple folder to house our Flask app, feel free to call it anything you want but I called it piapp:

sudo mkdir piapp
cd piapp

If you don't already have venv installed, install it now:

sudo apt install python3-venv

This creates a blank folder called piApp. You can call this anything you want. Now we'll install venv:

sudo python3 -m venv venv

You can name the virtual environment folder anything you want, I called it venv. We need to then activate our virtual environment with this command:

. venv/bin/activate

Your terminal should now be prefixed with (venv), which means that any action you take here, will only happen in your virtual environment. There's one quirk that I ran into while installing flask. You may also run into a weird permission error when trying to install flask. When your venv is created, the environment is owned by root. So if you run into this issue, deactivate your virtual environment then run this command to change the owner of the environment before proceeding:

sudo chown -R pi:pi venv

Then reactivate your venv and continue. Now let's install Flask:

pip install flask

If everything goes well, you'll get a success message at the end. Now let's create a simple Python script that will serve as our root Flask app. I called it piapp.py but you can call it anything you want. 

sudo nano piapp.py

In the file, add this:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

The code is taken directly from the Flask documentation found here: http://flask.pocoo.org/docs/1.0/quickstart/

If you want to test your app before proceeding with Apache, run it with:

flask run --host=0.0.0.0

We need one additional dependency before we can move forward with Apache. In the past the venv package came with a file called activate_this.py which allowed external processes to activate and run scripts from a particiular virtual environment.  I'm not sure when this was removed but we need to put the file in the venv/bin/ directory:

cd venv/bin/
wget https://raw.githubusercontent.com/pypa/virtualenv/master/virtualenv_embedded/activate_this.py

This will grab a working version of the activate_this.py script. 

Why do we need this? 

Because Flask is not installed globally and is only accessible through our virtual environment, Apache (as a global user and install) will not be able to access our virtual environment. Let's make some changes to our Apache configs (you may want to deactivate your virtual environment now but I have not noticed any issues either way):

cd /etc/apache2/sites-available
sudo nano piapp.conf

We go into the sites-avaialble directory which contains our Apache configurations. We can edit the default confg but I've decided to create a brand new one called piapp.conf. Edit the file and input these values:

	
<VirtualHost *:80>
        ServerName nazberrypi
	WSGIDaemonProcess piapp user=pi group=www-data threads=5
	WSGIScriptAlias /piapp /var/www/piapp/piapp.wsgi
	<Directory /var/www/piapp>
		WSGIProcessGroup piapp
		WSGIApplicationGroup &{GLOBAL}
		Require all granted
	</Directory>
</VirtualHost>

If you installed your Flask app in a diffrent directory, make sure you make those edits above before saving. As the WSGIScriptAlias suggests, we need a piapp.wsgi file. But before we create it, let's make sure that our Pi can run this configuration by installing a libapache module:

sudo apt install libapache2-mod-wsgi-py3 -y

I've learned that Apache or Pi doesn't come with this enabled by default. Once this is installed, we can enable our configuration and disable the default one with these commands:

sudo a2ensite piapp.conf
sudo a2dissite 000-default.conf
sudo service apache2 restart

If everything went well, you'll be able to enable your new config, disable the old default one, and restart Apache without any errors. After making those changes, let's go back and create that .wsgi file:

cd /var/www/piapp
sudo nano piapp.wsgi

Then in the file, input this:

#!/usr/bin/env python3

activate_this = '/var/www/piapp/venv/bin/activate_this.py'
with open(activate_this) as file_:
	exec(file_.read(), dict(__file__=activate_this))
	
import sys
sys.path.insert(0, '/var/www/piapp')

from piapp import app as application

This file will be accessed by Apache (user www-data), it will use the activate_this.py script and import then run the Flask app on port 80. Since it's port 80, we don't need to specify it in our browser when we visit the page. Again, if you placed your files in a different locations, make the necessary edits above. 

If all went well, you can restart Apache and see if you are able to access your Flask App:

sudo service apache2 restart

Now you can try to visit your Flask app without the App and see the magic work: http://{{ip_addr}}/piapp

In the next tutorial, I will show you how to turn on an LED using your browser! We are finally getting there. 

That's all! 

Giveaway

Now if you're here about the giveaway, keep reading:

This is my fourth Raspberry Pi giveaway. Here are the official rules:

Here are a list of official rules:

  1. Only open to US residents (sorry, I will try to open it up internationally in the future)
  2. Comment anywhere in this video or on the video posted on EasyProgramming.net - comment can be anything but I would really appreicate if you'd share a project idea that you have or have already worked on
  3. Optional: Mention what state you are from.
  4. I will stop taking entries on May 30, 2019 11:59:59 PM EST and winners will be announced in the June 1, 2019 tutorial
  5. That's all! 

Past winners are welcome to try again! Comments on YouTube and EasyProgramming will earn you one entry each. Patrons on Patreon will get 5 entries per tier! Meaning you can get up to 15 entries on Patreon alone. Look to becoming a patron: https://www.patreon.com/nazmus.

Bonus entry can be made on the EP subreddit, so be on the lookout for that thread: https://www.reddit.com/r/EasyProgramming/

I apologize again for opening up to US residents only. Since I'm covering the costs myself, I need to be able to minimize costs so that give away more of these. International shipping is just so expensive! I do hope to open it to international folks at some point. 

Enjoy the tutorial and good luck in the drawing! 

Remember to checkout the Resources section below for associated downloadable content, JSFiddle links, and other resources. Watch the video and follow along!

Resources:

No resources from Easy Programming for this video! Follow me on Github for other resources https://github.com/naztronaut

But be sure to check out the Flask documentation here for a better understanding of how to use Flask: http://flask.pocoo.org/docs/1.0/quickstart/



Comments: