Tip on running Flask applications on Apache/2.4.46 (FreeBSD) using CGI
After receiving several Internal Server Error
from Apache and making changes to httpd-custom.conf
when trying to run a Flask app using CGI, I realized that setting environment variables in your .profile
does not guarantee your .cgi
or .py
scripts in the cgi-bin
directory will have access to them. Knowing the behavior of crontab
and Python scripts, I should have figured this out earlier. For example, if script.py
looks something like
import sys
sys.path.append('Your virtual env/site packages')
import os
import mysql.connector
from sqlalchemy import create_engine
import pandas as pd
from flask import Flask, render_template
from wsgiref.handlers import CGIHandler
app = Flask(__name__)
sqlpass = os.getenv('SQLCRD')
sqlusr = os.getenv('SQLUSR')
sqlsrv = os.getenv('SQLSRV')
sqldb = os.getenv('SQLDB')
engine = create_engine('mysql+mysqlconnector://' +
sqlusr + ':' + sqlpass + '@' + sqlsrv + '/' + sqldb, echo=False)
df = pd.read_sql('SOME SQL QUERY', engine)
@app.route("/hello")
def home():
return df.to_json()
and you call it from cgi_script.cgi
, where the cgi
script follows Flask’s documentation
#!/pathtoyourpythonvirtualenv/python
from wsgiref.handlers import CGIHandler
from yourapplication import app
CGIHandler().run(app)
in the cgi-bin
directory. Then, when you call it from
www.yoursitename.com/cgi-bin/cgi_script.cgi/hello
in your browser, it will not work. The reason is that scripts in cgi-bin
run in a mostly empty environment, so SQLUSR
and SQLCRD
are not available, even though they have been defined in .profile
. There are several ways to resolve this, I used the following approach. Add from wsgiref.handlers import CGIHandler
to the top of script.py
and
if __name__ == '__main__':
CGIHandler().run(app)
to the bottom of script.py
. Then call script.py
from a ‘wrapper’ CGI script (cgi_script.sh
) as shown below
#!/usr/local/bin/bash
export SQLUSR=valueofvariable
export SQLCRD=valueofvariable
source ~/yourproject/env/bin/activate
cd ~/whereyoukeepthepythonscript
python script.py
by pointing your browser to
www.yoursitename.com/cgi-bin/cgi_script.cgi/hello
Alternatively, source your .profile
inside of cgi_script.sh
. Sourcing your .profile
seems more secure but I’m not sure if it actually is.