Ten Thousand
I used nginx for a long time. I am with someone else now.
Long before NGINX Plus went commercial, before it even called itself 1.0. Apache was king then. You wrote VirtualHost blocks in httpd.conf, stacked rewrite rules in mod_rewrite, chose between prefork and worker for your MPM. That was normal. nginx was some unheard-of HTTP server out of Russia.
There was a period when the C10K problem was everywhere. How do you handle ten thousand concurrent connections. Apache's prefork model assigned one process per connection. Ten thousand connections meant ten thousand processes. Each process consumed tens of megabytes. You needed hundreds of gigabytes of RAM. Nobody had that kind of memory back then. Switching to worker still hit thread limits. A model that spawns one process per connection could not scale.
nginx was event-driven. A handful of worker processes used epoll to juggle massive numbers of connections. Not one process per connection. One process handling thousands. Memory efficiency improved by orders of magnitude. Configuration was simple too. Coming from the verbosity of Apache's httpd.conf, an nginx conf file felt almost suspiciously short.
nginx spread fast during the social-game era. Tens of thousands of players hitting gacha results simultaneously. Traffic spiking the instant an event went live. nginx absorbed loads Apache could not handle. Drop it in front as a reverse proxy and backend pressure dropped dramatically.
Load balancing, failure detection, caching. What we now call an L7 ALB and a CDN — back then a single nginx box covered both roles. You placed it in front and most problems went away.
Now nginx is unremarkable infrastructure. Cloudflare, AWS — behind the scenes they run nginx or architectures shaped by it. After the F5 acquisition the commercial push grew stronger, and freenginx forked off. A single personal project supports a significant share of all internet traffic.
The someone else is OpenResty. I wanted to push custom metrics to VictoriaMetrics. Latency distributions per endpoint. Presence or absence of specific headers. Skew in response sizes. Measurement logic that nginx conf could not express. stub_status shows connection counts. But to look inside each request, you have to step outside the conf.
OpenResty lets you touch the request with Lua. In log_by_lua you assemble metrics and push them to VictoriaMetrics. What the conf could not hold, a few dozen lines of Lua handles. It felt like nginx's design philosophy with one programmable layer added on top.
There was an era when ten thousand concurrent connections was the problem. That problem was solved, witnessed, and now no one speaks of it.