Local Hosting pt II: Flask and Apache

In part one, we went over how to host a website on your a raspberry pi in your home. Next, we need to take it to the next level. Currently our self hosted website is just static assets--like css, html, and javascript.

If we want our apache server to handle data, we need to have a backend. Enter flask and way too much time setting up config stuff.

Before we get started, we are assuming you have a linux machine set up and apache2 installed. Our linux machine will be our raspberry pi.

Step One: Install and Enable mod_wsgi

WSGI (Web Server Gateway Interface) is an interface between web servers and web apps for python. Python is single threaded, meaning that it can only do one thing at a time. As you can imagine, if one user had to wait for another in order to do something on your website, then it wouldn't be a very popular site. WSGI fixes that problem.

Plus more importantly, its the needed add on to get your flask app working on an apache server, so we have to do it, even if we were cool with having a single threaded web app.

To install mod_wsgi, in the terminal type:

sudo apt-get install libapache2-mod-wsgi python-dev
    

Next, you need to enable mod_wsgi

sudo a2enmod wsgi 
    

Step Two: Creating (or Moving) your Flask App

Next we need to have an app to actually serve on the server, and your static website won't work here.

It is convention to store your app in the /var/www directory. If for whatever reason you don't have permission to write in that folder use the following command:

chmod -R "USERNAME" /var/www
    

So lets move into this folder:

cd /var/www
    

If you have an app, move it into this folder now (preferably using git). Once its in there you can skip ahead to Step Three. If not, lets create an app.

Ok back to creating the app--

Lets create a project folder and move into it:

sudo mkdir proj
    cd proj
    

Create another folder called flaskapp and move into it:

sudo mkdir flaskapp
    cd flaskapp
    

Next we are going to create some folders inside here:

sudo mkdir static templates
    

Your directory structure should look like the following:

|----proj
    |---------flaskapp
    |--------------static
    |--------------templates
    

You should currently be in the flaskapp directory. You can always check this with pwd. Next we are going to add the barebones logic for our flask app.

sudo nano __init__.py
    

And within that file we just created, copy paste the following:

from flask import Flask
    app = Flask(__name__)
    @app.route("/")
    def hello():
        return "My first flask app"
    if __name__ == "__main__":
        app.run()
    

Save and close!

Step Three: Install Flask and Create a Virtual Environment

NOTE: if you used git to bring your app over into /var/www then you can skip this step. Just check and make sure that venv has all the packages you need. We will cover this in Step Four.

In general, you should set up a virtual environment to keep your application isolated from the rest of your server.

Make sure you are using python3. To test enter the following:

python3
    

If you see >>> _ that means that you have python3 installed and working. Type in exit() to leave.

Python 3 is needed as it supports virtual environments out of the box. So we can use the following to create a virtual environment:

sudo virtualenv venv
    

Next we need to activate the venv.

source venv/bin/activate
    

Once it is done your console will change from $ to (venv) $ _.

Python 3 comes with pip, which is python's package manager. We will use that to install flask.

sudo pip install flask
    

Step Four: Checking our Progress

Let's stop and breathe for a second. Too dramatic? Probably. But let's stop anyways and make sure that we have what we need.

First let's look at directory structure:

|----proj
    |---------flaskapp
    |--------------static
    |--------------templates
    |--------------venv
    

If yours looks like that, we are looking good thus far. Next let's make sure flask is in our virtual environment. Let's cd into our virtual environment and make sure its there.

cd /var/www/proj/flaskapp/venv/lib/python3.7/site-packages
    ls
    

You should see a bunch of packages here including flask. If you can't get to that directory it might be because python 2 not 3.7 is installed in venv. Got to venv/lib to check.

Next lets get back to where we should be:

cd /var/www/proj/flaskapp/
    

And see if we can run __init__.py.

sudo python __init__.py
    

It should display “Running on http://localhost:5000/” or "Running on http://127.0.0.1:5000/".

If not, check your folder structure and make sure they you have all the packages and stuff.

Ok, lets get out of the virtual environment:

deactivate
    

Step Five: Create the .wsgi File

This file will actually serve the flask app.

We are going to store this in the proj folder:

cd /var/www/proj
    sudo nano config.wsgi
    

Add the following:

import sys
    import logging
    import site

    # this tells wsgi where the libraries are
    site.addsitedir('/var/www/proj/flaskapp/venv/lib/python3.7/site-packages')
    logging.basicConfig(stream=sys.stderr)

    # name of the top level folder for the project
    sys.path.insert(0,"/var/www/proj/")

    # flaskapp will be the inner folder from your project folder
    from flaskapp import app as application
    application.secret_key = 'key'
    

So there are three comments here and three things you may want to change. Let's walk through all three.

Where your libraries are

# this tells wsgi where the libraries are
    site.addsitedir('/var/www/proj/flaskapp/venv/lib/python3.7/site-packages')
    logging.basicConfig(stream=sys.stderr)
    

This part tells WSGI where your virtual environment is. It should point to your venv folder in your project.

Where your project is

# name of the top level folder for the project
    sys.path.insert(0,"/var/www/proj/")
    

This tells python where the root directory is for the project. It should be the top level folder for your project.

Where your app is

# flaskapp will be the inner folder from your project folder
    from flaskapp import app as application
    application.secret_key = 'key'
    

On line 2 where it says from flaskapp, replace flaskapp with whatever the name of your app is (its the folder within your proj folder).

Step Six: Configure and Enable Your Virtual Host

This is going to tell apache which app to run.

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

Add the following to the file:

<VirtualHost *:80>
            ServerName <<YOUR IP ADDRESS>>
            WSGIScriptAlias / /var/www/proj/config.wsgi
            <Directory /var/www/proj/flaskapp/>
                Order allow,deny
                Allow from all
            </Directory>
            Alias /static /var/www/proj/flaskapp/static
            <Directory /var/www/proj/flaskapp/static/>
                Order allow,deny
                Allow from all
            </Directory>
            ErrorLog ${APACHE_LOG_DIR}/error.log
            LogLevel warn
            CustomLog ${APACHE_LOG_DIR}/access.log combined
    </VirtualHost>
    

Save and close your file.

Next enable the virtual host with the following command:

sudo a2ensite FlaskApp
    

Step Seven: Restart Apache and Bask in Success

Finally, just restart apache to apply the changes.

sudo service apache2 restart 
    

You shouldn't get any error messages at this point! To check and make sure this worked go to a different laptop and enter your IP address into your web browser, and you should see your flask app!

Just in Case:

Let's say that not everything is perfect, and you are getting a server 500 error at this point. Let's go over how to check the error logs.

To check the error logs:

nano /var/log/apache2/error.log 
    

If there is a bunch of information in there, you may want to clear out the logs first.

sudo bash -c 'echo > /var/log/apache2/error.log'
    

Then refresh the page and view the logs again.

nano /var/log/apache2/error.log