Every setting is one environment variable
There are no config files. Every setting is an environment variable, and every variable has a default that holds up in production. Deploy an empty environment, then override only the variables you actually care about.
Anything outside this set — typos like "ture" — fails fast at startup, naming the variable. Empty equals unset: FOO=${FOO} substitutions that produce FOO= fall back to the default instead of refusing to start.
Server & workers
12 variablesAddress and port for the main HTTP server.
Root directory for serving files and PHP scripts.
Single canonical entry script. Unset = direct file mapping, *.php = front controller, non-.php = SPA fallback; with worker mode — the worker bootstrap. Resolved against DOCUMENT_ROOT.
Enable persistent worker mode. Requires ENTRY_FILE pointing at a .php script.
Maximum concurrent TCP connections.
Async I/O threads. 1 = single-threaded, N = fixed count, unset = auto.
PHP executor backend: sapi for real PHP, stub for benchmarking without PHP.
Worker pool size. N = fixed pool, MIN:MAX = dynamic scaling, 0 = auto.
Seconds a dynamic worker stays idle before being retired.
Max pending requests in the PHP queue; 529 when full. For MIN:MAX pools, initial workers = the minimum.
Memory ceiling per worker in MiB before recycling. 0 = unlimited. On-demand recycling via Worker::scheduleExit().
Populate $_GET, $_POST, $_COOKIE, $_FILES, $_SERVER and php://input before each script. Falsy = object API only (oxphp_http_request()).
Traffic & delivery
15 variablesMax seconds to receive HTTP headers after connect (Slowloris protection).
Max seconds to wait for in-flight connections during graceful shutdown.
Max requests per IP per window. 0 = off; a full PHP queue answers 529.
Rate-limit window duration in seconds.
Path to the PEM certificate. Both TLS_CERT and TLS_KEY must be set to enable TLS.
Path to the PEM private key.
Minimum TLS version: 1.2 or 1.3. Validated at startup even when TLS is off.
Max simultaneous open streams per connection.
Max queued RST_STREAM frames before the connection is closed (Rapid Reset protection).
Max total decoded header bytes per request.
Seconds between PING frames; 0 disables.
Seconds to wait for a PING reply before closing the connection.
Cache-Control: max-age for static files. Accepts 30s, 5m, 2h, 30d, 1w, 1y, bare seconds or off. Replaces STATIC_CACHE_TTL.
mtime revalidation for the in-memory cache — checked at most every 3 s per file. Replaces STATIC_CACHE.
Brotli quality 0–11. 0 disables compression.
Security
5 variablesClickjacking protection: DENY, SAMEORIGIN or off. Sets X-Frame-Options + CSP frame-ancestors; application-set headers always win.
Trusted proxy CIDRs (or private). Real client IP from Forwarded / X-Forwarded-* via rightmost-non-trusted.
Glob patterns whose .php files never execute via direct URI (/uploads/**). Matched before disk I/O — no existence oracle.
Response on a deny match: an HTTP status 400–599 or a /-prefixed PHP fallback script inside DOCUMENT_ROOT.
Absolute paths under which symlinks may escape DOCUMENT_ROOT. Unset = no escapes allowed.
Logs, traces & profiles
34 variablesLog verbosity: trace, debug, info, warn, error.
Per-request access log: all = every request, error = 4xx/5xx only, unset = off.
Internal server (/health, /metrics, /config). Port-only values bind 127.0.0.1; unset = not started.
CIDR allow-list for the internal server; outsiders get 403, health probes stay reachable. Loopback is not implicit.
Directory with custom {status}.html error pages.
Max body bytes for internal query endpoints (512 KiB).
W3C Trace Context propagation: reads traceparent/tracestate and forwards them to PHP via $_SERVER.
Enable OpenTelemetry span export. Implies TRACE_CONTEXT=true.
Export protocol: grpc or http/protobuf.
OTLP collector endpoint.
Export timeout in milliseconds.
Authentication headers: key=value,key2=value2.
Service name in exported spans.
Service version attribute.
Extra resource attributes: env=prod,region=us-east-1.
Sampling strategy: always_on, always_off, traceidratio and the parentbased_* variants.
Sampling ratio 0.0–1.0 for ratio-based samplers; out-of-range values are clamped.
APM: auto-instrumentation of 33 PHP functions (PDO, mysqli, cURL, Redis…), error capture, tracing SDK. Requires OTEL_ENABLED.
Slow-query threshold in ms; slower DB queries get oxphp.db.slow=true.
Record bind parameters in db.params spans. Disable if parameters may be sensitive.
Master switch. Other PROFILER_* vars are still parsed, so typos surface at startup.
Probability 0.0–1.0 that a request is sampled.
Also sample requests to the internal server.
Bearer token required for on-demand profiling via oxphp_profiler_*().
Per-request span cap; longer profiles are truncated.
Max call-stack depth per sample (hard cap 65535).
Directory for on-disk profiles.
Formats written to disk: xhprof, speedscope, pprof, flamegraph.
Rate limit on profile files written per second.
Max profile files kept; older ones are pruned.
Remote endpoint to POST profiles to.
Wire format for exports.
Bearer token sent with each export.
XHGui-compatible wrapping; unset = auto-detect from the URL.
Example configurations
Starting points straight from the docs — copy one and adjust.
With the internal server running, /config returns the resolved configuration as JSON. TLS paths, INTERNAL_ADDR and ERROR_PAGES_DIR are scrubbed from the response.
Zero configuration is a valid configuration
Every default above is chosen so an empty environment just works.