A Modern Web App in C
334 points by prophittcorey 7 hours ago | 148 comments

ramses0 6 hours ago
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" (ie: firecracker vm / lambda-style) or very "comfortable" environments (ie: shell, debuggers, unit/integration tests).
reply
rpdillon 5 hours ago
Mirrors my experience, and it's funny you mention busybox: I just discovered busybox's ability to serve via `busybox httpd -p 9000 -h . -f -v` with a `cgi-bin` folder dropped in the current directory.

I already write Python services using Bottle that function both as a standalone server and as a CGI script, and I've been updating them to work with busybox's more constrained CGI environment (basically being able to handle the lack of .htaccess rewrite rules).

I definitely see a chance for simple deployment tools to make a resurgence as we create more one-off/disposable/personal software, and the low system requirements for something like busybox + lua stack are extremely minimal, which fits well with the current DDR4-is-good-enough zeitgeist. I'm running them on an old Raspberry Pi 2B and it's plenty performant for the ~10 people that access it regularly.

reply
MomsAVoxell 5 hours ago
Instead of busybox+Lua, I just use TurboLua:

https://turbo.readthedocs.io/en/latest/

Event driven, fast, all the networking basics in place including http, mustache templates and encryption, light and small executable, very nice for embedded applications, signals and fd handling built-in, very easy to use…

Have used it very successfully for million-dollar projects, including some scientific applications running on limited-resource systems (512 megs of RAM) ..

Was very, very easy to add C functions to interface with the web front-end, libffi is great for this purpose, but its also very easy to extend as a standard, well-written Lua/C application ..

reply
rpdillon 4 hours ago
This is exactly the sort of thing I'm really interested in. I'm particularly excited about various takes on Lua+batteries, have looked into designing my own (C wrapper with bindings to networking, JSON, templating, and DB libraries), but found Redbean to be almost ideal so never got past overall design to dig into code.

Turbo looks fantastic, though! It's precisely the niche I was looking to have filled, so I'll build a prototype or two in it to see what I think. Very much appreciate the pointer!

reply
MomsAVoxell 4 hours ago
You’re welcome - we share interests, I too am interested in the Lua+batteries approach to life - I’ve used Lua very successfully in many commercial projects, so I’m quite convinced of its power in spite of the warts and thorns that many newbies in the ways of Lua tend to whine about.

TurboLua is particularly great because it really integrates about all of the I/O mechanisms you could want in a network-centric application, plus it has a pretty nice runtime loop which is easy to hook into and coordinate properly with signal handlers and fd sets and things. Can’t beat it as a very quick way to do embedded stuff too - very easy to do gpio, signal handling, etc.

Good luck, if you have time to share your thoughts after an initial first-pass, I’d be happy to hear your perspective ..

reply
OleksandrC 6 hours ago
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/

reply
nmstoker 2 hours ago
Nice. I know your comment was on the technical points, but it definitely under sells the game!
reply
hughw 5 hours ago
It's beautiful
reply
Transformanshen 53 minutes ago
That's cool
reply
assimpleaspossi 3 hours ago
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.

reply
glouwbug 3 hours ago
Feels so long ago the way you write about it, but 22 years ago was basically 2005
reply
assimpleaspossi 3 hours ago
It was February, 2004
reply
benlivengood 4 hours ago
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.

reply
ncruces 2 hours ago
Shameless plug: if you value Go, and CGO_ENABLED=0, and SQLite, and are worried about C in a web server and RCEs, may I interest you in my SQLite driver?

https://github.com/ncruces/go-sqlite3

I just wrote up the security goals of the tool I use to translate C to Go: https://github.com/ncruces/wasm2go/blob/main/SECURITY.md

I obviously can't make any promises, as it's just a personal pet project, but those are the goals, and they do catch memory corruption bugs in practice: https://sqlite.org/bugs/forumpost/543f94984b

reply
unixholder 2 hours ago
The deeper you go into complex web technologies & frameworks, the more obvious it becomes that simplicity wins.
reply
chasil 18 minutes ago
I have used ccgi.c when I needed access to system calls and PHP was too much of an attack surface.

https://github.com/moths/libccgi/blob/master/ccgi.c

reply
Levitating 6 hours ago
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...

reply
synergy20 5 hours ago
I just use lighttpd
reply
Levitating 3 hours ago
I used it for a long time but the configuration of nginx just allows for more stuff.

I have my own configuration template for nginx: https://git.levitati.ng/Levitating/nginx.conf

reply
huijzer 5 hours ago
But the real question is, does Caddy support it?

The answer is: it does but via community plugins.

reply
BirAdam 6 hours ago
fastcgi wrap.
reply
assimpleaspossi 3 hours ago
Exactly what I used and wonder why the OP didn't. I'll comment at the top.
reply
Levitating 3 hours ago
Ease of configuration, I think? I don't remember my gripes with fcgiwrap exactly.

I have used it and I've even made PR for it which led to a response from the lighttpd maintainer: https://github.com/gnosek/fcgiwrap/pull/62

Essentially I wanted fgciwrap to be able to accept arbitrary response bodies without headers, so I could use it with programs that weren't actually made for cgi. Lighttpd supports this but apparently that's an happy accident.

reply
ok123456 5 hours ago
A Go binary with CGO=0 and all templates/documents embedded gives you a better overall tooling and deployment experience. Put it in a scratch container for complete isolation.
reply
doublepg23 5 hours ago
CGO=0 came in clutch at previous job when we were deploying Go apps compiled on builders that had a newer glibc than the actual prod server.
reply
creatonez 2 hours ago
Is the CGI process opening up the SQLite database for every request...? That would have the most insane contention ever.
reply
zbentley 2 hours ago
Would it? The file handle doesn’t contend for a lock IIRC; just writes.
reply
creatonez 2 hours ago
I mean sure, you could still win if almost no requests are opening the database in write mode
reply
zbentley 15 minutes ago
Does it lock if the DB is opened in write mode, or only when a write query is issued?

If the latter, then it’ll only contend on simultaneous writes, which mutex anyway.

reply
Kuyawa 3 hours ago
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

reply
nostrademons 2 hours ago
Why C instead of Rust if you're using AI anyway?

C introduces the possibility of memory-safety issues, which are deadly in server software that's exposed to the Internet. And AI, from what I've seen, is not all that great at writing software with zero memory bugs.

Rust closes the memory safety holes, at the cost of making the programmer think through ownership and architecture much more carefully. Those are exactly the skills that AI is good at. So if you want something fast and are writing it with AI anyway, why not have the AI generate Rust code?

reply
joshheitzman 38 minutes ago
Because the memory safety Rust offers isn't worth the supply chain risks: https://safeguard.sh/resources/blog/rust-supply-chain-securi...
reply
zanecodes 14 minutes ago
A problem that C solves by simply not having a supply chain! You can vendor dependencies in Rust just as easily as you can in C; far easier in fact thanks to `cargo vendor`. Cargo won't review them for vulnerabilities though, you'll still have to do that yourself.
reply
1718627440 3 minutes ago
It does, the package systems of C evolved alongside the OS, so they are now the OS package managers and also cope with all other language mangers.
reply
Ygg2 2 minutes ago
C (and C++) has a supply chain. It's called unpaid Linux maintainers.
reply
nostrademons 12 minutes ago
Don't use packages you didn't vibecode and audit yourself then. That's the situation C puts you in anyway.
reply
cozzyd 23 minutes ago
supply chain, compile times, binary size
reply
nostrademons 13 minutes ago
Not huge problems for a web app, where you are controlling deployment yourself.
reply
Panzerschrek 6 hours ago
> There's no separate database server. You open the database file through SQLite's C API.

> Every request spawns a fresh process.

How does it work when multiple concurrent requests are possible? Does SQLite allow simultaneous write access from multiple processes?

reply
citrin_ru 6 hours ago
SQLite does allow write access from mulitple processes - file locks (fcntl) are used to ensure at any given moment only one of processes modifies the database (or WAL if WAL is enabled).
reply
prophittcorey 6 hours ago
SQLite can handle multiple concurrent requests if it's set to WAL mode. Reading is all non-blocking/concurrent but writing is still synchronous. You should also set the "busy timeout" or else your blocked writes will timeout immediately.
reply
tomjen3 2 hours ago
In Wal mode you can have multiple readers. Writers block, but because there is no network traffic, the writers finish very quickly, so in practice you don't usually wait that long.
reply
warkdarrior 6 hours ago
Users who send concurrent requests will be summarily banned and their data deleted. It's the only way to be sure.
reply
huijzer 5 hours ago
SQLite is a database. The main idea of a database is to support concurrent reads/writes although databases differ in how much concurrency they allow
reply
td521534f12 5 hours ago
The answer is more complicated for SQLite: https://sqlite.org/isolation.html

> There can only be a single writer at a time to an SQLite database. There can be multiple database connections open at the same time, and all of those database connections can write to the database file, but they have to take turns.

However, it can also be configured in WAL mode where the single writer is applying WALs while the applications append to the log.

reply
sophacles 4 hours ago
The main idea of a database is to support storing data in a structured and queryable way. Concurrency came later.
reply
hughw 5 hours ago
I disagree with the first sentence. In 199x the first people I knew making web pages dropped perl scripts, not C programs, into cgi-bin.
reply
fleeno 19 minutes ago
My first CGI programs around that time were in bash! I wrote so much useless but fun things back then.
reply
forinti 2 hours ago
I learnt Perl because I had to make a page with a form that would then be turned into Postscript and printed. My only options were C, which I knew well, and Perl, which I had never seen before. So I got to learning Perl. Doing it in C just seemed like too much work for the task.
reply
nkozyra 5 hours ago
May have pre-dated you by a bit. Perl definitely took foot not long after but the earliest cgi-bin days were dominated by C before people got tired of fighting compilation for web apps.

IIRC the spec itself says it was built for C applications.

mod-perl was a godsend, of course.

reply
minaguib 5 hours ago
Perl's CGI.pm was updated as recently as 5 months ago :)

https://metacpan.org/pod/CGI

reply
icedchai 2 hours ago
Same. My first "web app" was a Perl CGI that saved data to mSQL (not MySQL), probably early 1995.
reply
wainstead 60 minutes ago
Same!
reply
rjrjrjrj 4 hours ago
I started using Perl in 1996.

But the very first CGI scripts I wrote were in C, late 95 or early 96. Apache on Slackware Linux.

reply
layer8 3 hours ago
I still have such Perl scripts deployed, though using FastCGI.
reply
PaulDavisThe1st 4 hours ago
We did the CGI-bin in C thing at amzn in 1994.
reply
user0120397125 4 hours ago
[dead]
reply
jjuel 4 hours ago
I just really wish it had some examples of code in there to get a better idea of what is really going on. It sounds interesting.
reply
tomcam 3 hours ago
They use this framework: https://learnbchs.org

Their example is:

    #include <err.h> /* err(3) */
    #include <stdlib.h> /* EXIT_xxxx */
    #include <stdio.h> /* puts(3) */
    #include <unistd.h> /* pledge(2) */ 
    int main(void)
    {
      if (pledge("stdio", NULL) == -1) 
        err(EXIT_FAILURE, "pledge");
        puts("Status: 200 OK\r");
        puts("Content-Type: text/html\r");
        puts("\r");
        puts("Hello, world!\n");
        return EXIT_SUCCESS;
      }
reply
mc007 5 hours ago
came back to C/C++ for same reasons, no supply chain trouble, fits in my head, runs forever, ... here a playground for win32, using partially webview2, all batteries included, openai client , tts, stt, vpl, images, audio, video, ... comes with webview2 apps, settings (and encryption), config, rest server, ipc, testing, CLI11, postgres, installer, doc gen, modbus, OpenCV, daemon, computer use, agent memory, image tools, mcp server/client, experimental flow editor - what a fun and exciting times :) https://github.com/polymech-info/win32-boilerplate
reply
codazoda 2 hours ago
I agree on "fits in my head". I haven't used C++ but I used to love ANSI C. I had a reference manual for it that was something like 30 pages and basically covered the entire language. There's something magical about the compact size of regular C.
reply
rietta 2 hours ago
It's been a long time since I have tried to do Windows work in C/C++. Is this Win32 the actual Win32 API of yesteryear or something else. I thought CMoke was a Unix tooling.
reply
criddell 13 minutes ago
Microsoft added CMake support to Visual Studio in 2017.
reply
macleginn 4 hours ago
"A modern web application typically puts a web server like nginx in front and reverse-proxies to an application server written in another language like Ruby, Python, Go, or Rust. That always felt a bit strange to me: you essentially have two web servers, and one of them is also responsible for your business logic." -- Is the fundamental difference here that the business-logic binary is not always running but gets spun out with each request? This looks like a relatively minor thing, to be honest.
reply
prophittcorey 2 hours ago
I meant to express the layers of abstraction feel strange to me in a typical setup.

A typical setup today looks like:

nginx -> puma/unicorn/gunicorn/etc -> your code

With cgi that middle layer is gone. It's just:

nginx -> your code

The layer reduction is nice when it comes to things like debugging. You don't have to guess if the middle server is removing a header, failing to forward a header, etc.

It's obvious who does that with cgi.

reply
bijowo1676 5 hours ago
Author described good ole PHP 3.

Early PHP (3 and 4) were the thin layer over the C libraries and were pretty fast and easy. it came about right when CGI was deprecated and it solved CGI's problems

reply
dorongrinstein 29 minutes ago
Many tools can achieve the same thing. I can write a note in pencil, pen, crayon etc. I will tell you a secret, but don't tell anyone: you can write it in assembly also.
reply
prophittcorey 18 minutes ago
Don't give me any more ideas!
reply
fmo91 6 hours ago
It's not very clear to me why the author has chosen C in the first place. I appreciate the effort of sharing the experience with us, anyway.
reply
prophittcorey 6 hours ago
I didn't want to state why C and not "X" because the comments would have devolved into an all out language war.
reply
kanbankaren 5 hours ago
As someone who works on C compilers, I find the obession with C language insane.

For any greenfield project, pick up C++ in lieu of C if you want a C language.

There is no runtime penalty for using C++ if you stick to plain structs and don't use virtual functions, but you get better static type safety, lvalue references, namespaces, etc. even if you don't use the OO features.

Even for virtual functions, the overhead is minimal that it is just noise.

C compilers themselves are written in C++ for the last 15 years. Oh, the irony!

reply
glouwbug 3 hours ago
Because in practice it’s really hard to not succumb to C++ feature creep. You start with good intentions and limit yourself to namespaces and structs, but then the “this will benefit from a vector, or this from a map” appears, then you realize you’d like a templated use case, and a single raw pointer or resource handle from a call to something like fopen() suddenly is not releasing its resource on a linked list pop and now you’re writing move semantics on top of copy semantics because a destructor declaration silently enforces copies on a std::move without move semantics. You reach for a unique pointer and, and all of a sudden, you have most of modern C++ without a single virtual call.

So people obsess over C because you’re hard limited by the upper feature bound. And that’s not so bad because C gets feature updates too - microscopic but effective feature updates; see C29 for the poor man’s RAII: defer

reply
ricardobeat 2 hours ago
C3 lang gives you defer + a lot of significant ergonomic improvements right now: https://c3-lang.org
reply
glouwbug 13 minutes ago
C3 is very good
reply
feelamee 45 minutes ago
and what it does take away? most "better C" languages basically looks like C++ (except zig, maybe). Nobody write something real in them, so nobody knows about their pitfalls.
reply
kevin_thibedeau 4 hours ago
T> here is no runtime penalty for using C++

Large portions of the standard lib depend on heap allocations. C is a much safer target for environments with limited resources.

reply
prophittcorey 5 hours ago
I generally like "C-style C++", but I find it difficult to draw the line between C and C++. It's too easy to keep reaching into C++ for "just one more thing."

That may be a me problem.

reply
PaulDavisThe1st 4 hours ago
It's what we did at amzn in 1994 ...
reply
bigbuppo 2 hours ago
Wasn't amazon running on tandem back then?
reply
PaulDavisThe1st 2 hours ago
In 1994, amzn ran on a single solaris workstation. Same at the beginning of 1995. I can't comment after that.
reply
ricardobeat 2 hours ago
There is a huge mental overhead penalty...
reply
christoff12 6 hours ago
Fair enough. But I am also curious if you'd like to share your rationale.
reply
Kevin_Flynn 6 hours ago
I can never figure out why everything isn't in C. :|
reply
ricardobeat 2 hours ago
Is it because you segfault before reaching the answer?
reply
1718627440 2 minutes ago
A segfault IS the memory protection taking in effect.
reply
layer8 3 hours ago
The underlying libraries you use tend to be in C anyway, so it simplifies things to just use them with their native interface, and not having to add another language runtime and its idiosyncrasies.
reply
uecker 6 hours ago
Yesterday or so there was a post about using Zig. When I read it I thought that using C would work equally well.
reply
christoff12 6 hours ago
Yeah, I thought it was interesting that both of these[0] were on the front page.

[0] - the other one: https://news.ycombinator.com/item?id=50051573

reply
EGreg 6 hours ago
I'm old enough to remember when the OKCupid guys wrote their own webserver in C++!

I took the concept of "slots" in requests, from it: https://github.com/okws/okws

reply
codazoda 6 hours ago
It hasn't been touched in a long time, maybe that's because it's "complete", but here's a quick CGI library:

https://github.com/codazoda/cgi-lib

reply
Surac 4 hours ago
i also do that way, but i also have written my own webserver so i have no cgi interface. it serves files and provides "special" sites for the application written in. I use html and css as a frontend. nealy no js code in the html. Things i hate: - applicatin status handling - mixing html, css, js and c in one file - having no web "widgets" - having to make them by myself
reply
rietta 4 hours ago
There is Boost in C++. It is very mature and honestly modern C++ has a lot of extremely powerful stdlib functionality and classes that will still be orders of magnitude more performant that the vast majority of the web app languages we use today. See https://www.boost.org/
reply
lilbigdoot 6 hours ago
I'm still in the middle of reading but I wanted to comment first that I had a pleasantly surprising experience a few years ago with CGI. I hadn't thought about CGI since I was a kid and I was tasked with adding a simple dynamic page to a server that had nothing running yet except apache. For whatever reason I though to try out CGI because of how simple the page was going to be, and yeah. Would recommend

I just got C FFI working in my LLVM based language last night so I'll need to take a look at playing around with BCHS :)

reply
hollowonepl 5 hours ago
I was not thinking about vanilla C and CGI but I wrote my own modern web api server app in C++ (std+boost only) and I found it extremely pleasant experience. very reliable and little supply chain/dependency hell problematic too.

It’s for intranet business app so although it’s not yet production ready yet, definitively winning against many other modern approaches in web development in my consideration, and quite refreshing POC project.

reply
whizzter 2 hours ago
Yeah, shuddering at trying to manage memory vs static strings (with OOB risks) in plain C, modern C++ does give so much.

I'm actually also rewriting a header-only server (std c++ and sockets) I wrote a few years back to take advantage of C++26 reflections and similar to give it something similar in capability to AspNetCore+EFCore.

reply
6c696e7578 44 minutes ago
fcgi tends to be overlooked
reply
Quitschquat 6 hours ago
I worked on a FORTRAN 77 CGI application in the early 00s. I think the host was Apache httpd, on some old HPUX version.
reply
dhuan_ 5 hours ago
How about modern web apps in shell scripts only:

https://dhuan.github.io/mock/latest/examples.html

reply
chihuahua 2 hours ago
Ideally, it should be a shell script for CMD.EXE, using the finest scripting language ever invented. The elegance of using FOR for such diverse tasks as enumerating files, file contents, string splitting, lists of numbers, and parsing the output of another command, is unmatched.
reply
Scubabear68 6 hours ago
From the article, "WRITING HTML AND CSS IN C ISN'T TOO BAD".

Um, any and all string handling in C is pretty miserable.

reply
feelamee 36 minutes ago
tell me where working with strings is not miserable? Practically, modern languages with RAII make it easy at the cost of perfomance (doing a lot of allocations). So, if you doing lot of string handling, you still need to think how to do it in performant way. If doing it a bit - why care about miserable.
reply
prophittcorey 6 hours ago
To be fair, the HTML and CSS in C wasn't too bad.. the Youtube scraper was also written in C and that was a lot more painful :)
reply
sam1r 6 hours ago
I can empathize entirely. After writing a scraper for html in C, outputting html in C is a piece of cake.
reply
PhilipRoman 6 hours ago
Emitting strings is fine, it's the parsing that sucks.
reply
Joker_vD 6 hours ago
If you do it with the string functions from the standard library then yes, it is.
reply
prophittcorey 6 hours ago
The standard string functionality is painful. I wrote my own string view and string builder that work with fixed size strings. No memory allocations, etc.
reply
throwaway2037 5 hours ago
I am confused. Is this project open source? If yes, I could not find a link to the source code. Can someone help me?
reply
emersonrsantos 6 hours ago
Does anyone know if Hacker News uses CGI as well? I know there's some JavaScript and AJAX magic for the interactive elements on the frontend.
reply
geoffbp 5 hours ago
I remember the days of wrangling cgi-bin on Linux hosts! Not a common paradigm these days..
reply
orphereus 3 hours ago
Wow, you are a role model for me
reply
Alifatisk 5 hours ago
Reminds me of the Vibe.d web framework for D lang. Good memories.
reply
chmaynard 5 hours ago
Not open source, apparently. Am I missing something?
reply
gfalcao 3 hours ago
Yes, but why? Why really? Are you Valgrinding the s*t out of the code? What about memory leaks? No template language? Did you use an A.I. Agent? I mean, the code is probably porn for GTK/glib coders, unless it's a horror movie instead. I'm really confused on the motivation there.
reply
fg137 2 hours ago
> CGI's decline was justified in 2004 but doesn't hold up in 2026.

I mean, the article should not be taken seriously on any technical level. It's ok just for fun.

reply
chihuahua 2 hours ago
I think the best parody is one that leaves the reader wondering if it was intended as parody, or if the author was serious.
reply
a3w 3 hours ago
why not dietlibc/gatling/append-only-DBs?
reply
afavour 6 hours ago
A shame to hand code a project in C and then use AI to write a blog post.

It’s a cool project to test yourself but most of the benefits outlined would also apply to Go, Rust, etc, and then you also get memory safety thrown into the mix as well.

reply
skrrtww 6 hours ago
I don't think the post was written by AI.

It has headers like AI blogposts, and features a lot of parallel structure like AI blogposts ("there's no <blank>. you <blank>"), but if you actually read it none of it reads like slop. To me anyway.

reply
xd1936 6 hours ago
Interestingly, Pangram says that exactly the first 50% is AI and the second half is not. ¯\_(ツ)_/¯
reply
Muhammad523 6 hours ago
Not that those tools are that accurate
reply
exe34 5 hours ago
You could have saved milliseconds and used a pseudo random number generator.
reply
exe34 6 hours ago
It reads like autism to me. The theme confirms that.
reply
cnqso 6 hours ago
[flagged]
reply
andrepd 2 hours ago
Instantly reminded me of this: source code of the first big Portuguese www portal and search engine: https://github.com/celso/sapo
reply
rfgplk 4 hours ago
Decent, but a half measure. Meaning you still depend on a separate web server (httpd in this case) to actually push your sites over the wire. This limits you in terms of how expressive your web application can be (ie you cannot arbitrarily write HTTP headers or choose how to serve your clients), and in terms of performance.

A far better (and harder approach) is to actually write the whole stack yourself. Meaning the actual web application and web server are packaged from a single binary. You of course have a myriad options in how to actually implement this (the server loop can run as a separate coroutine/thread/process/etc), but overall the performance and expressiveness flexibility is limitless. On top of that you can actually get blazing fast performance compared to classical approaches.

I'd also advise everyone to avoid CGI at all costs. It's overhead is massive (new process every time, more or less) and _itself_ is a half measure since implementing a proper code hot loading/module system for servers is too much of a hassle (and standardizing it is hard). Nowadays you want to inline your server and then handle HTTP generation separately (however you'd like).

reply
sophacles 4 hours ago
CGI does allow arbitrary HTTP headers.
reply
so-cal-schemer 3 hours ago
Who needs rust or javascript anymore when we can write all our code in C again and put an agentic zero-day hunter in the toolchain?

"Make no mistakes."

Or a comfy scripting language with a great FFI as X intended.

reply
paularmstrong 7 hours ago
> Everything about marketyour.games is modern

I can't read any of the text on that page other than the headings. Is that what makes it modern? I assume the stack mentioned in the blog post is vibe-slop as well.

reply
prophittcorey 6 hours ago
I wanted to try my hands at a monochromatic website and chose two shades that were far enough apart to pass a AAA contrast rating for accessibility. I'll try to improve it soon.

It was 100% human slopped :)

reply
mrweasel 6 hours ago
My eyes aren't particularly bad, not at the point where I need glasses to read books, program or anything, but I'm at 160-170% zoom before it's comfortable to read. HN is the same... so it might just be me.
reply
blodorn 60 minutes ago
The BCHS stack is OpenBSD, C, OpenBSD's httpd, and SQLite.

Is that the stack you are referring to, or something else?

reply
devmor 6 hours ago
I still like writing web applications in PHP for many of the same reasons listed here - modern PHP anyways.

I shy away from frameworks unless I am building something that I expect a large team to work on, or I specifically need multiple complex features that don't make sense to maintain.

I've written a few applications for my own personal use or targeted at friends/family recently that have no third party dependencies other than Bootstrap, which I still like more than tailwind for anything that doesn't need to look like a marketing page.

reply
UltraSane 4 hours ago
Connecting any C code to the internet is a terrible idea as we have learned over and over again.
reply
assimpleaspossi 3 hours ago
Your server, operating system and database might all be written in C right now.
reply
BirAdam 3 hours ago
It's essentially a guarantee.

Linux is C.

Windows is C and C++.

macOS is C, ObjC, and C++.

reply
UltraSane 3 hours ago
And great effort had to be made to fix all the thousands of severe security bugs.
reply
assimpleaspossi 3 hours ago
As if no large software system ever had such a problem and doesn't still today.
reply
t00 5 hours ago
"Every request spawns a fresh process" <- this is when I stopped reading to save some time for the latest news in AI. Apologies for an abrupt interrupt.
reply
EGreg 6 hours ago
"Every request spawns a fresh process. Deploying a new version is replacing one file. That means no server restart and no downtime. New requests simply pick up the new binary."

I think that's why FastCGI exists. It is the equivalent of PHP's "Swoole" or "FrankenPHP" or "amphp" or Laravel's "octane", etc. Each process is long-lived and tries to clean up its state as much as possible between requests. Forking a new process can take around 8ms (https://news.ycombinator.com/item?id=19005586)

When I was building https://github.com/Qbix/webserver in PHP, I was faced with forking a new process per request. I implemented fork-per-request at first, similar to PHP-FPM and then implemented the "FastCGI" approach of long-lived processes that clean up after each request. (Modern PHP has introspection so the engine can know what to clean up, before calling the php files to handle things.) However, some things are not really possible to completely reset in PHP, and you have to be careful with database connection pools, etc. Typically those are left open even by preforking processes like php-fpm.

Anyway, I ended up flipping it: use the "FastCGI" approach as a default, and if the original PHP code doesn't work (rare), then for that app, you can choose the regular CGI approach of forking a process per request. That way you get maximum speed by default, and manually opt into safety (this is an exception to my usual priorities).

PHP is actually quite fast. But I was also interested in transpiling it to C. So I built the transpiler at: https://ulanguage.org/playground ... used Claude to transform about 1000 PHP functions to their native equivalents, but if you use any of the others, it would hook into the Zend runtime and link with it. (There are some nuances with zvals and objects, and resources in previous PHP versions, but I managed to overcome them.) By the way, it also works with Node and Python FFI the same way.

You can basically now take PHP, Python or Javascript/Typescript code, and speed up the CPU-bound parts about 10-50x. A lot of that is because of string and JSON handling. Many web apps use strings and JSON a lot. So underneath, I had the compiler use "ropes" for the strings, and avoid concatenation. It also parallelizes the JSON encode and decode into code that can run on multiple cores at once, i.e. large JSON payloads are encoded and decoded in parallel. Those are just huge speedups.

Anyway... all of this is mostly focused on speed optimization, so you can solve the literally C100K problem (forget C10K) today, on a regular box. If you don't need speed or FastCGI, your approach is fast enough for the vast majority of applications.

PS: By the way, if you fork after your program already loaded the framework and initialized the configuration, then you can run a lot more workers, literally 10x-100x more of them, because Linux and Mac will share all the loaded memory between processes, and do Copy-On-Write only on dirty pages. And when your request is done, and the process exits, that custom memory is efficiently cleaned up by the OS. It is this feature that allowed me to finally get the best of both worlds... run all existing PHP code, that makes blocking I/O requests all over the place to the database, filesystem, network etc. while at the same time being able to handle 100,000 requests in flight at the same time! Swoole and FrankenPHP can't do that.

reply
tancop 5 hours ago
FastCGI sounds like a perfect fit for Tiger Style and Zig. You can avoid allocations completely if you set up a fixed size arena and reset it after each request.
reply
iririririr 6 hours ago
what are the code paths in php you're dropping for the actual speed improvement? just the parsing?

if not, you could have sent patches and have the best of both worlds

reply
EGreg 5 hours ago
Patches? Explain

My goal for speed was to run all existing unmodified PHP code out there, but handle 10x as many requests and throughput

Well, and also a ton of other features too

reply
LoganDark 3 hours ago
> marketyour.games

Visited this website out of curiosity, and... Please do not use Courier New as a monospace font, not even as part of a fallback. Its stem width for body text is often less than a pixel, which looks awful.

reply
frou_dh 60 minutes ago
Just the other day I thought it looked like the friggin official Python homepage is using Courier for the code example
reply
marcelox86 6 hours ago
Another interesting looking blog post that I can't bear to read without my eyes bleeding :(
reply
nocman 5 hours ago
Interesting. It looks fine to me. What's the part that bothers your eyes? (genuinely curious).
reply
smhenderson 5 hours ago
It supports reader view just fine...
reply
marcelox86 5 hours ago
I'm talking about all the claude-isms in the writing. i've seen a couple posts on linkedin that read just like this page
reply