Configuration

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.

Boolean values
truthy on true 1 yes falsy off false 0 no

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 variables
0.0.0.0:80

Address and port for the main HTTP server.

/var/www/html/public

Root directory for serving files and PHP scripts.

(unset)

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.

false

Enable persistent worker mode. Requires ENTRY_FILE pointing at a .php script.

10000

Maximum concurrent TCP connections.

CPU / 2 (min 1)

Async I/O threads. 1 = single-threaded, N = fixed count, unset = auto.

sapi

PHP executor backend: sapi for real PHP, stub for benchmarking without PHP.

CPU / 2 (min 1)

Worker pool size. N = fixed pool, MIN:MAX = dynamic scaling, 0 = auto.

30

Seconds a dynamic worker stays idle before being retired.

workers × 128

Max pending requests in the PHP queue; 529 when full. For MIN:MAX pools, initial workers = the minimum.

(unset)

Memory ceiling per worker in MiB before recycling. 0 = unlimited. On-demand recycling via Worker::scheduleExit().

true

Populate $_GET, $_POST, $_COOKIE, $_FILES, $_SERVER and php://input before each script. Falsy = object API only (oxphp_http_request()).

Traffic & delivery

15 variables
5

Max seconds to receive HTTP headers after connect (Slowloris protection).

30

Max seconds to wait for in-flight connections during graceful shutdown.

0 (off)

Max requests per IP per window. 0 = off; a full PHP queue answers 529.

60

Rate-limit window duration in seconds.

(unset)

Path to the PEM certificate. Both TLS_CERT and TLS_KEY must be set to enable TLS.

(unset)

Path to the PEM private key.

1.2

Minimum TLS version: 1.2 or 1.3. Validated at startup even when TLS is off.

PHP_WORKERS_MAX × 4

Max simultaneous open streams per connection.

20

Max queued RST_STREAM frames before the connection is closed (Rapid Reset protection).

65536

Max total decoded header bytes per request.

20

Seconds between PING frames; 0 disables.

10

Seconds to wait for a PING reply before closing the connection.

30d

Cache-Control: max-age for static files. Accepts 30s, 5m, 2h, 30d, 1w, 1y, bare seconds or off. Replaces STATIC_CACHE_TTL.

off

mtime revalidation for the in-memory cache — checked at most every 3 s per file. Replaces STATIC_CACHE.

4

Brotli quality 0–11. 0 disables compression.

Security

5 variables
DENY

Clickjacking protection: DENY, SAMEORIGIN or off. Sets X-Frame-Options + CSP frame-ancestors; application-set headers always win.

(unset)

Trusted proxy CIDRs (or private). Real client IP from Forwarded / X-Forwarded-* via rightmost-non-trusted.

(unset)

Glob patterns whose .php files never execute via direct URI (/uploads/**). Matched before disk I/O — no existence oracle.

404

Response on a deny match: an HTTP status 400–599 or a /-prefixed PHP fallback script inside DOCUMENT_ROOT.

(unset)

Absolute paths under which symlinks may escape DOCUMENT_ROOT. Unset = no escapes allowed.

Logs, traces & profiles

34 variables
info

Log verbosity: trace, debug, info, warn, error.

(unset)

Per-request access log: all = every request, error = 4xx/5xx only, unset = off.

(unset)

Internal server (/health, /metrics, /config). Port-only values bind 127.0.0.1; unset = not started.

(unset)

CIDR allow-list for the internal server; outsiders get 403, health probes stay reachable. Loopback is not implicit.

(unset)

Directory with custom {status}.html error pages.

524288

Max body bytes for internal query endpoints (512 KiB).

false

W3C Trace Context propagation: reads traceparent/tracestate and forwards them to PHP via $_SERVER.

false

Enable OpenTelemetry span export. Implies TRACE_CONTEXT=true.

grpc

Export protocol: grpc or http/protobuf.

localhost:4317 / 4318

OTLP collector endpoint.

10000

Export timeout in milliseconds.

(unset)

Authentication headers: key=value,key2=value2.

oxphp

Service name in exported spans.

(unset)

Service version attribute.

(unset)

Extra resource attributes: env=prod,region=us-east-1.

parentbased_traceidratio

Sampling strategy: always_on, always_off, traceidratio and the parentbased_* variants.

1.0

Sampling ratio 0.0–1.0 for ratio-based samplers; out-of-range values are clamped.

false

APM: auto-instrumentation of 33 PHP functions (PDO, mysqli, cURL, Redis…), error capture, tracing SDK. Requires OTEL_ENABLED.

100

Slow-query threshold in ms; slower DB queries get oxphp.db.slow=true.

false

Record bind parameters in db.params spans. Disable if parameters may be sensitive.

false

Master switch. Other PROFILER_* vars are still parsed, so typos surface at startup.

0.0

Probability 0.0–1.0 that a request is sampled.

false

Also sample requests to the internal server.

(unset)

Bearer token required for on-demand profiling via oxphp_profiler_*().

50000

Per-request span cap; longer profiles are truncated.

256

Max call-stack depth per sample (hard cap 65535).

/tmp/oxphp-profiles

Directory for on-disk profiles.

xhprof,speedscope

Formats written to disk: xhprof, speedscope, pprof, flamegraph.

10

Rate limit on profile files written per second.

100

Max profile files kept; older ones are pruned.

(unset)

Remote endpoint to POST profiles to.

xhprof

Wire format for exports.

(unset)

Bearer token sent with each export.

(auto-detect)

XHGui-compatible wrapping; unset = auto-detect from the URL.

Async & shared state

19 variables
0 (off)

Dedicated async worker threads. 0 = functions registered but throwing AsyncException on call.

ASYNC_WORKERS × 64

Max pending tasks in the async queue. 0 = auto.

256

Per-worker cap on concurrent task fibers; global in-flight cap = fibers × workers.

true

Master switch for the whole OxPHP\Shared\* subsystem.

100000

Global cap on all Shared entries; inserts past it throw CapacityException.

1 GiB

Global cap on estimated memory across all entries.

0.7

Start shedding lowest-priority work past this fraction of the caps.

true

Toggles the oxphp_shared_* Prometheus exposition.

true

Toggles the /__ox_shared/* introspection API.

true

Value previews in introspection responses; disable if previews could leak data.

16

BFS depth for cycle checks; raise for deep graphs.

10000

Edges walked during cycle checks; raise for dense graphs.

1 MiB

Per-value size cap; larger inserts fail fast.

64 MiB

Per-channel total payload cap.

false

A panic inside a Mutex/Once closure poisons the primitive permanently instead of best-effort recovery.

off

Lock-contention diagnostics: off, count or trace.

100

Polling interval for the lock-diagnostics sampler.

256

Per-string truncation in /entry previews.

20

Entries sampled in /entry previews.

Presets

Example configurations

Starting points straight from the docs — copy one and adjust.

# verbose logs while you build and debug
LOG_LEVEL=debug
# record every request, not just errors
ACCESS_LOG=all
# one worker — deterministic, breakpoint-friendly
PHP_WORKERS=1
# local /health, /metrics and /config endpoints
INTERNAL_ADDR=127.0.0.1:9090
# re-read edited static files without a restart
STATIC_REVALIDATE=on
Inspect the live configuration

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.

curl -s http://localhost:9090/config | jq .

Zero configuration is a valid configuration

Every default above is chosen so an empty environment just works.