OxPHP
Asynchronous PHP application server written in Rust.
Replaces nginx + PHP‑FPM with a single binary.
Features
Native PHP via Custom SAPI
Executes PHP natively through a custom sapi_module_struct — no CGI, no FastCGI, no external process. Full ZTS thread safety with OPcache + JIT.
Multi-Threaded Worker Pool
Dedicated OS thread per PHP worker with ZTS isolation. Static (PHP_WORKERS=N) or dynamic (MIN:MAX) scaling with automatic dead worker respawning.
Modern HTTP Stack
Built on Hyper + Tokio for async I/O. HTTP/1.1 with keep-alive, Brotli compression, HTTP caching with ETag/304, native TLS via rustls, and configurable timeouts.
Built-in Observability
Prometheus metrics at /metrics, health checks at /health, structured JSON access logging, and auto-generated X-Request-ID headers.
Production Ready
Per-IP rate limiting, cooperative execution deadlines, graceful shutdown with connection draining, custom error pages, and bounded request queues with backpressure.
Flexible Routing
Three modes: Traditional (direct file mapping), Framework (front controller), and SPA (HTML5 history). Static file serving with MIME detection and caching.
SSE & Streaming
Server-Sent Events and chunked transfer encoding with real-time flush. Use oxphp_stream_flush() to push data as it becomes available.
Plugin System
Typed event dispatcher with priority ordering. Core features (rate limiting, metrics, compression) are implemented as plugins using the same API available to extensions.
High Performance
mimalloc allocator, zero-clone hot path, lock-free response slot pool, pre-allocated buffers. Benchmarked at ~32.7k req/s — outperforming nginx + PHP‑FPM.
Quick Start
FROM ghcr.io/oxphp/oxphp:nightly COPY --chown=www-data:www-data . /var/www/html
Place your PHP application in the build context. The document root is /var/www/html/public.
# Build your image docker build -t my-app ghcr.io/oxphp/oxphp:nightly # Run with defaults (auto-scaled workers, port 8080) docker run -p 8080:8080 my-app # Run with custom configuration docker run -p 8080:8080 \ -e PHP_WORKERS=8 \ -e RATE_LIMIT=100 \ -e INDEX_FILE=index.php \ my-app
my-app/ ├── Dockerfile ├── public/ # ← DOCUMENT_ROOT │ ├── index.php # front controller (framework mode) │ └── assets/ # static files (served directly) ├── app/ # application code (outside doc root) │ ├── routes.php │ └── ... └── preload.php # OPcache preload (optional)
Configuration
All configuration is via environment variables. No config files needed.
| Variable | Default | Description |
|---|---|---|
LISTEN_ADDR | 0.0.0.0:8080 | HTTP listen address |
DOCUMENT_ROOT | /var/www/html/public | Document root path |
INDEX_FILE | (empty) | Routing mode: index.php = framework, index.html = SPA |
TOKIO_WORKERS | 0 | Async I/O threads (0 = auto, CPU/2) |
COMPRESSION_LEVEL | 4 | Brotli compression level (0-11, 0=off) |
STATIC_CACHE_TTL | 30d | Static file cache TTL (30s, 5m, 2h, 30d, 1w, 1y, or off) |
| Variable | Default |
|---|---|
PHP_WORKERS | 0 (auto: cpu×2) |
QUEUE_CAPACITY | workers × 128 |
PHP_WORKERS_IDLE_SECONDS | 30 |
PHP_WORKERS=8 (static) or PHP_WORKERS=2:16 (dynamic scaling).
| Variable | Default |
|---|---|
WORKER_FILE | (none) |
WORKER_MAX_REQUESTS | 0 (unlimited) |
WORKER_MAX_MEMORY_MIB | 0 (unlimited) |
Set WORKER_FILE=../worker.php for persistent PHP with soft reset between requests.
| Variable | Default |
|---|---|
REQUEST_TIMEOUT_SECONDS | 120 |
HEADER_TIMEOUT_SECONDS | 5 |
DRAIN_TIMEOUT_SECONDS | 30 |
| Variable | Default |
|---|---|
RATE_LIMIT | 0 (off) |
RATE_WINDOW_SECONDS | 60 sec |
TLS_CERT | (none) |
TLS_KEY | (none) |
| Variable | Default |
|---|---|
INTERNAL_ADDR | (none) |
ACCESS_LOG | true |
LOG_LEVEL | info |
ERROR_PAGES_DIR | (none) |
Set INTERNAL_ADDR=0.0.0.0:9090 to enable /health, /metrics, /config.
PHP Functions
OxPHP exposes these functions to PHP scripts via the oxphp_sapi extension.
oxphp_request_id(): string
Returns the 16-char hex request ID for the current request.
oxphp_worker_id(): int
Returns the zero-based worker thread index.
oxphp_server_info(): array
Returns SAPI name, version, worker ID, request timestamp, and worker mode flag.
oxphp_finish_request(): bool
Sends response immediately, continues background execution.
oxphp_stream_flush(): bool
Activates streaming mode and flushes output as a chunk.
oxphp_is_worker(): bool
Returns true if running in worker mode, false in traditional mode.
oxphp_is_streaming(): bool
Returns true if chunked/SSE streaming mode is active.
oxphp_request_heartbeat(int $time = 10): bool
Extends the execution deadline by N seconds.
oxphp_worker(callable $handler): bool
Enters persistent worker loop. Calls handler per request with soft reset.
Documentation
| Section | Content |
|---|---|
| Getting Started | Installation, Docker setup, quick start guide |
| Architecture | Request lifecycle, worker pool, SAPI bridge, event system |
| Features | Routing, TLS, compression, rate limiting, error pages, timeouts |
| PHP Integration | Custom functions, superglobals, OPcache configuration |
| Operations | Configuration reference, health checks, metrics, graceful shutdown |
Available in: English · Русский · Беларуская · 中文