Qbix Server โ€” A Web Server in Pure PHP

Serve 100× more users
on one machine

Handle all your HTTP requests and WebSocket rooms securely by default, through OS-enforced process isolation. Based on PHP’s shared-nothing architecture, Qbix Server is able to run thousands of existing PHP websites★ without modification. It now runs on Linux, Mac, Windows, iOS and Android, and is able to generate standalone binaries that you can sign and distribute. And now, v2 makes it easy to make apps decentralized and continue working offline via WiFi and Bluetooth, too. 🤯

★ including WordPress, OwnCloud, Magento, Drupal, Joomla, and frameworks including Qbix, Laravel and Symfony.

git clone https://github.com/Qbix/webserver
cd webserver
php qbixserver.php
Or grab a self-contained binary (Linux, macOS, Windows)
curl -LO https://github.com/Qbix/webserver/releases/latest/download/qbixserver-macos-arm64
chmod +x qbixserver-macos-arm64
./qbixserver-macos-arm64
๐Ÿ›ก๏ธ PHP2Shell (CVE-2026-109618 & CVE-2026-109619) โ€” Qbix Server is immune. Running another server? Read this.

What happened: Two heap use-after-free bugs in PHP's C runtime โ€” PHP2Shell โ€” allow unauthenticated remote code execution on any server running PHP 8.0โ€“8.5 before the Oct 21 2026 patches. The bugs fire during multipart request parsing, before any application code runs. No WAF rule, no login check, no middleware can intercept them.

If you run Qbix Server: you are already protected, regardless of PHP version. Qbix Server runs PHP as CLI SAPI (not FPM), which never registers the vulnerable upload-progress callback. More importantly, Qbix Server parses multipart/form-data in the parent process and re-serializes a clean representation before any PHP worker sees the request โ€” the raw attacker bytes never reach PHP's built-in parser. Both CVE paths are structurally closed. Version 3.4.1 adds explicit ini_set hardening as an additional layer, but all prior versions are protected too.

If you're still running nginx + php-fpm and can't migrate right now, deploy Qbix Proxy in front of your stack. It applies the same re-serialization strategy โ€” parsing and re-emitting multipart bodies before they reach PHP โ€” without requiring any changes to your application. It also defends against future parser-class vulnerabilities in PHP's C runtime.

References: PHP2Shell advisory ยท Security Affairs ยท Phoenix Security analysis

View on GitHub See examples

Everything in one process

Replaces nginx + fpm + Node + Redis + supervisor + Docker.

โšก

14ร— Throughput

Persistent workers at 120KB each. 400 workers on 200MB. 1,060 req/s where fpm does 78.

Learn more โ†’
๐Ÿ”Œ

WebSocket + Rooms

Same port as HTTP. Rooms are forked processes with shared state. Socket.IO protocol. No Node.

Learn more โ†’
๐Ÿงฉ

Unmodified PHP

WordPress, Laravel, Symfony, Drupal. 27 functions rewritten as files load. Reads .htaccess. Just works.

Learn more โ†’
๐Ÿ”’

Microservice Isolation

Authority + sandbox with one config change. Same code, different roles. Secrets never leave the authority.

Learn more โ†’
๐ŸŒ

Cluster Replication

Multiple servers with SQLite. Events replicate. Kill a node, restart โ€” it catches up.

Learn more โ†’
๐Ÿ–ผ๏ธ

Image Processing

Resize with ?w=400. Serves AVIF or WebP from the Accept header. Save-Data support. Disk cache that regenerates when the original changes.

Learn more โ†’
๐Ÿ“‹

Smart Response Headers

X-Cache-Tree for per-component invalidation. X-Accel-Redirect for access-controlled files. ETag generation. Directory listing.

Learn more โ†’
๐Ÿ“ˆ

Auto-Generated API Docs

Write handler files, get OpenAPI 3.1 and MCP specs automatically. Swagger UI, Postman, Redoc โ€” and AI tools can call your appโ€™s API directly.

Learn more โ†’
๐Ÿ”

TLS, Cron & Logging

HTTPS auto-starts when certs exist. Built-in cron scheduler. Buffered access logs with daily rotation and gzip archiving.

Learn more โ†’

Plus six example apps included: chat, kanban, SSE stream, REST API, live counter and a distributed swarm. See examples →

New in v2.0

Apps that keep working offline

Every Qbix Server now has a cryptographic identity and can find other servers nearby over Bluetooth and Wi-Fi. Phones on the same bus, in the same hall, or in a place with no signal can exchange data directly, encrypted end to end, with no server in the middle.

// React to peers coming and going
Q_WebServer_Transport::onPeerOnline(function ($peer) {
    Q_WebServer_MeshSync::syncWithPeer('notes', $peer['peer_id'], $since,
        array('Q_WebServer_Transport', 'requestFromPeer'));
});

No breaking changes from v1.x: the mesh layer does nothing until a peer is discovered. Release notes →

14×vs fpm (50ms I/O)
24×vs fpm (200ms I/O)
120KBper worker (COW)
0.03msstate reset
💡 Why it’s faster than everything else

The problem with php-fpm: Whether opcache is enabled or not, the vast majority of production PHP code is I/O-bound. Workers wait for the database, the filesystem, an API call. During that wait, the worker is doing nothing — but it’s holding 30–60MB of RAM. On a 4GB server, fpm gets maybe 80 workers. Each one blocks on a 200ms query. That’s the ceiling.

The problem with Swoole, RoadRunner, and FrankenPHP: They try to solve this by making PHP evented, like Node.js. But that means rewriting your code to use their async libraries. Every PDO::query(), every file_get_contents(), every curl_exec() in every WordPress plugin and Laravel package uses blocking I/O. It doesn’t yield. Swoole can’t help with code that doesn’t cooperate.

How Qbix solves it: Instead of making each worker do more, run more workers. The server loads your framework into a parent process, then calls pcntl_fork(). The kernel marks every page copy-on-write. Each worker shares the parent’s loaded classes and only pays for pages it writes to. A WordPress-like request dirties 30 pages = 120KB. The same 4GB that gives fpm 80 workers gives Qbix thousands.

Your code runs unmodified, in two modes:

Persistent workers (default) — workers stay alive across requests. 27 functions are rewritten as files load. Static properties restored from snapshot in 0.03ms. This is the fast path: 2,294 req/s on CPU-bound work.

Fork-per-request — for code the shim can’t track (functions with internal static variables, plugins that register untrackable global state). Each request gets a fresh fork. Slower than persistent mode, but each worker still costs only 120KB instead of 50MB — so you can run 100× more workers than fpm on the same hardware. That’s the whole point.

Even on Windows — where fork isn’t available, the server runs persistent workers with the same 27-function rewriting. You don’t get COW memory savings, but you get the same code compatibility and the same control panel.

We proposed this for PHP core as switch_global_context(). While that works its way through the RFC process, the server does it in userland today.

🔍 Benchmarks vs Swoole, FrankenPHP, and php-fpm

CPU-bound (WordPress-like workload, same 200MB):

Workersreq/svs fpm
php-fpm4~350—
Swoole4~4001.1×
Qbix1002,2946.6×

I/O-bound (50ms database query):

Workersreq/svs fpm
php-fpm478—
Swoole (coroutines*)4~300~4×
Qbix1001,06014×

I/O-bound (200ms — real database load):

Workersreq/svs fpm
php-fpm420—
Swoole (coroutines*)4~200–500~10–25×
Qbix20048824×

* Swoole coroutines require Runtime::enableCoroutine() and coroutine-aware drivers. Unmodified WordPress/Laravel uses blocking I/O and hits fpm’s ceiling.

🛡️ 27 functions rewritten — how state gets reset

Workers are persistent — they handle thousands of requests without restarting. Between each request, a Reflection-based snapshot restores all static properties in 0.03ms. 27 PHP functions are rewritten as each file is loaded, before PHP compiles it:

header(), setcookie(), session_start(), move_uploaded_file(), ini_set(), register_shutdown_function(), set_error_handler(), spl_autoload_register(), putenv(), and 18 others — all tracked per request and cleaned up between requests.

Unmodified WordPress, Laravel, Symfony, and Drupal get shared-nothing safety automatically. No adapters, no code auditing.

Full compatibility details → · What gets rewritten in each framework →

📊 How many users can one $30/month machine handle?
Metricphp-fpmQbix
Workers on 4GB~80 (50MB each)400 (120KB each)
Throughput (200ms I/O)~80 req/s~2,000 req/s
Concurrent active users1,60040,000
Registered accounts16K–32K400K–800K
WebSocketNeeds Node.js100K+ built in
DatabaseNeeds PostgresSQLite (50K writes/sec)
Monthly cost$30 + DB server$30 total

One machine. No database server, no Redis, no Node, no Docker. Add a second with DNS failover for redundancy — distributed mode keeps both SQLite copies in sync.

Fork after preload

Load everything once. Fork workers. Each costs 120KB, not 42MB.

Parent Process (30MB)framework · routes · cachesCOWCOWWorker (120KB)Worker (120KB)Worker (120KB)Worker (120KB)php-fpm: 4 × 42MB = 168MBQbix: 400 × 120KB = 47MBSame code. Same RAM. 100× more workers.

Live Dashboard

Built-in at /Q/dashboard. No Grafana, no Prometheus.

localhost:4000/Q/dashboard

Qbix Server Dashboard

2,847Req/min
142Connections
400Workers
23msLatency
99.8%Uptime
47MBMemory
200 GET /api/users 12ms
200 POST /api/tasks 34ms
304 GET /css/app.css 1ms
200 WS /Q/ws upgrade 2ms

Dashboard & control panel docs →

Get started

git clone https://github.com/Qbix/webserver
cd webserver
php qbixserver.php --root=examples/todo/web

View on GitHub → Download binary Examples

Runs everywhere

Download a binary for your platform. PHP is bundled inside — nothing to install.

Linuxx86_64 & ARM64 · COW fork
macOSApple Silicon & Intel · COW fork
Windowsx64 · persistent workers
iOS & Androidarm64 · mesh transports

On Linux and macOS, thousands of COW-forked workers at ~120KB each. On Windows, persistent workers with the same 27-function rewriting. On phones, the same server behind a native Bluetooth and Wi-Fi transport. FreeBSD builds from source.

Use with your existing codebase

If you already have a PHP app running on nginx + php-fpm, switching is one command.

cd my-laravel-app && php qbixserver.php --root=public --preset=laravel
cd my-wordpress-site && php qbixserver.php --root=. --preset=wordpress
cd my-symfony-app && php qbixserver.php --root=public --preset=symfony
cd my-drupal-site && php qbixserver.php --root=web --preset=drupal

Try persistent mode first — it handles most apps. If yours needs fork-per-request, that’s still 100× more workers than fpm on the same hardware. How your code gets rewritten →