Running Python Flask on an Apache server

This week on the Linux server course our task is to set up Python Flask on an Apache server and run some basic stuff on it. I'll be setting this up on a server that I set up earlier and I will set it so that a subdomain of my main domain will direct there while it is still running.

Testing name based virtual host on local machine

The first task was to simulate a dns with the hosts file on Linux. I decided to make a site that would be available on juusotesti.com on localhost. I added a new host to /etc/hosts and created a new site configuration in Apache's sites-available folder. I added a new folder named public_sites in my home directory where I put a folder named juusotesti. Inside I put a basic index.html that has some plain-text.

hosts

127.0.0.1       localhost
127.0.1.1       TpadJ
127.0.0.1       juusotesti.com

juusotesti.com.conf

<VirtualHost *:80>
        ServerName juusotesti.com
        ServerAlias juusotesti.com
        DocumentRoot /home/juuso/public_sites/juusotesti
        <Directory /home/juuso/public_sites/juusotesti>
                Require all granted
        </Directory>
</VirtualHost>

commands

sudoedit /etc/hosts
sudoedit /etc/apache2/sites-available/juusotesti.com.conf
mkdir -p public_sites/juusotesti
echo "juusotesti.com toimii!" > public_sites/juusotesti/index.html
curl -H 'Host: juusotesti.com' localhost
        juusotesti.com toimii!

Setting up the subdomain

I already have an Apache server running on a DigitalOcean droplet and I have a domain name registered so I can just set it up with a few clicks. The site is now available on temp.juusokalliomaki.com.

a-record

dns-records

curl

Apache WSGI and Hello FLask!

First I will set up WSGI on Apache so that it can serve my upcoming Flask site. I'm following Tero Karvinen's post on Flask deployment to get this done. I'll start by setting up a user that will be used to manage the Flask app and installing all the required packages.

sudo adduser tempwsgi #Creating the user
sudo usermod --lock tempwsgi #Locking it because it will be not used on its own
sudo adduser $(whoami) tempwsgi #Adding myself to the group

sudo apt-get update
sudo apt-get -y install python3 python3-flask libapache2-mod-wsgi-py3

Then I'll set up a new config in Apache's sites available folder that so that the Python app can be served when it's ready.

sudoedit /etc/apache2/sites-available/tempwsgi.conf #Creating the conf file
sudo a2ensite tempwsgi #Enabling the site
sudo a2dissite 000-default #Disabling the default site
sudo systemctl restart apache2 #Restarting Apache

The config I used is the following

<VirtualHost *:80>
        ServerName temp.juusokalliomaki.com

        WSGIDaemonProcess tempwsgi user=tempwsgi group=tempwsgi threads=5
        WSGIScriptAlias / /home/tempwsgi/public_wsgi/temp.wsgi

        <Directory /home/tempwsgi/public_wsgi/>
                WSGIScriptReloading On
                WSGIProcessGroup tempwsgi
                WSGIApplicationGroup %{GLOBAL}
                Require all granted
        </Directory>
</VirtualHost>

Now that Apache's config is set up, the next step is to create the required file structure in tempwsgi user's directory.

sudo mkdir /home/tempwsgi/public_wsgi
sudo chown tempwsgi:tempwsgi /home/tempwsgi/public_wsgi/#change ownership of folder because it was created with sudo
sudo chmod g=rwxs /home/tempwsgi/public_wsgi/#change folder rights so that everyone in the group can acces all new file inside
nano /home/tempwsgi/public_wsgi/temp.wsgi #creating the conf
nano /home/tempwsgi/public_wsgi/hello.py #creating the hello Flask app

temp.wsgi

import sys
assert sys.version_info.major >= 3, "Python version too old in temp.wsgi!"

sys.path.insert(0, '/home/tempwsgi/public_wsgi/')
from hello import app as application

hello.py

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
        return "Hello Flask!"

Testing that the app is running

curl-hello

Then the task was to test that the site was modifiable without using sudo and without restarting the Apache server. I created a new python file that was almost the same as hello.py, I just changed the return string. Then I modified the last line of temp.wsgi to from modified import app as application.

mod-test

Adding templates to Flask

To use templates with Flask I created a folder for the templates and added a simple base html-template that I would try to use. I created a base.html file with the following code, added a new path to hello.py and changed temp.wsgi back to using hello.py. The {{ message }} is replaced with the value assigned in the templated function in hello.py. This was done based on this Tero Karvinen's post.

base.html

<!doctype html>
<html>
        <head>
                <title>Flask Template</title>
                <meta charset="utf-8">
        </head>
        <body>
                <h1>{{ message }}</h1>
        </body>
</html>

hello.py

from flask import Flask, render_template
app = Flask(__name__)

@app.route("/")
def hello():
        return "Hello Flask!"

@app.route("/template")
def templated():
        return render_template("base.html", message="Templates are working!")

flask-template

Using Flask request

Next I created a page that read information about the visitor with Flask's request import. I added a new path to the app in hello.py and touched the temp.wsgi file to get the new setup running. The page tells the visitor their ip and user agent. temp.juusokalliomaki.com/request

Addition to hello.py

@app.route("/request")
def requestParams():
        addr = request.remote_addr
        agent = request.user_agent.string
        return "Hello: " + addr + " -- " + agent

flask-template

Links: