<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: cgi</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/cgi.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-07-05T23:28:31+00:00</updated><author><name>Simon Willison</name></author><entry><title>Serving 200 million requests per day with a cgi-bin</title><link href="https://simonwillison.net/2025/Jul/5/cgi-bin-performance/#atom-tag" rel="alternate"/><published>2025-07-05T23:28:31+00:00</published><updated>2025-07-05T23:28:31+00:00</updated><id>https://simonwillison.net/2025/Jul/5/cgi-bin-performance/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://jacob.gold/posts/serving-200-million-requests-with-cgi-bin/"&gt;Serving 200 million requests per day with a cgi-bin&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Jake Gold tests how well 90s-era CGI works today, using a Go + SQLite CGI program running on a 16-thread AMD 3700X.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Using CGI on modest hardware, it’s possible to serve 2400+ requests per second or 200M+ requests per day.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I got my start in web development with CGI back in the late 1990s - I was a huge fan of &lt;a href="https://web.archive.org/web/20010509081826/http://www.amphibianweb.com/newspro/"&gt;NewsPro&lt;/a&gt;, which was effectively a weblog system before anyone knew what a weblog was.&lt;/p&gt;
&lt;p&gt;CGI works by starting, executing and terminating a process for every incoming request. The nascent web community quickly learned that this was a bad idea, and invented technologies like PHP and &lt;a href="https://en.wikipedia.org/wiki/FastCGI"&gt;FastCGI&lt;/a&gt; to help avoid that extra overhead and keep code resident in-memory instead.&lt;/p&gt;
&lt;p&gt;This lesson ended up baked into my brain, and I spent the next twenty years convinced that you should &lt;em&gt;never&lt;/em&gt; execute a full process as part of serving a web page.&lt;/p&gt;
&lt;p&gt;Of course, computers in those two decades got a &lt;em&gt;lot&lt;/em&gt; faster. I finally overcame that twenty-year core belief in 2020, when &lt;a href="https://simonwillison.net/2020/Nov/28/datasette-ripgrep/"&gt;I built datasette-ripgrep&lt;/a&gt;, a Datasette plugin that shells out to the lightning fast &lt;a href="https://github.com/BurntSushi/ripgrep"&gt;ripgrep&lt;/a&gt; CLI tool (written in Rust) to execute searches. It worked great!&lt;/p&gt;
&lt;p&gt;As was &lt;a href="https://news.ycombinator.com/item?id=44464272#44465143"&gt;pointed out on Hacker News&lt;/a&gt;, part of CGI's problem back then was that we were writing web scripts in languages like Perl, Python and Java which had not been designed for lightning fast startup speeds. Using Go and Rust today helps make CGI-style requests a whole lot more effective.&lt;/p&gt;
&lt;p&gt;Jake notes that CGI-style request handling is actually a great way to take advantage of multiple CPU cores:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These days, we have servers with 384 CPU threads. Even a small VM can have 16 CPUs. The CPUs and memory are much faster as well.&lt;/p&gt;
&lt;p&gt;Most importantly, CGI programs, because they run as separate processes, are excellent at taking advantage of many CPUs!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Maybe we should start coding web applications like it's 1998, albeit with Go and Rust!&lt;/p&gt;
&lt;p&gt;&lt;small&gt;To clarify, I don't think most people should do this. I just think it's interesting that it's not as bad an idea as it was ~25 years ago.&lt;/small&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=44464272"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/go"&gt;go&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/performance"&gt;performance&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;&lt;/p&gt;



</summary><category term="cgi"/><category term="go"/><category term="performance"/><category term="sqlite"/></entry><entry><title>websocketd</title><link href="https://simonwillison.net/2019/Jan/26/websocketd/#atom-tag" rel="alternate"/><published>2019-01-26T02:38:53+00:00</published><updated>2019-01-26T02:38:53+00:00</updated><id>https://simonwillison.net/2019/Jan/26/websocketd/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://websocketd.com/"&gt;websocketd&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Delightfully clever piece of design: “It’s like CGI, twenty years later, for WebSockets”. Simply run “websocketd --port=8080 my-program” and it will start up a WebSocket server on port 8080 and fire up a new process running your script every time it sees a new WebSocket connection. Standard in and standard out are automatically hooked up to the socket connection. Since it spawns a new process per connection this won’t work well with thousands of connections but for smaller scale projects it’s an excellent addition to the toolbok—and since it’s written in Go there are pre-compiled binaries available for almost everything.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=19000109"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/go"&gt;go&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/websockets"&gt;websockets&lt;/a&gt;&lt;/p&gt;



</summary><category term="cgi"/><category term="go"/><category term="websockets"/></entry><entry><title>Are there any alternatives to CGI for web servers?</title><link href="https://simonwillison.net/2013/Aug/10/are-there-any-alternatives/#atom-tag" rel="alternate"/><published>2013-08-10T12:14:00+00:00</published><updated>2013-08-10T12:14:00+00:00</updated><id>https://simonwillison.net/2013/Aug/10/are-there-any-alternatives/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/Are-there-any-alternatives-to-CGI-for-web-servers/answer/Simon-Willison"&gt;Are there any alternatives to CGI for web servers?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yes. CGI stopped being relevant around the turn if the century! Many languages can be embedded in web servers now (mod_php, mod_python, mod_perl for Apache etc), there's the FastCGI protocol which allows web servers to communicate with external processes without needing to start a brand new process for every request, and it's also common these days to run an HTTP server written in the same language as your application and proxy requests to it - Unicorn, gunicorn, Jetty are all examples of this.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/web-development"&gt;web-development&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cgi"/><category term="web-development"/><category term="quora"/></entry><entry><title>sfical.py</title><link href="https://simonwillison.net/2008/Jun/27/sfical/#atom-tag" rel="alternate"/><published>2008-06-27T08:09:42+00:00</published><updated>2008-06-27T08:09:42+00:00</updated><id>https://simonwillison.net/2008/Jun/27/sfical/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.pocketsoap.com/weblog/2008/06/1816.html"&gt;sfical.py&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Neat idea: write a CGI script that turns a proprietary API (in this case the SalesForce events API) in to standard ical format, then run it on your Mac’s local Apache server and subscribe to it from iCal.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apache"&gt;apache&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/icalendar"&gt;icalendar&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mac"&gt;mac&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/macos"&gt;macos&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/salesforce"&gt;salesforce&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/simon-fell"&gt;simon-fell&lt;/a&gt;&lt;/p&gt;



</summary><category term="apache"/><category term="cgi"/><category term="icalendar"/><category term="mac"/><category term="macos"/><category term="salesforce"/><category term="simon-fell"/></entry><entry><title>.php? .cgi? .who-cares?</title><link href="https://simonwillison.net/2007/Feb/9/graceful/#atom-tag" rel="alternate"/><published>2007-02-09T01:01:09+00:00</published><updated>2007-02-09T01:01:09+00:00</updated><id>https://simonwillison.net/2007/Feb/9/graceful/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.jpstacey.info/blog/2007/02/08/php-cgi-who-cares/"&gt;.php? .cgi? .who-cares?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
J-P Stacey argues that “URLs need to be hackable by the developer as well as by the user”. There’s certainly room for improvement in keeping complex URL structures maintainable from a server-side developer’s perspective.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/urls"&gt;urls&lt;/a&gt;&lt;/p&gt;



</summary><category term="cgi"/><category term="urls"/></entry><entry><title>SubWiki</title><link href="https://simonwillison.net/2006/Dec/16/subwiki/#atom-tag" rel="alternate"/><published>2006-12-16T19:19:51+00:00</published><updated>2006-12-16T19:19:51+00:00</updated><id>https://simonwillison.net/2006/Dec/16/subwiki/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://subwiki.tigris.org/"&gt;SubWiki&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
A wiki that uses Subversion for its data repository, implemented as a Python CGI.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="http://simonwillison.net/2006/Dec/16/code/"&gt;Google Code gets wikis and file downloads&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/subversion"&gt;subversion&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/wiki"&gt;wiki&lt;/a&gt;&lt;/p&gt;



</summary><category term="cgi"/><category term="python"/><category term="subversion"/><category term="wiki"/></entry><entry><title>Apache Module mod_actions</title><link href="https://simonwillison.net/2004/Aug/20/apache/#atom-tag" rel="alternate"/><published>2004-08-20T22:44:50+00:00</published><updated>2004-08-20T22:44:50+00:00</updated><id>https://simonwillison.net/2004/Aug/20/apache/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://httpd.apache.org/docs-2.0/mod/mod_actions.html#action"&gt;Apache Module mod_actions&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Channel all requests for a specific file type through a CGI script.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;&lt;/p&gt;



</summary><category term="cgi"/></entry><entry><title>Pwyky (A Python Wiki)</title><link href="https://simonwillison.net/2004/Jan/26/pwyky/#atom-tag" rel="alternate"/><published>2004-01-26T07:08:36+00:00</published><updated>2004-01-26T07:08:36+00:00</updated><id>https://simonwillison.net/2004/Jan/26/pwyky/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://infomesh.net/pwyky/"&gt;Pwyky (A Python Wiki)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
A neat little wiki in a single CGI file

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="http://www.disobey.com/dnn/2004/01/index.shtml"&gt;the disobey nonsense network&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;&lt;/p&gt;



</summary><category term="cgi"/></entry><entry><title>cgi_buffer</title><link href="https://simonwillison.net/2003/Nov/22/cgi_buffer/#atom-tag" rel="alternate"/><published>2003-11-22T18:36:28+00:00</published><updated>2003-11-22T18:36:28+00:00</updated><id>https://simonwillison.net/2003/Nov/22/cgi_buffer/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;a href="http://www.mnot.net/cgi_buffer/"&gt;cgi_buffer&lt;/a&gt; is voodoo magic for Perl, Python and &lt;acronym title="PHP: Hypertext Preprocessor"&gt;PHP&lt;/acronym&gt; scripts that automatically handles a bunch of bandwidth saving &lt;acronym title="HyperText Transfer Protocol"&gt;HTTP&lt;/acronym&gt; tricks such as Content-Length headers (which enable persistent connections), ETags for caching and GZip content compression. Pretty neat.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cgi"/></entry><entry><title>The difference between POST and GET</title><link href="https://simonwillison.net/2003/Oct/25/difference/#atom-tag" rel="alternate"/><published>2003-10-25T03:49:19+00:00</published><updated>2003-10-25T03:49:19+00:00</updated><id>https://simonwillison.net/2003/Oct/25/difference/#atom-tag</id><summary type="html">
    &lt;p&gt;How important is the ability to tell the difference between data sent by POST and data sent by GET (i.e in the query string) when developing web applications? Some web frameworks (such as &lt;acronym title="PHP: Hypertext Preprocessor"&gt;PHP&lt;/acronym&gt;) provide separate mechanisms for accessing POST and GET data. Others (such as Python's &lt;a href="http://www.python.org/doc/current/lib/module-cgi.html"&gt;cgi module&lt;/a&gt;) provide a single interface to form information that doesn't distinguish between the two. I already have a strong opinion on this but I'm going to leave it open for discussion here for a bit before weighing in.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/http"&gt;http&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/php"&gt;php&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cgi"/><category term="http"/><category term="php"/><category term="python"/></entry><entry><title>The Python Web SIG</title><link href="https://simonwillison.net/2003/Oct/18/pythonWebSIG/#atom-tag" rel="alternate"/><published>2003-10-18T22:42:09+00:00</published><updated>2003-10-18T22:42:09+00:00</updated><id>https://simonwillison.net/2003/Oct/18/pythonWebSIG/#atom-tag</id><summary type="html">
    &lt;p&gt;Python now has a &lt;a href="http://www.python.org/sigs/web-sig/"&gt;Web SIG&lt;/a&gt;. &lt;acronym title="Special Interest Group"&gt;SIG&lt;/acronym&gt;s are Special Interest Groups, each with a target to develop and improve a certain aspect of the Python language, standard library or community. The Web &lt;acronym title="Special Interest Group"&gt;SIG&lt;/acronym&gt; has two purposes: create a plan for improving Python's web client abilities (including things like the ability to parse &lt;acronym title="Cascading Style Sheets"&gt;CSS&lt;/acronym&gt;) and work on improving Python's server side capabilities.&lt;/p&gt;

&lt;p&gt;I'm hoping that the &lt;acronym title="Special Interest Group"&gt;SIG&lt;/acronym&gt; can work to bring together some of the work being done with web frameworks within the Python community. As demonstrated by &lt;a href="http://www.python.org/cgi-bin/moinmoin/WebProgramming" title="WebProgramming"&gt;this wiki page&lt;/a&gt;, Python users are spoilt for choice when it comes to selecting a framework for developing web applications. This is a dual edged sword - on the one hand diversity is a good thing, but on the other hand actually chosing a framework for a project has become a lengthy and arduous task. A few web frameworks (such as mod_python) are partially standardised around the interface defined by Python's &lt;a href="http://www.python.org/doc/current/lib/module-cgi.html"&gt;CGI module&lt;/a&gt;, but this module has some severe shortcomings (the greatest of which is probably an inability to distinguish between GET and POST data). I would like to see the &lt;acronym title="Special Interest Group"&gt;SIG&lt;/acronym&gt; define a more capable interface that covers more common web abilities, then encourage existing frameworks to provide a compatability layer for that interface. That way, developers could code to the standard interface safe in the knowledge that selecting and moving between frameworks would require very little in the way of changes to developed code.&lt;/p&gt;

&lt;p&gt;The &lt;acronym title="Special Interest Group"&gt;SIG&lt;/acronym&gt; is open to all, so I encourage anyone with an interest in Python's web programming capabilities to sign up and get involved.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/http"&gt;http&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cgi"/><category term="http"/><category term="python"/></entry><entry><title>Ludicrously simple templates with Python</title><link href="https://simonwillison.net/2003/Jul/28/simpleTemplates/#atom-tag" rel="alternate"/><published>2003-07-28T23:37:05+00:00</published><updated>2003-07-28T23:37:05+00:00</updated><id>https://simonwillison.net/2003/Jul/28/simpleTemplates/#atom-tag</id><summary type="html">
    &lt;p&gt;A long, long time ago I wrote my first ever &lt;acronym title="PHP: Hypertext Preprocessor"&gt;PHP&lt;/acronym&gt; templating system. It was pretty simple; it consisted of a function that took two arguments: the name of a template file, and an associative array of replacements to make on that file.&lt;/p&gt;

&lt;p&gt;I've finally got around to playing with Python &lt;acronym title="Common Gateway Interface"&gt;CGI&lt;/acronym&gt;s for web development recently, and decided I needed a similar system. Thanks to Python's powerful string formatting operator, it ended up as a one-liner:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;def template(file, vars):
    return open(templatedir.template, 'r').read() % vars
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Presuming you've set templatedir at the top of the script, the above function lets you load a template and make some simple replacements on it with a single function call. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;h3&amp;gt;%(title)s&amp;lt;/h3&amp;gt;

%(body)s

&amp;lt;p class="footer"&amp;gt;Posted: %(date)s&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With the above saved in the template directory as "entry.tpl", the template function above can be used thus:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;
print template('entry.tpl', {
    'title':'A blog entry', 
    'body':'Entry goes here...',
    'date':'3rd July 2003'})
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The work is all done by the &lt;code class="python"&gt;% vars&lt;/code&gt; bit at the end of the line. Since vars is a dictionary, Python substitutes the named items in the dictionary for their corresponding &lt;code class="python"&gt;%(varname)s&lt;/code&gt; tokens in the string loaded from the template file. More information on &lt;a href="http://www.python.org/doc/current/lib/typesseq-strings.html" title="2.2.6.2 String Formatting Operations"&gt;string formatting operations&lt;/a&gt; can be found in the manual.&lt;/p&gt;

&lt;p&gt;As templating systems go, it's far from the most useful or complete solution. It does however show that a little Python can go quite a long way.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/php"&gt;php&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cgi"/><category term="php"/><category term="python"/></entry><entry><title>More Python advocacy</title><link href="https://simonwillison.net/2002/Jul/5/morePythonAdvocacy/#atom-tag" rel="alternate"/><published>2002-07-05T13:31:47+00:00</published><updated>2002-07-05T13:31:47+00:00</updated><id>https://simonwillison.net/2002/Jul/5/morePythonAdvocacy/#atom-tag</id><summary type="html">
    &lt;p&gt;More Python advocacy: &lt;a href="http://www.linux-mag.com/2002-04/python_01.html"&gt;PYTHON: Yes, You SHOULD Be Using it!&lt;/a&gt; The article contains some background information on Python and why it is worth knowing, but the bulk of the article consists of a getting started guide for Python on Linux, complete instructions on using the interactive prompt, code samples and a small CGI script. It is worth noting that the CGI script example should not be deployed anywhere accessible to the public as it could allow crackers to execute code of their chosing on your web server.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cgi"&gt;cgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="cgi"/><category term="python"/></entry></feed>