Pangram verdict · v3.3
We believe that this document is fully AI-generated
AI likelihood · overall
AIArticle text · 1,591 words · 6 segments analyzed
⚡ Qbix Server A pure PHP web server. No nginx, no Apache, no php-fpm. One process serves static files, PHP scripts, WebSocket connections, and a live dashboard. 🔟✖ 10x more concurrent PHP on the same hardware The biggest bottleneck in PHP hosting is memory. Each php-fpm worker loads your entire framework independently — 30–60MB per worker. On an 8GB server, that's ~160 workers max. That's your ceiling for concurrent PHP requests. Qbix Server forks workers after loading your classes. Thanks to copy-on-write, all that shared code (framework, config, autoloader) uses memory only once. Each worker adds only ~5MB for its per-request data: php-fpm: 8GB ÷ 50MB per worker = 160 concurrent PHP requests Qbix Server: 8GB ÷ 5MB per worker = 1,600 concurrent PHP requests Same hardware. Same PHP code. 10x more users served. Why it's faster than nginx + php-fpm for real apps nginx + php-fpm Qbix Server 🚀 PHP request speed 10–50ms bootstrap on every request 0ms — workers fork after classes are loaded 💾 Memory per worker 30–60MB each (duplicated) ~5MB each (shared base via copy-on-write) 👥 Concurrent PHP (8GB) ~160 workers ~1,600 workers 🔒 Access-controlled files Public URLs or hacky rewrites X-Accel-Redirect — PHP checks access, server streams the file 🧩 Cache invalidation Whole-page only (purge everything) X-Cache-Tree — invalidate one component, keep the rest cached 🌐 WebSocket Needs a separate server Built in ⚙ Setup Install nginx, configure proxy_pass, php-fpm pool, sockets... php qbixserver.php --port=8080 Static file throughput is 55–73% of nginx (C will always beat PHP on raw I/O). But on actual PHP workloads, the memory and bootstrap savings make this dramatically faster and more scalable.
💡 You can always put nginx, a reverse proxy, or a CDN (Cloudflare, CloudFront) in front of this for faster HTTPS and edge caching. Qbix Server handles the PHP execution, access control, and intelligent caching behind it. 📑 Table of Contents Quick Start Performance Why Not php-fpm? vs FrankenPHP and Swoole Features Server Headers For PHP Developers Configuration Three Ways to Run Building With Qbix Platform Architecture HTTP/2 Support Requirements License 🚀 Quick Start # Clone git clone https://github.com/Qbix/Server.git cd Server # Create a web directory mkdir web echo '<h1>Hello World</h1>' > web/index.html # Run php qbixserver.php --port=8080 Open http://localhost:8080. That's it. # Or serve an existing directory php qbixserver.php --root=/var/www/mysite --port=80 # Or use the PHAR (single file, 196KB) php bin/qbixserver.phar --root=./public --port=8080 📊 Performance Benchmarked against nginx on the same single-core container, PHP 8.3, Ubuntu 24. 13KB static file, best-of-3 runs, warm caches. Scenario nginx Qbix Server Ratio Sequential (c=1) 10,154 req/s 6,376 req/s 63% Concurrent (c=10) 12,300 req/s 6,876 req/s 56% High concurrency (c=50) 12,919 req/s 7,253 req/s 56% Keep-alive (c=10) 26,858 req/s 19,700 req/s 73% Keep-alive (c=50) 30,158 req/s 20,369 req/s 67% Zero failed requests across 50,000+ requests at concurrency 50. Server never crashed. For context: 20K req/s means the server handles 1,000 simultaneous page loads per second (assuming ~20 static assets per page), all from a single PHP process.
🏎 Why Not php-fpm? The traditional stack — nginx + php-fpm — works like this: Request → nginx → FastCGI socket → php-fpm worker ↓ Load PHP Include autoloader Boot framework Connect to DB Run your code Send response ↓ Worker resets or dies Every PHP request pays the bootstrap cost. Even with OPcache, each php-fpm worker re-initializes your framework's class instances, config trees, and DB connections on every request. For a framework like Qbix (or Laravel, Symfony, etc.), this bootstrap takes 10–50ms — often longer than the actual work. Qbix Server eliminates this entirely: Startup: 1. Load PHP 2. Include autoloader 3. Load ALL framework classes into memory 4. Parse ALL config files 5. Connect to database 6. pcntl_fork() → workers inherit everything ↓ Request: Worker already has classes, config, DB connections. Just run your code. 0ms bootstrap. The key insight is fork after preload. Unix fork() uses copy-on-write, so forked workers share the parent's memory pages for all those preloaded classes. Each worker starts with ~30MB shared (read-only) and allocates only the per-request data. Compare this to php-fpm where each worker loads everything independently, using 30MB × N workers of duplicated memory. Preloading classes Use the --workers=N flag and configure which classes to preload: { "Q": { "webserver": { "preload": [ "Q_Dispatcher", "Q_Request", "Q_Response", "Q_Config", "Q_Cache", "Q_Session", "Db", "Db_Mysql", "Db_Row", "Db_Query", "Users", "Users_User", "Users_Session", "Streams", "Streams_Stream", "Streams_Message" ] } } } # Start with 4 workers (classes loaded once, shared across all) php qbixserver.php --app=/path/to/myapp --port=8080 --workers=4 The parent process loads and parses every class in the preload list, then forks. Workers inherit the entire loaded state — OPcache entries, class definitions, parsed config trees, autoloader maps.
The first PHP request in each worker runs at full speed, no cold start. The numbers php-fpm Qbix Server Bootstrap per request 10–50ms 0ms Memory per worker 30–60MB each 30MB shared + ~5MB per worker IPC overhead FastCGI socket + serialization Direct function call or Unix fork Static files Separate nginx process Same process, memory-cached, single fwrite Config reload Restart all workers SIGHUP, zero downtime WebSocket Needs separate server Built in For a Qbix app with 20 loaded plugins, the bootstrap savings alone make the server 2–5x faster on PHP requests compared to nginx + php-fpm. Why it's actually faster in practice The benchmarks above measure static file throughput, where nginx's C implementation and sendfile() syscall give it an inherent edge. But for real PHP applications, the story flips: nginx + php-fpm: 0.1ms static file + 30ms PHP bootstrap + 5ms actual work = 35ms Qbix Server: 0.15ms static file + 0ms bootstrap + 5ms actual work = 5ms The 0.05ms you lose on static files, you gain back 30ms on every PHP request. And you can always put nginx or a CDN in front for the static file edge. ⚖ vs FrankenPHP and Swoole If you're looking beyond php-fpm, you've probably seen FrankenPHP and Swoole. Here's how they compare: FrankenPHP Swoole Qbix Server Language Go + C (embeds PHP) C extension for PHP Pure PHP Install Download Go binary or Docker pecl install swoole (compiles C) php qbixserver.php — nothing to install Architecture Worker mode (persistent) Coroutine-based (persistent) Shared-nothing with fork-after-preload State leaks ⚠ Possible — workers persist between requests ⚠ Possible — must manage globals carefully ✅ Impossible — each request gets a clean fork PHP compatibility Most code works, some edge cases Many extensions incompatible,
blocking I/O breaks coroutines ✅ 100% — standard PHP, nothing unusual Memory safety Go runtime + PHP = complex interaction C extension = segfault risk PHP only = memory-safe by default Access control No X-Accel-Redirect equivalent Manual implementation ✅ Built-in X-Accel-Redirect Component cache No No ✅ X-Cache-Tree — sub-page invalidation Early hints / 103 ✅ Yes No Via amphp HTTP/2 ✅ Built-in (Caddy) ✅ Built-in ✅ Via amphp WebSocket Via Mercure ✅ Built-in ✅ Built-in The shared-nothing advantage FrankenPHP and Swoole keep PHP workers alive across requests. This is fast, but it means global state, static variables, database connections, and in-memory caches persist between unrelated requests. This causes subtle bugs: // This leaks between requests in FrankenPHP/Swoole: class UserService { private static ?User $cached = null; public static function current(): User { if (!self::$cached) { self::$cached = User::fromSession(); } return self::$cached; // Returns previous user's data! } } Every PHP framework, library, and snippet that uses static variables, singletons, or global state becomes a potential security hole. You have to audit everything. Qbix Server avoids this entirely. Workers fork from a preloaded parent, so they inherit loaded classes and parsed config (read-only, shared via copy-on-write). But each request runs in its own process — when it's done, everything is gone. No state leaks. No audit needed. Your existing PHP code works exactly as it does on php-fpm. The "just PHP" advantage FrankenPHP requires Go tooling to build or a pre-built binary that bundles Caddy. Swoole requires compiling a C extension, which can conflict with other extensions and doesn't work on all hosting environments. Qbix Server is a PHP file. If you can run php -v, you can run the server. It uses standard PHP extensions (sockets, pcntl) that come pre-installed on most systems. There's no compilation step, no foreign runtime, no binary compatibility issues. #
FrankenPHP docker pull dunglas/frankenphp # 150MB+ image, or build from Go source # Swoole pecl install swoole # compiles C, may fail on some systems # Then edit php.ini, restart php... # Qbix Server php qbixserver.php --port=8080 # done When to choose what Choose FrankenPHP if you want Caddy's ecosystem (automatic HTTPS, HTTP/3) and don't mind Go as a dependency. Good for Laravel projects that already use Octane. Choose Swoole if you need coroutines for high-concurrency I/O (thousands of simultaneous HTTP client requests, database queries). Good for async-heavy microservices. Choose Qbix Server if you want shared-nothing safety, zero-install deployment, access-controlled file serving, component-level cache invalidation, and full compatibility with existing PHP code. Good for apps that serve pages (not just APIs), need fine-grained caching, and want the simplest possible deployment. ✨ Features Category What you get Static files ETag, 304 Not Modified, Last-Modified, MIME type detection, in-memory response cache Keep-alive HTTP/1.0 and 1.1, TCP_NODELAY, configurable limits HTTP/2 Via amphp — multiplexed streams, header compression, TLS (optional) PHP execution .php files in document root run in-process or via pre-fork worker pool Compression On-the-fly gzip/brotli + pre-compressed .gz/.br siblings WebSocket RFC 6455 upgrade on any path Dashboard Live stats at /Q/dashboard — request rates, memory, status codes Health check JSON at /Q/health — for load balancers and monitoring Control panel Password-protected at /Q/panel — manage