A Modern Web App in C: One Binary, Three Dependencies, and Zero Downtime

Corey Prophitt shipped a commercial web product—marketyour.games—using the BCHS stack: OpenBSD, C, httpd, and SQLite. No framework, no templating language, no container. Every request spawns a fresh process, and deploying a new version means replacing one file. He argues CGI's 2004 decline no longer holds up: process forking is cheap, the supply chain is tiny, and the entire app fits in your head.

CGI is serverless, minus the vendor (and surprise bills).
  1. ramses0

    My favorite trivia is that busybox has built-in cgi-bin support (and `rclone serve webdav` seems remiss to not mention as well). `https://elixir.bootlin.com/busybox/1.37.0/source/networking/...`

    Everything the post mentions is 100% true and well-reasoned, especially with the inclusion of pledge/chroot/etc. for dropping privileges.

    There's two diametrically opposed deployment mechanisms:

    1) stack towers of glop on top of each other until you're running a simple `echo "hello world"` on top of a docker container inside a vm in a proxmox server as part of a k8s cluster under a hypervisor running on remote compute...

    2) just run `bash -c 'echo "hello world"'` and front it with CGI (stateless, single binary, yada yada yada...)

    Take a peek at https://github.com/Domain/bash.cgi ... not that i'm suggesting that 'bash over busybox using cgi-bin' is the "proper architecture", it's more trying to illustrate that the amount of code that holds you back from being nearly truly "frameworkless" is tiny and easy to reason about.

    For some of the internal tooling I'm doing for work, I've been tending towards:

    some-cmd [--json|--markdown] ...yet-more-args...

    When you use the process and shell environment itself as a repl, you start trending towards `[--cgi-bin]` would "just" be another output type, and the ability (nay: foresight!) to ensure that your commands are independent, reproducible, and only depend on their input arguments leads you directly towards being runnable in both "hostile" ( […]

  2. OleksandrC

    For people who find interest in weird web applications, I have been working on a game project, in C++, where the client is compiled to WebAssembly with Emscripten, and the application server is also implemented in C++ (behind nginx).

    This is from pre-AI era also. The game is Civ-like. Custom engine from scratch (including both the 3D stuff, and all the web handling also).

    Take a look: https://statebuilder.com/

  3. assimpleaspossi

    I started a web dev company 22 years ago after developing an online menu ordering system for a restaurant I owned. I, then we, did pretty much the same thing as talked about in the posting but we used fastcgi. I started with C because I knew C. That was my real job. It ran so well, the franchise bought the software from me--and then devolved it to all the Microsoft stuff and had issues upon issues from then on out. That's another story.

    I continued to make sites for other venues that needed online ordering; such as theatre companies and restaurants. All in C, fastcgi, FreeBSD, postgresql and h2o-server cause it always did what we wanted without bending to someone else's rules. It was fast and easy to make changes while changes weren't made for us or without our consent. We did very well for ourselves.

  4. unixholder

    The deeper you go into complex web technologies & frameworks, the more obvious it becomes that simplicity wins.

  5. benlivengood

    Golang also makes it possible to serve a web site or service from a single binary. You can even avoid linking libc if you stick to core Go (CGO_ENABLED=0), and it comes with all the http and tls libraries you need to replace the traditional web server (nginx, apache, httpd) as well.

    I love C and wrote some CGIs in C in the past but I don't love concurrent programming in C. While forking and execing can use shared read-only mmap on .text segments, the .bss and .data will need initialization and copying; there's unavoidable startup overhead that a threaded process avoids, and raw pthreads is kind of painful. If all you need to do is serve a low traffic site, CGI is fine.

    My biggest worry would be how often the SQLite DB gets backed up because there's no way a C web server will be free of RCEs in today's world.

  6. Levitating

    CGI is great. Sadly nginx doesn't support it natively as opposed to lighttpd.

    I like this project for adding CGI to nginx: https://github.com/pjincz/nginx-cgi

    There's also methods of starting Rack applications directly form nginx via passenger[1]. Rack is the CGI like interface for ruby webapps: https://github.com/rack/rack

    It easily allows for writing applications and middleware with a few lines of ruby.

    [1]: https://www.phusionpassenger.com/documentation/Users%20guide...

  7. creatonez

    Is the CGI process opening up the SQLite database for every request...? That would have the most insane contention ever.

  8. Kuyawa

    The time is right for AI to generate a basic C web framework just like Node Express with request, response, template, cookies, auth, db, websockets and some other libs

    It would be blazing fast, for use by AI itself

    Just for fun

More from this day

2026-10-12