I. Introduction
Flask
is a powerful web framework for Python.
And
Python in turn is a
wonderful language, written by an equally wonderful (and dry-witted) man,
Guido van Rossum.
(I had
dinner
with him several times on-board
Linux Lunacy III.
Yes, I'm a name-dropper; I also taught Linus Torvalds' kids how to play rock-paper-scissors.
But I digress...)
But... Flask, IMHO like many Python tools, suffers from oft-times vague and inconsistent
documentation.
In my case, I wanted to install Flask on a RHEL-style (e.g. CentOS, AlmaLinux, etc.) production
Linux server, using Apache.
It took several hours of googling and experimentation and assembling different (and sometimes
contradictory) clues from different pages, in order to create a coherent set of installation
instructions.
Which, gentle reader, I offer to you, below.
II. Assumptions and Terminology
- These instructions were developed and tested on AlmaLinux 8.5.
They should apply to CentOS or any RHEL-based Linux distribution.
Other distributions have other tools or locations
(e.g. get-apt instead of yum, different installation locations for Apache httpd, etc.),
but the overall pattern will be the same.
- Requires 'root' access.
- Python 3.8 was used throughout.
- Apache 2.4.37 with wsgi.
- The test Flask app lives in a newly-created Linux user, in this case 'flask', in /home/flask.
- Similarly, the test Flask app has its own virtual host, with the domain name flask.myserver.com.
- The WSGI 'daemon' group(s) are flask1 (for http) and flask1s (for https).
Each distinct Flask app must have unique daemon group name(s).
- The WSGI interface script is called flaskapp.wsgi.
The names of the app, WSGI interface, and daemon groups can vary, they just
need to be consistent across the scripts and virtual host definitions.
III. Supporting Software Installation
- Python 3.8. Flask needs Python 3.8 or higher. As root:
yum install python38.x86_64
This installs the python command at /usr/bin/python3.8.
- mod wsgi 3.8. While Linux can handle multiple versions of Python, Apache/WSGI can only support
one version of WSGI at a time.
In order to support Flask, I needed the python 3.8 version, so I removed the default WSGI module,
and added the Flask-compatible version:
yum remove python3-mod_wsgi.x86_64
yum install python38-mod_wsgi.x86_64
III. Set up test Flask app
- App dir. Logged in as user 'flask', create test app directory:
mkdir Test
- venv. Install the virtual environment:
cd Test
python3.8 -m venv .venv
- Install Flask.
. .venv/bin/activate
pip install Flask
- App. Create the test app (in Test/index.py):
#!/usr/bin/python3.8
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, Flask!"
Note the "shebang" in the first line, that specifies python 3.8.
- WSGI. Create the WSGI interface, in Test/flaskapp.wsgi:
#!/usr/bin/python3.8
import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, "/home/flask/Test/")
sys.path.insert(0, "/home/flask/Test/.venv/lib/python3.8/site-packages")
from index import app as application
- Permissions. The Flask and python scripts must be accessible
by the Apache httpd user.
cd
chmod 711 . Test
chmod 755 Test/*
IV. Connect to Apache
This assumes that you are already familiar with setting up virtual hosts.
Note the "SetEnv" line: this allows WSGI to automatically reload any Flask/Python
files that have changed, on the fly.
For a speedier 'production' server, simply remove that line.
- Virtual Host. Create the virtual host file, in (e.g.) /etc/httpd/conf/vhosts/flask.myserver.com:
<VirtualHost *:80>
ServerName flask.myserver.com
ServerAdmin you@youremailserver.com
WSGIDaemonProcess flask1
WSGIScriptAlias / /home/flask/Test/flaskapp.wsgi/
DocumentRoot /home/flask/Test
SetEnv FLASK_ENV development
<Directory /home/flask/Test>
Order allow,deny
Allow from all
AllowOverride All
Require all granted
</Directory>
ErrorLog /var/log/httpd/flask-error.log
CustomLog /var/log/httpd/flask-access.log combined
RewriteEngine on
RewriteCond %{SERVER_NAME} =flask.myserver.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
- https.
Configuring https can be tricky.
I find it easiest to use the
Apache Certbot
to both create the https virtualhost file,
and automatically create the SSL certificate.
Warning: Apache httpd may complain about the (seemingly) duplicate WSGIDaemonProcess name.
I found it easiest to:
- Delete the WSGIDaemonProcess line.
- Run certbot to create & install the https virtualhost for flask.myserver.com.
- Add the line back in to both flask.myserver.com virtualhost files.
- In the https virtualhost file, change the group name, e.g. WSGIDaemonProcess flask1s (note the 1s).
- Restart. And, of course, restart http:
service httpd restart
V. Testing
You should now be able to point a browser at https://flask.myserver.com, and see "Hello, Flask!".
If you run into problems, see /var/log/httpd/flask-error.log (and flask-access.log).
When it comes time to optimize for production usage, see the
documentation for WSGIDaemonProcess.
It provides many options for controlling the number of available threads, and other features.
VI. Relevant links
These are links that I found in my searching; most of them have
some useful clues,
but as noted in the introduction, they vary wildly.
- Flask Quickstart
- RedHat: doc on Python & WSGI 3
- Stackoverflow: get WSGI to pick up virtual env
- General/vague article about virtualhosts
- Google: More WSGI configuration
- Windows Apache/Flask
- Plain English: Apache/Flask
- Hello World with Flask/Apache