WSGI and CGI Apps in a DreamHost Shared Hosting Account
I experimented with running WSGI and CGI apps in my DreamHost shared hosting account.
Introduction
As I have mentioned before, for my conradhalling.com website, which is hosted by DreamHost, I am working on a Python-based web application. DreamHost supports CGI applications but no longer supports WSGI applications.
I’m comfortable with writing a CGI application, but it’s still possible to create a WSGI application using Flask and run it as a CGI application.
In the Python world, it is getting more difficult to write CGI applications simply because the modules and documentation are disappearing. The Python cgi
and cgitb
modules were deprecated in Python 3.11 and removed from Python 3.13. The instructions for deploying a Flask application using CGI were removed from the Flask documentation in July 2022 with version 2.1.3. These changes are unfortunate because there is still a use case for CGI in a shared hosting account where WSGI is not available.
Fortunately for Python 3.13 users, the cgi
and cgitb
modules were moved to the legacy-cgi
package, which is available from the Python Packaging Index (PyPI). Since I’m working on a server that has Python 3.10 installed, the cgi
and cgitb
modules are readily available.
An Example CGI Script
On the DreamHost server, CGI scripts needed to have a file extension of .py
or .cgi
and needed to be executable. I made the scripts executable by providing a #!
line containing the path to Python and setting the file’s mode to 755
, as in this example, where the script was named helloworld.py
.
1
$ chmod 755 helloworld.py
On conradhalling.com, I installed a simple “hello world” CGI script and tested it successfully at https://conradhalling.com/projects/helloworld.py. The script was:
1
2
3
#!/usr/bin/env python
print("Content-type: text/html\n");
print("Hello, World, from Python CGI!");
Running WSGI Scripts as CGI
The documentation for Python’s wsgiref
module didn’t provide a working example, but it was possible to use wsgiref.handlers.CGIHandler
to run a WSGI app as a CGI app.
A Basic WSGI App
As a working example, I was fortunate to find a basic WSGI script by Keith Gaughan at Running a Python WSGI application as a CGI script. I tested the script successfully at https://conradhalling.com/projects/helloworld_wsgi.py. The script, which conformed exactly to the WSGI specifications described in PEP 3333, was:
1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python3
from wsgiref.handlers import CGIHandler
def simple_app(environ, start_response):
status = "200 OK"
headers = [("Content-Type", "text/plain")]
start_response(status, headers)
return [b"Hello, world, from WSGI running as CGI!"]
CGIHandler().run(simple_app)
A Flask App Modified to Run as CGI
For this example, I modified the Flask Quickstart application to run under CGI at https://conradhalling.com/projects/helloworld_flask.py. Note that I changed the #!
line to use the Python virtual environment into which I had installed flask.
1
2
3
4
5
6
7
8
9
10
11
12
#!/home/conhal1/venv/bin/python3
from flask import Flask
from wsgiref.handlers import CGIHandler
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World, from Flask!</p>"
CGIHandler().run(app)
A Flask App Run by a CGI Script
Finally, I borrowed this example from Running Flask and Python with CGI. Here, the flask application is contained in its own module without any commands that run it. A second script imports the Flask application and runs it using wsgiref.handlers.CGIHandler
.
This is the module containing the Flask Quickstart application in a file named myapplication.py
.
1
2
3
4
5
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '<h1>Hello, World, from a Flask module!</h1>'
And this was the CGI application file, called myapplication.cgi
, which ran at https://conradhalling.com/projects/myapplication.cgi.
1
2
3
4
5
#!/home/conhal1/venv/bin/python3
from wsgiref.handlers import CGIHandler
from myapplication import app
CGIHandler().run(app)