<?xml version="1.0" encoding="utf-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Fun with ones and zeros - wsgi</title>
<subtitle>Barry&#039;s notes on computer software and hardware</subtitle>
<link href="/blog/tags/wsgi"></link>
<updated>2026-04-17T13:43:49-07:00</updated>
<id>urn:uuid:69a5b1a8-8e62-199d-9074-fe2be47bf867</id>
<entry>
<title>Running Python WSGI apps with SCGI and inetd</title>
<link href="/blog/entries/running-python-wsgi-apps-scgi-and-inetd"></link>
<id>urn:uuid:17ba402d-28d0-1844-298e-26ae6796046b</id>
<updated>2011-09-18T06:00:00-07:00</updated>
<author><name>Barry Pederson</name>
<email>bp@barryp.org</email>
</author>
<content type="html">&lt;body&gt;&lt;p&gt;&lt;em&gt;Using &lt;a href=&quot;https://github.com/barryp/scgi-inetd-wsgi&quot;&gt;scgi-inetd-wsgi&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Previously, I wrote about running &lt;a href=&quot;/blog/entries/cgi-scripts-nginx-using-scgi/&quot;&gt;CGI Scripts with Nginx using SCGI&lt;/a&gt;
with the help of a super-server such as &lt;code&gt;inetd&lt;/code&gt; and a small C shim that
takes a SCGI request from stdin and sets up a CGI enviroment.&lt;/p&gt;
&lt;p&gt;There&#039;s also a companion project &lt;a href=&quot;https://github.com/barryp/scgi-inetd-wsgi&quot;&gt;on GitHub&lt;/a&gt; for doing something
similar with Python WSGI apps.  The code works on Python 2.6 or higher
(including Python 3.x).  &lt;em&gt;It can easily be patched for Python 2.5 or lower
by with a simple string substitition mentioned in the source file&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It&#039;s not something you&#039;d want to run a frequently-accessed app with,
because there&#039;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&#039;t want to have to keep and monitor a long-running
process, or for development of a WSGI app where you don&#039;t want to have
to stop/start a process everytime you make a change.&lt;/p&gt;
&lt;p&gt;Let&#039;s take a look at a diagram to see what the flow will be:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/10/23/scgi_wsgi.png&quot; alt=&quot;SCGI&amp;lt;-&amp;gt;WSGI&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Nginx opens a socket listened to by inetd&lt;/li&gt;
&lt;li&gt;inetd spawns a Python script with stdin and stdout connected to the
accepted connection&lt;/li&gt;
&lt;li&gt;The Python script would import &lt;code&gt;inetd_scgi&lt;/code&gt; and call its &lt;code&gt;run_app&lt;/code&gt; function
passing a WSGI app to actually handle the request.  &lt;code&gt;run_app&lt;/code&gt; will read
the SCGI request from stdin, setup a WSGI enviroment, call the handler, and
send the handler&#039;s response back to Nginx via stdout.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&#039;s how you&#039;d wire up the &lt;code&gt;Hello World&lt;/code&gt; app from &lt;a href=&quot;http://www.python.org/dev/peps/pep-3333/&quot;&gt;PEP 3333&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;source&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;HELLO_WORLD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Hello world!&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;simple_app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sd&quot;&gt;&quot;&quot;&quot;Simplest possible application object&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#039;200 OK&#039;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;response_headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#039;Content-type&#039;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#039;text/plain&#039;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;start_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response_headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HELLO_WORLD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vm&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#039;__main__&#039;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;inetd_scgi&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;inetd_scgi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run_app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;simple_app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you had saved that script as say &lt;code&gt;/local/test.py&lt;/code&gt;, you might add this to
&lt;code&gt;/etc/inetd.conf&lt;/code&gt; to serve it up:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:www:www:200:/var/run/test.sock  stream   unix   nowait/4  www /local/test.py /local/test.py&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and in Nginx with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;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;
}    &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, accessing &lt;a href=&quot;http://localhost/test&quot;&gt;http://localhost/test&lt;/a&gt; should show &#039;Hello world!&#039;&lt;/p&gt;&lt;/body&gt;</content>
</entry>
</feed>