Skip to main content

Ubuntu 18.04.1, ISPConfig3, Python 3, Flask, Apache 2, and mod_wsgi

Today I spent a lot of time trying to figure out how to get a Flask application started using Python 3 on Ubuntu 18.04.1. I had previously built an application using Python 2.7, Flask, and mod_wsgi, but it had been a while and the documentation I came across just wasn't connecting the dots properly. Here's my notes after the endeavor.

For the example, the root directory of the ISPConfig3 user is going to be /var/www/clients/client1/web1/.

# install 
sudo apt install libapache2-mod-wsgi-py3 python3-pip
# disable mod_python if it's installed, or just uninstall it as mod_wsgi can't be loaded at the same time

# install python3 virtualenv globally
sudo pip3 install virtualenv

# change to the private folder where we'll create the project
cd /var/www/clients/client1/web1/private/
# create the project folder and change into it
mkdir project1 && cd project1
# create the virtual environment in the env directory, which will be created for us
virtualenv env
# activate the virtual environment
source env/bin/activate
# install flask
pip install flask
# setup some other directories and empty files
mkdir app log
touch wsgi.py run.py config.py app/__init__.py

wsgi.py

import sys
sys.path.insert(0, "/var/www/clients/client1/web1/private/project1")

from app import app as application

run.py

# WSGI Server for Development
# Use this during development vs. apache. Can view via [url]:8001
# Run using virtualenv. 'env/bin/python run.py'
from app import app

app.run(host='0.0.0.0', port=8001, debug=True)

app/__init__.py

from flask import Flask
app = Flask(__name__)

# Configurations
#app.config.from_object('config')

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

Apache virtual host configuration

<VirtualHost *:80>

ServerName test.domain.com
ServerAdmin webmaster@test.domain.com

ErrorLog /var/log/ispconfig/httpd/test.domain.com/error.log

WSGIDaemonProcess client1web1 python-home=/var/www/clients/client1/web1/private/project1/env python-path=/var/www/clients/client1/web1/private/project1
WSGIProcessGroup client1web1
WSGIScriptAlias / /var/www/clients/client1/web1/private/project1/wsgi.py
WSGIPassAuthorization On

<Directory /var/www/clients/client1/web1/private/project1>
    WSGIProcessGroup client1web1
    WSGIApplicationGroup %{GLOBAL}
	WSGIScriptReloading On
    Require all granted
</Directory>

</VirtualHost>

<VirtualHost *:443>

ServerName test.domain.com
ServerAdmin webmaster@test.domain.com

ErrorLog /var/log/ispconfig/httpd/test.domain.com/error.log

<IfModule mod_ssl.c>
	SSLEngine on
	SSLCertificateFile /var/www/clients/client1/web1/ssl/test.domain.com-le.crt
	SSLCertificateKeyFile /var/www/clients/client1/web1/ssl/test.domain.com-le.key
	SSLCertificateChainFile /var/www/clients/client1/web1/ssl/test.domain.com-le.bundle
</IfModule>

# The WSGIDaemonProcess directive can only defined once, and you don't want two daemons for the same application.
# This is currently what is preventing my from being able to configure this type of application from the ISPConfig3 web interface.
# WSGIDaemonProcess client1web1 python-home=/var/www/clients/client1/web1/private/project1/env python-path=/var/www/clients/client1/web1/private/project1

WSGIProcessGroup client1web1
WSGIScriptAlias / /var/www/clients/client1/web1/private/project1/wsgi.py
WSGIPassAuthorization On

<Directory /var/www/clients/client1/web1/private/project1>
    WSGIProcessGroup client1web1
    WSGIApplicationGroup %{GLOBAL}
	WSGIScriptReloading On
    Require all granted
</Directory>

</VirtualHost>

Still to do:

  • Figure out how to configure this properly using just the ISPConfig3 control panel. I can make it work editing the config files by hand, but they eventually get overwritten by ISPConfig3. The big problem I have right now is the WSGIDaemonProcess directive can only exist once... not in both the http and https VirtualHost definitions.

Source material:

  • coxley/flask-file-structure (Source)
  • proper structure of the wsgi.py file (Source)
  • Flask 1.0.2 Quickstart (Source)
  • Flask Deployment Options - mod_wsgi / Apache (Source)