Rendered at 14:55:56 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
DannyBee 2 hours ago [-]
I wrote "CGI Programming Unleashed" when I was 16, a scant 31 years ago (it was published in 1996, but not written in 1996). So this sort of brings me back. Almost as much as watching people review the book 20 years later and be like "it seems dated".
I think the conclusion that CGI made sense to die then but not now is probably correct, but for a different reason.
The main reason CGI died in large part is because it wasn't fast enough. Not the only reason for sure, but this is the general consensus. Spawning cgi children was slow, etc. Solutions were built to do in-process CGI, or separate CGI daemons. This even happened per-language with in-process CGI support for Perl, etc.
In the end, as people wanted more speed, they moved away from CGI to various other ways of doing things (client side, etc).
This aspect probably no longer makes sense - i'd be shocked if you couldn't make CGI "fast enough" these days without anywhere near as many hoops. To the degree hoops are necessary, they are probably saner to implement.
That doesn't mean folks should move back to CGI of course - but as i said, it is probably accurate that the main reason it died probably does not hold up anymore.
pjmlp 1 hours ago [-]
In a way we kind of moved back to CGI, it just happens we call it serveless nowadays. :)
wannabe44 48 minutes ago [-]
If I don't invoke the serverless for a whole day, I don't have to pay for it.
Irony is that it's most useful for hobby projects. In production I'd not use it.
peter_retief 5 minutes ago [-]
I never understood why we abandoned cgi apps rather than fixing them.
Not sure why but it probably had something to do with Microsoft and the browser wars.
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).
rpdillon 21 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.
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 ..
rpdillon 20 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!
MomsAVoxell 20 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 ..
Bluestein 11 hours ago [-]
> limited-resource systems (512 megs of RAM) ..
I am offended on behalf of all for whom that is more RAM than their first computer had :)
BobbyTables2 10 hours ago [-]
Having a computer with 256MB of RAM was once my dream …
Seemed like a lot when I only had 2MB…
Bluestein 6 hours ago [-]
What was that Gates quote again? (No. Not the one from his latest, AI-oriented diatribe ...)
MomsAVoxell 8 hours ago [-]
Yes, I know. I learned to program on a system with 64k, which was only fully available if one used assembly.
512 megs is not a lot for an embedded Linux project these days, but it can do a lot. Especially if you use Lua. ;)
mathnode 7 hours ago [-]
This is the first I am hearing about turbo lua, very cool! I was aware of openresty but I still resorted to flask for quick endpoints or concepts. This changes things for me.
JSR_FDED 9 hours ago [-]
Fantastic, thanks. I love Lua and especially the mindset that goes along with it. Will definitely check this out. Combining it with Datastar could be brilliant - I wonder if TurboLua supports SSE streaming.
MomsAVoxell 8 hours ago [-]
All the basics are there (chunked mode), I think you’d only need to do some thing things:
local SSEHandler = class("SSEHandler", turbo.web.RequestHandler)
function SSEHandler:get()
self:set_async(true)
self:set_header("Content-Type", "text/event-stream")
self:set_header("Cache-Control", "no-cache")
self:set_chunked_write()
-- first event
self:write("data: hello\n\n")
self:flush()
-- later events via IOLoop
local ioloop = turbo.ioloop.instance()
local count = 0
local timer
timer = ioloop:add_timeout(1000, function()
count = count + 1
self:write(string.format("data: tick %d\n\n", count))
self:flush()
if count < 10 then
timer = ioloop:add_timeout(1000, timer) -- reschedule
else
self:finish()
end
end)
end
fr2029 13 hours ago [-]
[dead]
OleksandrC 22 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).
I'm also working on an educational game project in C++ compiled to WebAssembly with Emscripten. Absolutely awesome to work with.
HugoDz 3 hours ago [-]
Very cool!
nmstoker 18 hours ago [-]
Nice. I know your comment was on the technical points, but it definitely under sells the game!
Transformanshen 17 hours ago [-]
That's cool
Teever 15 hours ago [-]
I'm doing something similar but with a Red Alert++ type of game with C and WebAssembly and Emscripten.
It's something I've been picking at in my free time but these posts from the last week regarding game decompiling old games and rebuilding the as web apps have inspired me to pick it up again. It's interesting to me how many people were critical of the performance of these games and that recent Sim City clone definitely had my laptop fans whirring but I find that my game doesn't have any of these performance issues. Performance-wise WebAssembly and Emscripten seem remarkable, and I haven't even added SIMD or multicore functionality yet.
One of the nice features about building it this way is that the desktop version can easily interface with 3d model / image generators which I intend to in the desktop unit-editor to generate assets for the game.
The pipeline that I'm envisioning is a 3d model generator that pushes the models into Blender to generate different perspective stills of them and then feed that to a stable diffusion image generator that paints them and a unit icons and such, and a voice model that generates their "ready to serve" peon type sounds when you click on them. I'm picturing a system that I can leave over night unattended to generate a bunch of units that I can look at in the morning to add to the game if I like them.
assimpleaspossi 19 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.
glouwbug 19 hours ago [-]
Feels so long ago the way you write about it, but 22 years ago was basically 2005
assimpleaspossi 19 hours ago [-]
It was February, 2004
benlivengood 20 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.
ncruces 18 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?
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
bheadmaster 5 hours ago [-]
FWIW, there's modernc.org/sqlite which already provides pure Go sqlite implementation.
Might be useful to test your own implementation against.
But for the point I was making, it is in fact not an alternative. In my version each SQLite connection is confined to a sandbox, and a C memory bug cannot corrupt the Go runtime, call stack or heap. In their version, a C pointer becomes an unsafe.Pointer that can address all Go memory.
HackerThemAll 6 hours ago [-]
> there's no way a C web server will be free of RCEs in today's world.
That's a bold claim not supported by facts. The following one had not had any RCE for 27 years, since its inception, and counting. I am certain there are more C web servers written securely.
I wonder if it would be more efficient to skip httpd and implement the HTTP server directly in the app. It would be consistent with the idea of using C with very few dependencies, give a lot of flexibility, and avoid the overhead of CGI.
Implementing an HTTP server from scratch in C is quite simple, clients are harder though, so I would keep using libcurl.
HTTPS can be tricky though, so you probably want to delegate this part to a reverse proxy.
hmry 3 hours ago [-]
I personally found implementing an HTTP2 server from scratch quite difficult. The parsing and state machine was okay (and is also the easiest part to get from an external library), but correctly handling stream priority / bandwidth sharing and backpressure was really hard. Of course one could go HTTP1.1-only, but then you're losing out on the efficiency gains anyway :/
Retr0id 3 hours ago [-]
> Implementing an HTTP server from scratch in C is quite simple
Implementing an HTTP server is easy, but implementing a fast, feature-complete and secure one is complex.
jacquesm 3 hours ago [-]
HTTP is easy, HTTPS much, much harder. Also, in HTTP there are plenty of footguns that can lead to security issues if you're not super careful. That goes for C in general but in particular doing this with un-sanitized input straight from the net into your application is not a path I would recommend.
cavoirom 3 hours ago [-]
httpd is really minimal, it event doesn't have compression built-in, skipping it don't bring much benefit. OpenBSD provided a cozy environment for system operator by default.
coolius 3 hours ago [-]
sounds like a security disaster just waiting to happen
GuB-42 3 hours ago [-]
Done well, not really. As I said, it is not that hard and not that big, a thousand lines of code maybe, maybe two or three if you support a few extensions. There are some footguns, but most of them related to reading the documentation of system calls carefully. And we are in the age of LLMs, and LLMs are very good at noticing edge cases you forgot, especially if you didn't vibe-code the thing in the fist place. That's in addition to traditional tools, such as sanitizers, linters, and fuzzers.
What you gain by rolling your own instead of using a battle tested solution is a reduced attack surface. For example, an off-the-shelf HTTP server may be tricked into revealing the content of a file the user should not have access to, but if your custom server doesn't read files at all (you don't even make a open()) because everything is in RAM, or hardcoded in the executable itself, then such a vulnerability cannot exist. You may also decide to allocate most of your memory statically, because you know in advance how much you will need, and doing that, eliminate an entire class of potential vulnerabilities. An off-the-shelf HTTP server doesn't have this luxury.
And with one less dependency, you are also less vulnerable to supply chain attacks.
Hendrikto 3 hours ago [-]
> I was hesitant to write the entire frontend in C, but it wasn't nearly as painful as I imagined.
> All too many times have I:
> * Fought vim to highlight Go's html/template syntax.
> * Fought helix to detect Go templates without breaking html detection.
> * Fought rustrover to recognize jinja templates for a project using askama.
> Using C means there's no second language for your editor to half-detect, no mixed-syntax where highlighting falls apart, no plugin dance to get the two languages to cooperate.
None of that has to do with C. You can apply the exact same approach in Go, or in any other language for that matter.
RandomMarius 1 hours ago [-]
I never thought it would come full circle, but here we are. I've helped develop and huge UI application in C/C++ using basically zero frameworks (Used ImGui) and is being used productively by many people and is stable. It runs on Mac, Windows, and Linux. But have also got it fully working on Wasm64. Anything less than WASM and it would have buckled under the load. It's beautiful on Web.
A few years ago one would have thought that it would not be worth the pain to develop it in C, now with AI that is no longer a concern as well, and we're so glad we did not compromise.
bagacrap 1 hours ago [-]
Does ai not footgun itself in C?
I only use it in C++ but I'm glad to have memory safe constructs and other modern primitives to keep it somewhat verifiable by me.
hughw 21 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.
jim_lawless 2 hours ago [-]
I was writing them in C in 1995. I published this article explaining how to write a C CGI program in DDJ that hit the newsstands in Fall of 1995.
As I discussed on the Zig thread a few days ago, some of us were actually using C, alone or mixed with scripting languages.
For example, it wasn't uncommon to have C extensions for Perl scripts dropped into CGI directory.
nkozyra 21 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.
minaguib 21 hours ago [-]
Perl's CGI.pm was updated as recently as 5 months 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.
icedchai 18 hours ago [-]
Same. My first "web app" was a Perl CGI that saved data to mSQL (not MySQL), probably early 1995.
wainstead 17 hours ago [-]
Same!
rjrjrjrj 20 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.
layer8 18 hours ago [-]
I still have such Perl scripts deployed, though using FastCGI.
fleeno 16 hours ago [-]
My first CGI programs around that time were in bash! I wrote so much useless but fun things back then.
Udo 6 hours ago [-]
I dropped Pascal programs in there, because it was the language I knew best, good times! It was really slow, too, because the bundled runtime had a massive startup time.
user0120397125 19 hours ago [-]
[dead]
Levitating 22 hours ago [-]
CGI is great. Sadly nginx doesn't support it natively as opposed to lighttpd.
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.
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.
huijzer 20 hours ago [-]
But the real question is, does Caddy support it?
The answer is: it does but via community plugins.
zelcon 13 hours ago [-]
You can write a ngninx module.
That would be the actual 2026 way to write C web apps.
Used to be a huge pain, but now AI can just read the nginx source and do it correctly.
makz 40 minutes ago [-]
I don't understand how are they writting html in C. Is it like they are doing puts("<html>");?
unixholder 17 hours ago [-]
The deeper you go into complex web technologies & frameworks, the more obvious it becomes that simplicity wins.
sthuck 8 hours ago [-]
yes, but when I think simplicity I don't think string handling in C
brainless 13 hours ago [-]
I remember CGI days and I have written tiny web "features" with Perl and C many years ago. All my product backends are now in Rust and SQLite but I use frameworks and libraries. Like Tokio, Auxum/Actix Web, Diesel.
I am not sure I like the idea that the binary will be called by nginx on each request. I prefer the backend binary to have state. A 256 MiB virtual instance is enough for any software shared between friends, family or even a small community.
SQLite backups are easy. I really like how I am building web apps these days. Been with PHP for 7 years and then Python for 10+ years. Single binaries are awesome. I am looking at multi-server backends as well, still 256 - 512 MiB per instance but with a shared Redis. Still with SQLite. Should easy enable medium sized business software.
cube00 8 hours ago [-]
> Process forking isn't nearly as expensive as it was; modern kernels optimize it heavily.
When I start to dig into how complex async is to debug I'm really starting to come back around to regular forking.
melasadra 9 hours ago [-]
I am very surprised at the lack of pushback.
Seems like most is just glazing the simplicity of C.
I know very little of web technology, just a faint memory from when I took Odin Project years ago.But surely there are hackers out there that can give us good justification why we currently need such a long list of stack?
Why do people use : TypeScript + React + Next.js + Tailwind CSS + shadcn/ui + PostgreSQL
I honestly dont know.
Are these still needed in 2026
Maybe in just some use cases such as high interactivity + needing to scale ?
bottlepalm 9 hours ago [-]
In 2026 the stack is SQLite + Rust + AI
As long as the tokens keep flowing we'll all be fine. If they stop flowing we're going to be boned with this mountain of low level software we're creating that will need to be maintained. Let's not think about that.
Gormo 3 hours ago [-]
Well, the only way the tokens will stop flowing is if your CPU and GPU stop working, at which point you have bigger problems than what languages your programs are in.
And unless you're writing in assembly or raw machine code, "low level" isn't quite the right terminology. There's nothing more inherently complex about maintaining code in Rust, Go, or even C than in TypeScript or JS.
lelanthran 2 hours ago [-]
They've never been needed, well, maybe postgresql is.
You can get quite far with boring enterprise stack.
prmoustache 3 hours ago [-]
> Are these still needed in 2026
Need has never been the correct word.
chr15m 9 hours ago [-]
Software developers love complexity. They love to construct huge beautiful towers of the stuff.
Given the option, I will always go to a Java or .NET framework.
Using anything other than that, the decision wasn't done by me, rather my employer or customer.
The only reason I would not expose C or C++ directly into the Internet, is as Gen X I have been there, and don't miss the possible security issues, which I also failed to match 100% even though we already used tools like Purify, BoundsChecker and Insure++.
kbrannigan 9 hours ago [-]
Model are trained on them in 2026 .
Me Raw php .
Many people here have machines that can handle all of AOL , yahoo, msn of 2001 combined in their closet .
I have been going backwards in time as an experiment . I use mature extremely documented tools . Has to be at least 20 years old
Quothling 9 hours ago [-]
You don't need all those things, and for the most part you likely never did. Today I think most of it is legacy. A member of one of my teams recently wrote a node template for azure function apps, and when I reviewed it I asked them why they were using 20 dependencies when they needed 3. There was a lot of reasons, but the main reason was "that's what we've always done". One of these prevented updating to typescript 7 which is why I was reviewing it to begin with. A day later they're down to 4 dependencies that are actually being used for something useful.
SPA's and their frameworks still have their use cases. I don't think you can really get full "simplicity" when you have a lot of people working on the same code that goes into enterprise production. I do think that a lot of the more complicated stacks mainly exist because "that's how we've always done it". Which is frankly also a fair consideration if you're not in a position where changing it would generate a lot of value.
I find that it always comes down to people. The fewer people you are, the easier it is to make rapid changes. With a lot of people, and maybe people with very different backgrounds and skill-sets things changes. Change management isn't easy, and often the actual tech stack will matter a lot less than building a good team around it. You obviously still want to work toward changes and approvements, but switching a 100 people from their safe and overly complicated tech stack to something else will take a while. You'll also have to be damn sure it's worth it.
locallost 4 hours ago [-]
I would argue the need to scale, but not the tech. Instead it was scaling the people. Around 15-20 years ago you had a much clearer separation of tasks, e.g. back and frontend work. So you could have people that just wrote HTML and CSS with a bit of JavaScript. To be fair, doing that was a lot more difficult back then than today, regardless of AI. A lot of this has gone away as "full stack" became more and more of a thing.
I think the author of the article has the right idea, although they do not use AI. But I think with AI now, people are anyway stepping out of what they would normally dare do, and so one person can accomplish more than before. So it makes sense to simplify again, although again I think for most people this will mean use AI.
Panzerschrek 22 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?
citrin_ru 22 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).
prophittcorey 22 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.
tomjen3 18 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.
warkdarrior 22 hours ago [-]
Users who send concurrent requests will be summarily banned and their data deleted. It's the only way to be sure.
huijzer 20 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
> 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.
sophacles 19 hours ago [-]
The main idea of a database is to support storing data in a structured and queryable way. Concurrency came later.
bijowo1676 21 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
zelcon 12 hours ago [-]
That’s ironic because 99% of PHP code today is served using PHP-FPM which is essentially a FastCGI wrapper around PHP.
ok123456 21 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.
doublepg23 20 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.
noduerme 3 hours ago [-]
I reallllly appreciated the coder's explanation of the C executable.
But the website itself is awful. I mean, it's impossible on desktop or mobile to tell what buttons are active or disabled. There is basically no UI at all to tell you what you're dealing with or what you get if you unlock it by signing up.
And I'd say I appreciate the raw simplicity of the dark mode interface, except it also looks like it's LLM-generated, even if it's not.
So, I'm not sure what the gains were here, really. I like the hand-written approach, but wish it had some sort of personality. And not to be a debbie downer, but the purpose of this site is also to entice some long tail of small game developers to pay to feature their games with influencers on youtube, twitch, etc. which, as a business model, fine, parasitic but fine, but maybe the most depressing thing I've seen all year even in the middle of the death of most of the industry. On top of that, you're making people pay to sell dead games to dead-eyed streamers on a site that looks like a fucking mortuary. At a glance, there are even more influencers dying to get paid on this site than there are shitty AI slop games going out now; and I don't even know who's playing them; so zayt gezunt to everyone involved.
The best thing about this is that it was written in C, without AI. Ostensibly. Everything else about it makes me want to shoot myself.
My art director critique: make some fucking bright pink rollovers on the buttons or something. At least. Add a stupid pink polar bear as a mascot. Don't make me feel like I'm selling my soul to satan by signing up for it.
edit I'm still confused by which assets were compiled into the C .exe. Are there assets?
mc007 20 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
anilakar 5 hours ago [-]
> no supply chain trouble
In other words, you are the supply chain. You're responsible for the bugs you create, but at least they are your bugs not caused by upstream's upstream's upstream's maintainer installing an infected JS library.
Shall we call this "vertically-integrated programming" then? :-)
codazoda 17 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.
rietta 17 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.
criddell 16 hours ago [-]
Microsoft added CMake support to Visual Studio in 2017.
jjuel 19 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.
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
Shorel 6 hours ago [-]
There's already vibe.d. A web framework for D lang.
Blazingly fast. The fastest webpages I have ever seen are the D lang forums.
And it has the right name!
Better and safer than C. Much nicer for the programmer than Rust.
nostrademons 18 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?
hollowonepl 8 hours ago [-]
Rust comes with dependency hell comparable to NodeJs, and sorting out memory issues is experience not platform choice. Simplicity of C versus complexity of Rust plus Rust being a new “java” religion to solve C++ ain’t convincing to everybody. We had this religion already. Every new generation comes with an idea to fix C/C++ while some still prefer to stay disciplined in the first one and let it fix itself.
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.
hollowonepl 8 hours ago [-]
There is… standard library and posix standard or other system level libraries, once you learn them you discover you don’t need to auto download a library to convert string to bool that relies on 5 other stupid libraries to work all together.
Lean yet complete standard library is what should be preferred instead of that supply chain, especially in AI era that makes half of them obsolete and redundant.
skydhash 3 hours ago [-]
And a lot of C/C++ library are incredibly mature, so no need to update your code every 3 months just for dependency updates.
uecker 9 hours ago [-]
"Cargo won't review them for vulnerabilities though, you'll still have to do that yourself."
Cargo is a danger to society. People need to stop using these unsafe and dangerous technology.
1718627440 16 hours 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.
Ygg2 16 hours ago [-]
C (and C++) has a supply chain. It's called unpaid Linux maintainers.
throwaway2037 8 hours ago [-]
> unpaid Linux maintainers
In 2026, I would say most are paid, certainly all of the really important leads. They are employed directly by Linux Foundation, or by a tech giant, like Google, Meta, Amazon, IBM, etc.
Ygg2 8 hours ago [-]
Not Linux as in kernel. Linux as in distro. I doubt most of Arch, NixOS, GoboLinux, Slackware maintainers are on FAANG payroll.
prmoustache 3 hours ago [-]
RHEL/Fedora SUSE/OpenSuse, ubuntu then?
throwaway2037 3 hours ago [-]
That is what I was thinking.
nostrademons 16 hours ago [-]
Don't use packages you didn't vibecode and audit yourself then. That's the situation C puts you in anyway.
joshheitzman 16 hours ago [-]
The Rust ecosystem isn't structured for the high friction dependency model the C has. Its structured around nearly frictionless dependencies so its no surprise that dependency trees are very large and frequently changing.
The typical C project has far fewer dependencies than the typical Rust project. Those dependencies are usually individually larger and either maintained by OS maintainers or there is a copy of the code that is built for the project and is readily available for audit. Those copies can't change without direct action.
Its less trouble to setup static analysis, address sanitizer, and similar tools for a C project than it would be to manage local copies of thousands of dependencies for a Rust project.
nostrademons 15 hours ago [-]
There's nothing stopping you from ignoring the ecosystem and just using Rust with the stdlib. Remember that the context for this thread is AI-generated code. If the AI is writing it all, the code is effectively free, you can write tens of thousands of lines of it with a single prompt, you can customize it all to your specific use-case, and you can throw it away and have the AI write it again instead of maintaining it. Also as manual programmers we're accustomed to programming being a team sport where you fit in gracefully into the ecosystem and build things with the maintainer and rest of the team in mind, but in the AI world, you can ignore the ecosystem, there is no maintainer (because you throw it away and have the AI write something else when the requirements change), and the rest of the team has all been laid off.
There's a bunch of threads going on simultaneously on HN now about how people often misuse AI by applying rules of thumb learned from doing things as a professional to what they prompt the AI to do, rather than just asking it directly for what you want. This is one of those cases. Many of the rules of thumb of professional programming no longer hold under the radically different economics of AI-driven development.
joshheitzman 14 hours ago [-]
> If the AI is writing it all, the code is effectively free
Its not even close to free in either $, your own personal time, or calendar time.
uecker 9 hours ago [-]
My assumption is that people are productive in Rust mainly because of the ecosystem, just like Python programmers are because they can download so many ready-to-use parts. The great mashup languages.
steveklabnik 12 hours ago [-]
> Its less trouble to setup static analysis, address sanitizer, and similar tools for a C project than it would be to manage local copies of thousands of dependencies for a Rust project.
It is trivial with Rust to set up asan and friends. You just
This works for your dependencies too. This isn’t C, you don’t need to manage all of those builds individually. That’s what the build system is for.
17 hours ago [-]
cozzyd 17 hours ago [-]
supply chain, compile times, binary size
nostrademons 16 hours ago [-]
Not huge problems for a web app, where you are controlling deployment yourself.
Retr0id 3 hours ago [-]
I don't think "computers are faster now" (and the unspoken "LLMs write my code for me now") is a great reason to be using an inefficient design.
PaulRobinson 2 hours ago [-]
What's inefficient about this approach?
I'd wager a CGI written in C uses less memory and CPU than an equivalent application in any other language or framework. I'd wager this design has lower latency meaning higher throughput and therefore higher capacity, too.
Or perhaps you mean developer efficiency? Well, with the right tools you're going to catch memory issues so they're gone. It's a tiny language you can keep in your head, so that's not an issue - I'd argue you need an LLM to write good C (if you know what you're doing), than to write good Java or Python.
I sure do love a modern language and environment (I spent years as a Rails dev, and I love me a bit of Elixir), but to argue that C is not efficient is kind of wild.
Retr0id 2 hours ago [-]
The inefficient part is execing a fresh process on every incoming request. The article alludes to FastCGI etc. as alternatives but they're still workarounds for a fundamentally inefficient architecture.
rjrodger 2 hours ago [-]
My first web app in 1995 was also built like this!
Except I had no idea malloc existed and the whole thing was static arrays...
fps-hero 2 hours ago [-]
That’s one way to avoid use after free bugs!
Most of my initial foray in programming was on microcontrollers, of which dynamic memory allocation came late.
Atmel ATMega didn’t support it at all. Rabbits supported allocation but not freeing, so, static memory with extra steps. It wasn’t until I was using cortex’s that the idea of using malloc was even entertained.
Even still today, I pretty much stuck with static global with reference passing or allocate everything at initialisation time. It’s a surprisingly robust strategy.
binaryturtle 9 hours ago [-]
Wouldn't it be even more ideal to have the webserver and app be one and the same binary, all bells and whistles included? No need for CGI at all. Just one static binary, no extra disk I/O needed to load resources (all compiled in statically). Basically you can make the OS deny this app any additional disk access for additional hardiness.
athrowaway3z 7 hours ago [-]
I've done what you described with Rust and 1 dependency. The reason to not do that is because TLS is a pain in the ass.
But more to your point, I think what makes this httpd scheme especially attractive (for C users especially) is that you can't try to "optimize" anything. There is no temptation to lock/mutex/cache yourself into more problems. Its 1 process that then dies. Even 'free' becomes optional in some cases.
Ono-Sendai 5 hours ago [-]
What was the problem with TLS you ran into?
creatonez 18 hours ago [-]
Is the CGI process opening up the SQLite database for every request...? That would have the most insane contention ever.
zbentley 18 hours ago [-]
Would it? The file handle doesn’t contend for a lock IIRC; just writes.
creatonez 18 hours ago [-]
I mean sure, you could still win if almost no requests are opening the database in write mode
zbentley 16 hours 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.
ihateolives 9 hours ago [-]
I think you severely underestimate the speed of sqlite + nvme.
zelcon 12 hours ago [-]
These things usually get 1 visitor per month and it’s Googlebot
sweetjuly 12 hours ago [-]
fortunately AI (scrapers) have solved this problem so now you'll have no end of traffic
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.
prophittcorey 22 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.
kanbankaren 20 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!
glouwbug 19 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
uecker 9 hours ago [-]
Indeed, my experience is that just sticking to C leads to better software. I found it relieving and not limiting.
ricardobeat 18 hours ago [-]
C3 lang gives you defer + a lot of significant ergonomic improvements right now: https://c3-lang.org
rurban 10 hours ago [-]
gcc also gives you defer nowadays, called cleanup
feelamee 17 hours 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.
ricardobeat 15 hours ago [-]
What do you mean by that?
n=1 but I've probably written (sic - a lot of AI) over a million lines of it this year. I like it precisely because it is nothing like C++, it's really just a better C, and the compiler / tooling is almost as good as Go.
bogdanoff_2 12 hours ago [-]
> fn int foo(){
Eh? What's the point of a `fn` keyword if I can't `grep -r "fn foo"`?
glouwbug 16 hours ago [-]
C3 is very good
prophittcorey 20 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.
kevin_thibedeau 20 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.
mpyne 13 hours ago [-]
So use the C standard library instead of the C++ one. You still get RAII / constructors/destructors and runtime polymorphism, along with stronger compile-time type safety.
I frequently do that myself on simple C++ programs just for compile time reasons alone, where I'll use stdio.h instead of std::iostream or std::format.
kevin_thibedeau 12 hours ago [-]
Designated initializers are gimped in C++;
lelanthran 11 hours ago [-]
> For any greenfield project, pick up C++ in lieu of C if you want a C language.
Depends on the metric.
1. If the metric is "How many features can I have", then, sure, C++ wins - it has everything.
2. If the metric is "how few footguns are there", then C++ loses by a mile - there's too many ways that the different features from #1 above can interact with each other to make it viable to keep track of all the footguns when writing code.
You may not value having fewer footguns and/or lower cognitive burden, but many do.
zelcon 12 hours ago [-]
For any greenfield project, pick up Rust instead of C++. Why? Ask any AI and it will pick Rust. Since AI is writing the code now and it likes Rust, because the pre-AI internet in its most trustworthy training dataset liked Rust. Therefore all code will eventually be Rust.
PaulDavisThe1st 20 hours ago [-]
It's what we did at amzn in 1994 ...
18 hours ago [-]
bigbuppo 18 hours ago [-]
Wasn't amazon running on tandem back then?
PaulDavisThe1st 18 hours ago [-]
In 1994, amzn ran on a single solaris workstation. Same at the beginning of 1995. I can't comment after that.
prmoustache 3 hours ago [-]
caveat: Amazon was just a simple online bookstore at the time. There was little relation to what amazon is now (no AWS for example) except it was already selling and shipping stuff and keeping an inventory like any other online store.
ricardobeat 18 hours ago [-]
There is a huge mental overhead penalty...
christoff12 21 hours ago [-]
Fair enough. But I am also curious if you'd like to share your rationale.
prmoustache 3 hours ago [-]
Probably because he knows it well and he rely on pledge and unveil capabilities of openbsd and it is well documented on how to use those in C.
You can do that in other languages but you need to use aditionnal dependencies (modules or bindings).
uecker 22 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.
christoff12 21 hours ago [-]
Yeah, I thought it was interesting that both of these[0] were on the front page.
I can never figure out why everything isn't in C. :|
ricardobeat 18 hours ago [-]
Is it because you segfault before reaching the answer?
uecker 9 hours ago [-]
From all the programs I use, the ones written in C are the most reliable (such as vim, bash, coreutils, terminals, X11¹, ... also larger software such as gimp, blender). Over decades I literally can't experience a single crash!
¹ The exception is the Nouveau driver, but without it X was also perfectly stable for me.
1718627440 16 hours ago [-]
A segfault IS the memory protection taking in effect.
Kevin_Flynn 6 hours ago [-]
[dead]
layer8 19 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.
EGreg 22 hours ago [-]
I'm old enough to remember when the OKCupid guys wrote their own webserver in C++!
"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.
prophittcorey 18 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.
zelcon 12 hours ago [-]
Both nginx and Apache have modules that keep a Python/PHP/Perl interpreter loaded and invoke your entry point using FastCGI, completely leaving HTTP handling to the real web server. They went out of style for some reason, but there’s nothing stopping you from using them.
fodkodrasz 9 hours ago [-]
Some reason: isolation and economies of scale. Apart from the obvious security aspects imagine the situation that you are serving multiple applications, developed by different teams, on different roadmaps... and you need to do a major version update of the runtime. This strong coupling of application lifecycles makes the overhead of isolation worth it.
macleginn 16 hours ago [-]
Yes, this makes sense. Although you will probably have to implement at least some of the middle layer's functionality, which means (at least for me) roughly the same level of debugging complexity when coming back to your own code later.
20 hours ago [-]
hollowonepl 21 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.
whizzter 18 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.
rurban 9 hours ago [-]
Why Apache in front? I wrote my own single page C++ multi-threaded http server for our embedded needs, accepting only a single route. Nothing simplier than that. Now I also know if a client is connected or not, how many, and process the backend task accordingly. Like streaming from a camera or not.
KolmogorovComp 8 hours ago [-]
Sadly it doesn’t look like the server is source-avalaible, so we could count the number of security issues included. There is a reason why C is not used for web servers today.
tzury 7 hours ago [-]
Nginx is written in c.
KolmogorovComp 7 hours ago [-]
Are you comparing their one-person project to nginx? Linux is written in C and out-of-bounds bugs are still found.
tzury 4 hours ago [-]
I commented on the statement “There is a reason why C is not used for web servers today”.
codazoda 22 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:
Ok but what about basic features like metrics/observability, logging/alerting?
Maybe not all projects benefit from the full package but some things are now so commoditized that you should have them everywhere (and for heavier project add readiness/liveness probes, configuration management, live documentation, connection pooling, background task scheduling, dev tools like profiling and tracing)
account42 4 hours ago [-]
The basic feature is serving a website. The things you mention are optional addons and almost always unneccessary for the primary purpose.
Udo 6 hours ago [-]
I think the approach here is to code these basic features by hand. What's preventing the author from building what they need on top of their basic stack?
Speaking as someone who hand-rolled their server stack as a C++ framework for years, there is nothing in there that can't be done relatively easily. Some things certainly get easier even, the actual change in paradigm here is not that it's a hand written web app server in C, it's that it runs in its own server container which you have to manage. That's the actual tradeoff. You can't just deploy to Vercel.
I'm not sure what you think specifically needs maintaining, it's the same as LAMP, LEAN, JAM and the various stack acronyms? The BSD you choose is naturally maintained by the various BSD distros (though there's an implicit assumption of OpenBSD as will become obvious), C is C (so defer to your C-complier), httpd comes from OpenBSD (https://man.openbsd.org/httpd.8), and SQLite is SQLite. You can naturally choose to add additional libraries (some are suggested on the site, I don't know what their status is, but the article includes libcurl and libsodium, which are also well maintained), but as the example shows, you don't need much to start with. A key thing that's a bit hidden is the use of CGI and the various OpenBSD hardening tools (e.g. pledge, unveil), which make exploiting the C binary much harder than on other systems.
lioeters 7 hours ago [-]
That's a fresh C codebase if it's only 5 years old.
lilbigdoot 21 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 :)
so-cal-schemer 16 hours ago [-]
All my BCHS are hustlers.
Give it a shot; I bet you'd like it a lot.
Aldipower 8 hours ago [-]
> CGI gives you a single web server that calls your business logic directly. It's clear who does what.
One could simply put a Node.js server directly on the line. And then it is crystal clear who calls the business logic. I mean, there are reasons why we use Nginx in front of it. Distribution, filtering, rate limiting, etc..
BTW, the cgi-bin competitor back in the days was JavaScript too with the Netscape Communication/Enterprise Server that supported server-side dynamic JavaScript in 1997! Funny enough. :-)
Surac 20 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
keyle 15 hours ago [-]
And the cycle is born again. Seeing the cost of a rust conversion today, there is an argument...
chasil 16 hours ago [-]
I have used ccgi.c when I needed access to system calls and PHP was too much of an attack surface.
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/
Scubabear68 22 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.
prophittcorey 22 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 :)
sam1r 21 hours ago [-]
I can empathize entirely. After writing a scraper for html in C, outputting html in C is a piece of cake.
PhilipRoman 22 hours ago [-]
Emitting strings is fine, it's the parsing that sucks.
uecker 9 hours ago [-]
Of course, you could spend half an hour to write a string abstraction first before writing the parser, and which case this is not a problem anymore.
Joker_vD 22 hours ago [-]
If you do it with the string functions from the standard library then yes, it is.
prophittcorey 22 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.
feelamee 17 hours 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.
jiggawatts 11 hours ago [-]
You can "have your cake and eat it too" in Rust, C#, and I suppose C++ if you're a masochist.
These modern languages have both easy-to-use "owning" string types and a "string slice" type that can be passed around efficiently. Unlike C, in these languages a string and a slice are largely interchangeable, which makes them easier to use throughout not just your own codebase, but third-party libraries too.
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.
6c696e7578 17 hours ago [-]
fcgi tends to be overlooked
zhangyimin 11 hours ago [-]
I love this kind of simplicity. It's unexpectedly satisfying.
emersonrsantos 21 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.
jaza 6 hours ago [-]
AFAIK Hacker News was built (about 2 decades ago) by Paul Graham completely in Lisp (I assume with CGI) and AFAIK that's still how it runs today.
throwaway2037 20 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?
bigbuppo 13 hours ago [-]
Best I can do is use a framework built on top of a framework.
23 hours ago [-]
geoffbp 21 hours ago [-]
I remember the days of wrangling cgi-bin on Linux hosts! Not a common paradigm these days..
devmor 22 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.
dorongrinstein 17 hours 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.
prophittcorey 16 hours ago [-]
Don't give me any more ideas!
Alifatisk 21 hours ago [-]
Reminds me of the Vibe.d web framework for D lang. Good memories.
NetOpWibby 7 hours ago [-]
> It was refreshing to just write C. It isn't pretty, but neither is Tailwind.
LMAO, I'm sold.
HackerThemAll 6 hours ago [-]
I like everything about it EXCEPT the Apache HTTP Server (if I understood the article correctly). It should be discouraged nowadays. Its lack of progress, lack of features, poor performance and lack of security makes me never consider it again.
To give you more context. I recently closed a security gap in a customer's web server that most likely resulted in a data leak. That web server stored (of course) database backups and other personal data. The directory listing was visible and accessible from the open internet, because - note that - the .htaccess file where the access was disabled had INVALID END OF LINE CHARACTERS according to Apache (and it wasn't me who prepared it in the first place). Therefore - note - the server IGNORED that file and its default setting was OPEN ACCESS and enabled directory index. It's wrong on so many fronts. The Apache's philosophy is not "I cannot parse the config file, therefore I disable access to the directory tree until administrator notices and fixes it". It was not logged in the server logs as "invalid EOL detected". Apache after over 30 years of development cannot parse all 3 end of line sequences - the process which is TRIVIAL to the point of being ridiculous. Deciding not to include CRLF or bare CR is not about performance. It's just the decision of its makers, there's no justification these days. It violates "be liberal in what you accept and conservative in what you send". In 2026, when the cybercriminals are everywhere, just waiting for the data, scraping it all over, the server's default should be "close everything until it's explicitly open" and "if the config is broken, disable access and/or fail".
6031769 4 hours ago [-]
You can criticise Apache for many things but lack of features is surely not one of them. It comes with the kitchen sink and has plenty of add-ons for all those extra cases you might want.
I'd also take issue with the "poor performance" slur. It's never going to beat out lighttpd for pure static speed but all the "poor" benchmarks I have see for it are entirely due to low quality (or no) configuration. Configure it properly and it flies.
theinfamousmobb 6 hours ago [-]
> I like everything about it EXCEPT the Apache HTTP Server (if I understood the article correctly).
You didn't.
chmaynard 20 hours ago [-]
Not open source, apparently. Am I missing something?
psychoslave 7 hours ago [-]
Hmm, ok for minimalism, but C is not going to minimize the pain and risk of ugly standard library and manual memory management for something that is not relevant to optimize at this level.
orphereus 18 hours ago [-]
Wow, you are a role model for me
kimi 6 hours ago [-]
Web apps work on input text and generate text, and C is not the most text-friendly language there is. There is a reason why early CGI-BINs were usually written in Perl.
(I won't even get started on the issues of creating new software in a language that is unsafe by design, and where any performance advantage will be dwarfed by the cost of forking. Whatever floats your boat, dude.)
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.
TZubiri 16 hours ago [-]
Fun fact, you don't need busybox or an httpd, just open a socket on port 80. You can use openssl for port 443 or use stunnel
andrepd 18 hours ago [-]
Instantly reminded me of this: source code of the first big Portuguese www portal and search engine: https://github.com/celso/sapo
paularmstrong 22 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.
prophittcorey 22 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 :)
mrweasel 21 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.
amval 5 hours ago [-]
This has to be the least readable website I've seen in a few years.
blodorn 17 hours ago [-]
The BCHS stack is OpenBSD, C, OpenBSD's httpd, and SQLite.
Is that the stack you are referring to, or something else?
UltraSane 20 hours ago [-]
Connecting any C code to the internet is a terrible idea as we have learned over and over again.
assimpleaspossi 19 hours ago [-]
Your server, operating system and database might all be written in C right now.
BirAdam 19 hours ago [-]
It's essentially a guarantee.
Linux is C.
Windows is C and C++.
macOS is C, ObjC, and C++.
kimi 3 hours ago [-]
And nobody in their right mind sleeps soundly at night.
UltraSane 19 hours ago [-]
And great effort had to be made to fix all the thousands of severe security bugs.
assimpleaspossi 18 hours ago [-]
As if no large software system ever had such a problem and doesn't still today.
UltraSane 10 hours ago [-]
When windows was first widely connected to the Internet security was so terrible Microsoft actually had to pause all work on the next version of windows to fix the current version.
rramadass 9 hours ago [-]
The main problem was not the language itself, but how the OS/Software was initially written and how it evolved gradually with layers of cruft added to maintain backwards compatibility as they went through 16/32/64-bit architectures and different kernels (eg. NT vs. Win95).
It was the complexity and legacy baggage that was the crux of the problem.
hliyan 13 hours ago [-]
Whatever it is that you're writing this comment on, runs on something that is written in C. Whatever that is responding to your posted comment on the server side, runs on something that is written in C.
BobbyTables2 10 hours ago [-]
And whatever they happen to be, they’ve had multiple serious CVEs because they were written in C…
UltraSane 8 hours ago [-]
And new stupid memory safety bugs are found in it constantly that are impossible in better languages.
t00 20 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.
sourcopolo 14 hours ago [-]
> One binary, a SQLite file, three dependencies and the entire thing fits in your head.
clearly AI slop
smstl 4 hours ago [-]
Bro invented php
gfalcao 18 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.
fg137 18 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.
chihuahua 17 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.
EGreg 22 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.
20 hours ago [-]
tancop 21 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.
iririririr 22 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
EGreg 20 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
rfgplk 20 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).
zelcon 12 hours ago [-]
There is a third option, which doesn’t involve making your small application responsible for reinventing the wheel.
Take whatever is pushing the site over the wire (nginx, Apache, lighthttpd) and use its public APIs to implement your web application.
You can make your nginx.conf list the routes along with the C functions for each route, which nginx looks up in your shared library.
You can host numerous web apps just by updating adding an .so and updating the nginx conf.
This is also structurally more efficient your hand rolled web server which in all likelihood has to reverse proxy via nginx anyway.
sophacles 19 hours ago [-]
CGI does allow arbitrary HTTP headers.
marcelox86 22 hours ago [-]
Another interesting looking blog post that I can't bear to read without my eyes bleeding :(
nocman 21 hours ago [-]
Interesting. It looks fine to me. What's the part that bothers your eyes? (genuinely curious).
smhenderson 21 hours ago [-]
It supports reader view just fine...
marcelox86 21 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
4 hours ago [-]
LoganDark 19 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.
frou_dh 17 hours ago [-]
Just the other day I thought it looked like the friggin official Python homepage is using Courier for the code example
LoganDark 16 hours ago [-]
Looks that way to me too, but I wouldn't look to Python for best practice.
21 hours ago [-]
caniload 13 hours ago [-]
[flagged]
22 hours ago [-]
DobarDabar 6 hours ago [-]
[dead]
afavour 22 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.
skrrtww 22 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.
jjackyzheng 16 minutes ago [-]
This structurally seems like AI writing to me..
You can write a modern web application in C. I shipped one. One binary, a SQLite file, three dependencies and the entire thing fits in your head.
xd1936 22 hours ago [-]
Interestingly, Pangram says that exactly the first 50% is AI and the second half is not. ¯\_(ツ)_/¯
I think the conclusion that CGI made sense to die then but not now is probably correct, but for a different reason.
The main reason CGI died in large part is because it wasn't fast enough. Not the only reason for sure, but this is the general consensus. Spawning cgi children was slow, etc. Solutions were built to do in-process CGI, or separate CGI daemons. This even happened per-language with in-process CGI support for Perl, etc.
In the end, as people wanted more speed, they moved away from CGI to various other ways of doing things (client side, etc).
This aspect probably no longer makes sense - i'd be shocked if you couldn't make CGI "fast enough" these days without anywhere near as many hoops. To the degree hoops are necessary, they are probably saner to implement.
That doesn't mean folks should move back to CGI of course - but as i said, it is probably accurate that the main reason it died probably does not hold up anymore.
Irony is that it's most useful for hobby projects. In production I'd not use it.
Not sure why but it probably had something to do with Microsoft and the browser wars.
Is it time to fix web development?
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:
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).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.
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 ..
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!
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 ..
I am offended on behalf of all for whom that is more RAM than their first computer had :)
Seemed like a lot when I only had 2MB…
512 megs is not a lot for an embedded Linux project these days, but it can do a lot. Especially if you use Lua. ;)
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/
It's something I've been picking at in my free time but these posts from the last week regarding game decompiling old games and rebuilding the as web apps have inspired me to pick it up again. It's interesting to me how many people were critical of the performance of these games and that recent Sim City clone definitely had my laptop fans whirring but I find that my game doesn't have any of these performance issues. Performance-wise WebAssembly and Emscripten seem remarkable, and I haven't even added SIMD or multicore functionality yet.
One of the nice features about building it this way is that the desktop version can easily interface with 3d model / image generators which I intend to in the desktop unit-editor to generate assets for the game.
The pipeline that I'm envisioning is a 3d model generator that pushes the models into Blender to generate different perspective stills of them and then feed that to a stable diffusion image generator that paints them and a unit icons and such, and a voice model that generates their "ready to serve" peon type sounds when you click on them. I'm picturing a system that I can leave over night unattended to generate a bunch of units that I can look at in the morning to add to the game if I like them.
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.
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.
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
Might be useful to test your own implementation against.
But for the point I was making, it is in fact not an alternative. In my version each SQLite connection is confined to a sandbox, and a C memory bug cannot corrupt the Go runtime, call stack or heap. In their version, a C pointer becomes an unsafe.Pointer that can address all Go memory.
That's a bold claim not supported by facts. The following one had not had any RCE for 27 years, since its inception, and counting. I am certain there are more C web servers written securely.
https://cr.yp.to/publicfile.html
Implementing an HTTP server from scratch in C is quite simple, clients are harder though, so I would keep using libcurl.
HTTPS can be tricky though, so you probably want to delegate this part to a reverse proxy.
Implementing an HTTP server is easy, but implementing a fast, feature-complete and secure one is complex.
What you gain by rolling your own instead of using a battle tested solution is a reduced attack surface. For example, an off-the-shelf HTTP server may be tricked into revealing the content of a file the user should not have access to, but if your custom server doesn't read files at all (you don't even make a open()) because everything is in RAM, or hardcoded in the executable itself, then such a vulnerability cannot exist. You may also decide to allocate most of your memory statically, because you know in advance how much you will need, and doing that, eliminate an entire class of potential vulnerabilities. An off-the-shelf HTTP server doesn't have this luxury.
And with one less dependency, you are also less vulnerable to supply chain attacks.
> All too many times have I:
> * Fought vim to highlight Go's html/template syntax.
> * Fought helix to detect Go templates without breaking html detection.
> * Fought rustrover to recognize jinja templates for a project using askama.
> Using C means there's no second language for your editor to half-detect, no mixed-syntax where highlighting falls apart, no plugin dance to get the two languages to cooperate.
None of that has to do with C. You can apply the exact same approach in Go, or in any other language for that matter.
A few years ago one would have thought that it would not be worth the pain to develop it in C, now with AI that is no longer a concern as well, and we're so glad we did not compromise.
I only use it in C++ but I'm glad to have memory safe constructs and other modern primitives to keep it somewhat verifiable by me.
https://jimlawless.net/articles/ddj95/index.html
For example, it wasn't uncommon to have C extensions for Perl scripts dropped into CGI directory.
IIRC the spec itself says it was built for C applications.
mod-perl was a godsend, of course.
https://metacpan.org/pod/CGI
But the very first CGI scripts I wrote were in C, late 95 or early 96. Apache on Slackware Linux.
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...
I have my own configuration template for nginx: https://git.levitati.ng/Levitating/nginx.conf
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.
The answer is: it does but via community plugins.
I am not sure I like the idea that the binary will be called by nginx on each request. I prefer the backend binary to have state. A 256 MiB virtual instance is enough for any software shared between friends, family or even a small community.
SQLite backups are easy. I really like how I am building web apps these days. Been with PHP for 7 years and then Python for 10+ years. Single binaries are awesome. I am looking at multi-server backends as well, still 256 - 512 MiB per instance but with a shared Redis. Still with SQLite. Should easy enable medium sized business software.
When I start to dig into how complex async is to debug I'm really starting to come back around to regular forking.
I know very little of web technology, just a faint memory from when I took Odin Project years ago.But surely there are hackers out there that can give us good justification why we currently need such a long list of stack?
Why do people use : TypeScript + React + Next.js + Tailwind CSS + shadcn/ui + PostgreSQL
I honestly dont know.
Are these still needed in 2026
Maybe in just some use cases such as high interactivity + needing to scale ?
As long as the tokens keep flowing we'll all be fine. If they stop flowing we're going to be boned with this mountain of low level software we're creating that will need to be maintained. Let's not think about that.
And unless you're writing in assembly or raw machine code, "low level" isn't quite the right terminology. There's nothing more inherently complex about maintaining code in Rust, Go, or even C than in TypeScript or JS.
You can get quite far with boring enterprise stack.
Need has never been the correct word.
Also it's the code version of this old phrase: ("I Had More Time, I Would Have Written a Shorter Letter") https://quoteinvestigator.com/2012/04/28/shorter-letter/
Given the option, I will always go to a Java or .NET framework.
Using anything other than that, the decision wasn't done by me, rather my employer or customer.
The only reason I would not expose C or C++ directly into the Internet, is as Gen X I have been there, and don't miss the possible security issues, which I also failed to match 100% even though we already used tools like Purify, BoundsChecker and Insure++.
Me Raw php .
Many people here have machines that can handle all of AOL , yahoo, msn of 2001 combined in their closet .
I have been going backwards in time as an experiment . I use mature extremely documented tools . Has to be at least 20 years old
SPA's and their frameworks still have their use cases. I don't think you can really get full "simplicity" when you have a lot of people working on the same code that goes into enterprise production. I do think that a lot of the more complicated stacks mainly exist because "that's how we've always done it". Which is frankly also a fair consideration if you're not in a position where changing it would generate a lot of value.
I find that it always comes down to people. The fewer people you are, the easier it is to make rapid changes. With a lot of people, and maybe people with very different backgrounds and skill-sets things changes. Change management isn't easy, and often the actual tech stack will matter a lot less than building a good team around it. You obviously still want to work toward changes and approvements, but switching a 100 people from their safe and overly complicated tech stack to something else will take a while. You'll also have to be damn sure it's worth it.
I think the author of the article has the right idea, although they do not use AI. But I think with AI now, people are anyway stepping out of what they would normally dare do, and so one person can accomplish more than before. So it makes sense to simplify again, although again I think for most people this will mean use AI.
> 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?
> 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.
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
But the website itself is awful. I mean, it's impossible on desktop or mobile to tell what buttons are active or disabled. There is basically no UI at all to tell you what you're dealing with or what you get if you unlock it by signing up.
And I'd say I appreciate the raw simplicity of the dark mode interface, except it also looks like it's LLM-generated, even if it's not.
So, I'm not sure what the gains were here, really. I like the hand-written approach, but wish it had some sort of personality. And not to be a debbie downer, but the purpose of this site is also to entice some long tail of small game developers to pay to feature their games with influencers on youtube, twitch, etc. which, as a business model, fine, parasitic but fine, but maybe the most depressing thing I've seen all year even in the middle of the death of most of the industry. On top of that, you're making people pay to sell dead games to dead-eyed streamers on a site that looks like a fucking mortuary. At a glance, there are even more influencers dying to get paid on this site than there are shitty AI slop games going out now; and I don't even know who's playing them; so zayt gezunt to everyone involved.
The best thing about this is that it was written in C, without AI. Ostensibly. Everything else about it makes me want to shoot myself.
My art director critique: make some fucking bright pink rollovers on the buttons or something. At least. Add a stupid pink polar bear as a mascot. Don't make me feel like I'm selling my soul to satan by signing up for it.
edit I'm still confused by which assets were compiled into the C .exe. Are there assets?
In other words, you are the supply chain. You're responsible for the bugs you create, but at least they are your bugs not caused by upstream's upstream's upstream's maintainer installing an infected JS library.
Shall we call this "vertically-integrated programming" then? :-)
Their example is:
It would be blazing fast, for use by AI itself
Just for fun
Better and safer than C. Much nicer for the programmer than Rust.
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?
Lean yet complete standard library is what should be preferred instead of that supply chain, especially in AI era that makes half of them obsolete and redundant.
Cargo is a danger to society. People need to stop using these unsafe and dangerous technology.
The typical C project has far fewer dependencies than the typical Rust project. Those dependencies are usually individually larger and either maintained by OS maintainers or there is a copy of the code that is built for the project and is readily available for audit. Those copies can't change without direct action.
Its less trouble to setup static analysis, address sanitizer, and similar tools for a C project than it would be to manage local copies of thousands of dependencies for a Rust project.
There's a bunch of threads going on simultaneously on HN now about how people often misuse AI by applying rules of thumb learned from doing things as a professional to what they prompt the AI to do, rather than just asking it directly for what you want. This is one of those cases. Many of the rules of thumb of professional programming no longer hold under the radically different economics of AI-driven development.
Its not even close to free in either $, your own personal time, or calendar time.
It is trivial with Rust to set up asan and friends. You just
And you’re off to the races.This works for your dependencies too. This isn’t C, you don’t need to manage all of those builds individually. That’s what the build system is for.
I'd wager a CGI written in C uses less memory and CPU than an equivalent application in any other language or framework. I'd wager this design has lower latency meaning higher throughput and therefore higher capacity, too.
Or perhaps you mean developer efficiency? Well, with the right tools you're going to catch memory issues so they're gone. It's a tiny language you can keep in your head, so that's not an issue - I'd argue you need an LLM to write good C (if you know what you're doing), than to write good Java or Python.
I sure do love a modern language and environment (I spent years as a Rails dev, and I love me a bit of Elixir), but to argue that C is not efficient is kind of wild.
Except I had no idea malloc existed and the whole thing was static arrays...
Most of my initial foray in programming was on microcontrollers, of which dynamic memory allocation came late.
Atmel ATMega didn’t support it at all. Rabbits supported allocation but not freeing, so, static memory with extra steps. It wasn’t until I was using cortex’s that the idea of using malloc was even entertained.
Even still today, I pretty much stuck with static global with reference passing or allocate everything at initialisation time. It’s a surprisingly robust strategy.
But more to your point, I think what makes this httpd scheme especially attractive (for C users especially) is that you can't try to "optimize" anything. There is no temptation to lock/mutex/cache yourself into more problems. Its 1 process that then dies. Even 'free' becomes optional in some cases.
If the latter, then it’ll only contend on simultaneous writes, which mutex anyway.
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!
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
n=1 but I've probably written (sic - a lot of AI) over a million lines of it this year. I like it precisely because it is nothing like C++, it's really just a better C, and the compiler / tooling is almost as good as Go.
Eh? What's the point of a `fn` keyword if I can't `grep -r "fn foo"`?
That may be a me problem.
Large portions of the standard lib depend on heap allocations. C is a much safer target for environments with limited resources.
I frequently do that myself on simple C++ programs just for compile time reasons alone, where I'll use stdio.h instead of std::iostream or std::format.
Depends on the metric.
1. If the metric is "How many features can I have", then, sure, C++ wins - it has everything.
2. If the metric is "how few footguns are there", then C++ loses by a mile - there's too many ways that the different features from #1 above can interact with each other to make it viable to keep track of all the footguns when writing code.
You may not value having fewer footguns and/or lower cognitive burden, but many do.
You can do that in other languages but you need to use aditionnal dependencies (modules or bindings).
[0] - the other one: https://news.ycombinator.com/item?id=50051573
¹ The exception is the Nouveau driver, but without it X was also perfectly stable for me.
I took the concept of "slots" in requests, from it: https://github.com/okws/okws
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.
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.
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.
https://github.com/codazoda/cgi-lib
Maybe not all projects benefit from the full package but some things are now so commoditized that you should have them everywhere (and for heavier project add readiness/liveness probes, configuration management, live documentation, connection pooling, background task scheduling, dev tools like profiling and tracing)
Speaking as someone who hand-rolled their server stack as a C++ framework for years, there is nothing in there that can't be done relatively easily. Some things certainly get easier even, the actual change in paradigm here is not that it's a hand written web app server in C, it's that it runs in its own server container which you have to manage. That's the actual tradeoff. You can't just deploy to Vercel.
The last update seems > 5 years ago.
https://github.com/kristapsdz/bchs
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 :)
Give it a shot; I bet you'd like it a lot.
One could simply put a Node.js server directly on the line. And then it is crystal clear who calls the business logic. I mean, there are reasons why we use Nginx in front of it. Distribution, filtering, rate limiting, etc..
BTW, the cgi-bin competitor back in the days was JavaScript too with the Netscape Communication/Enterprise Server that supported server-side dynamic JavaScript in 1997! Funny enough. :-)
https://github.com/moths/libccgi/blob/master/ccgi.c
Um, any and all string handling in C is pretty miserable.
These modern languages have both easy-to-use "owning" string types and a "string slice" type that can be passed around efficiently. Unlike C, in these languages a string and a slice are largely interchangeable, which makes them easier to use throughout not just your own codebase, but third-party libraries too.
For example, the Rust `httparse` crate `Request` type returns parsed fields as string slices, not strings, which means it doesn't allocate anything on the heap: https://docs.rs/httparse/latest/httparse/struct.Request.html
which also makes me wonder if it wouldn't have been more programmer-friendlier had it been written in Perl?
https://dhuan.github.io/mock/latest/examples.html
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.
LMAO, I'm sold.
To give you more context. I recently closed a security gap in a customer's web server that most likely resulted in a data leak. That web server stored (of course) database backups and other personal data. The directory listing was visible and accessible from the open internet, because - note that - the .htaccess file where the access was disabled had INVALID END OF LINE CHARACTERS according to Apache (and it wasn't me who prepared it in the first place). Therefore - note - the server IGNORED that file and its default setting was OPEN ACCESS and enabled directory index. It's wrong on so many fronts. The Apache's philosophy is not "I cannot parse the config file, therefore I disable access to the directory tree until administrator notices and fixes it". It was not logged in the server logs as "invalid EOL detected". Apache after over 30 years of development cannot parse all 3 end of line sequences - the process which is TRIVIAL to the point of being ridiculous. Deciding not to include CRLF or bare CR is not about performance. It's just the decision of its makers, there's no justification these days. It violates "be liberal in what you accept and conservative in what you send". In 2026, when the cybercriminals are everywhere, just waiting for the data, scraping it all over, the server's default should be "close everything until it's explicitly open" and "if the config is broken, disable access and/or fail".
I'd also take issue with the "poor performance" slur. It's never going to beat out lighttpd for pure static speed but all the "poor" benchmarks I have see for it are entirely due to low quality (or no) configuration. Configure it properly and it flies.
You didn't.
(I won't even get started on the issues of creating new software in a language that is unsafe by design, and where any performance advantage will be dwarfed by the cost of forking. Whatever floats your boat, dude.)
"Make no mistakes."
Or a comfy scripting language with a great FFI as X intended.
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.
It was 100% human slopped :)
Is that the stack you are referring to, or something else?
Linux is C.
Windows is C and C++.
macOS is C, ObjC, and C++.
It was the complexity and legacy baggage that was the crux of the problem.
clearly AI slop
I mean, the article should not be taken seriously on any technical level. It's ok just for fun.
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.
if not, you could have sent patches and have the best of both worlds
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
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).
Take whatever is pushing the site over the wire (nginx, Apache, lighthttpd) and use its public APIs to implement your web application.
You can make your nginx.conf list the routes along with the C functions for each route, which nginx looks up in your shared library.
You can host numerous web apps just by updating adding an .so and updating the nginx conf.
This is also structurally more efficient your hand rolled web server which in all likelihood has to reverse proxy via nginx anyway.
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.
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.
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.
You can write a modern web application in C. I shipped one. One binary, a SQLite file, three dependencies and the entire thing fits in your head.
> I'm a minimalist at heart. I use classic Vim with zero plugins. That means no LSP, no autocomplete, no code formatters, and no AI.
yet the author gives us an AI-written blog post :p