Running Python WSGI apps with SCGI and inetd
Using scgi-inetd-wsgi
Previously, I wrote about running CGI Scripts with Nginx using SCGI
with the help of a super-server such as inetd
and a small C shim that
takes a SCGI request from stdin and sets up a CGI enviroment.
There's also a companion project on GitHub for doing something similar with Python WSGI apps. The code works on Python 2.6 or higher (including Python 3.x). It can easily be patched for Python 2.5 or lower by with a simple string substitition mentioned in the source file
It's not something you'd want to run a frequently-accessed app with, because there'd be quite a bit of overhead launching a Python process to handle each request. It may be useful however for infrequently used apps where you don't want to have to keep and monitor a long-running process, or for development of a WSGI app where you don't want to have to stop/start a process everytime you make a change.
Let's take a look at a diagram to see what the flow will be:
- Nginx opens a socket listened to by inetd
- inetd spawns a Python script with stdin and stdout connected to the accepted connection
- The Python script would import
inetd_scgi
and call itsrun_app
function passing a WSGI app to actually handle the request.run_app
will read the SCGI request from stdin, setup a WSGI enviroment, call the handler, and send the handler's response back to Nginx via stdout.
Here's how you'd wire up the Hello World
app from PEP 3333
#!/usr/bin/env python HELLO_WORLD = b"Hello world!\n" def simple_app(environ, start_response): """Simplest possible application object""" status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return [HELLO_WORLD] if __name__ == '__main__': import inetd_scgi inetd_scgi.run_app(simple_app)
If you had saved that script as say /local/test.py
, you might add this to
/etc/inetd.conf
to serve it up:
:www:www:200:/var/run/test.sock stream unix nowait/4 www /local/test.py /local/test.py
and in Nginx with:
location /test {
scgi_pass unix:/var/run/test.sock;
include /usr/local/etc/nginx/scgi_params;
fastcgi_split_path_info ^(/test)(.*);
scgi_param SCRIPT_NAME $fastcgi_script_name;
scgi_param PATH_INFO $fastcgi_path_info;
}
Then, accessing http://localhost/test should show 'Hello world!'