Configuration¶
prox uses JSON5 for configuration — a superset of JSON that supports comments, trailing commas, and unquoted keys.
Structure¶
Every configuration file contains up to four top-level sections:
┌───────────────────────────────────────────────────────────────┐
│ config.json5 │
├──────────────┬──────────────┬───────────────┬─────────────────┤
│ services │ plugins │ actions │ resources │
│ (WHAT) │(MIDDLEWARE) │ (HOW) │ (WITH WHAT) │
│ │ │ │ │
│ listen addr │ name │ type: proxy │ inline text │
│ tls on/off │ └ path │ type: static │ │
│ routes[] │ └ autostart│ type: serve │ │
│ └ match │ │ timeout │ │
│ └ plugins ─│──► ref │ │ │
│ └ speed │ │ │ │
│ └ action ──│──────────────│──► ref ───────│──► body_ref │
└──────────────┴──────────────┴───────────────┴─────────────────┘
Configuration is reference-based. Routes point to actions by name, and actions point to resources by name. Both actions and resources may also be inlined directly when a definition is not reused.
Services¶
A service defines a listener with routing rules. Services can be defined inline or loaded from external files.
Inline¶
{
services: {
my_site: {
listen: ":8080", // required
tls: true, // optional, default: false
tls_cert: "/path/cert", // required if tls: true (unless acme is set)
tls_key: "/path/key", // required if tls: true (single-file mode)
acme: {}, // optional, automatic certificates via ACME
h2: false, // optional, default: true. Set false for WebSocket
config: {}, // optional, per-service tuning
routes: [...] // required, at least one
},
},
}
h2 — HTTP/2 on TLS listeners¶
Controls whether the TLS listener advertises HTTP/2 via ALPN negotiation.
| Value | Description |
|---|---|
true |
HTTP/2 enabled (default when TLS is on) |
false |
HTTP/1.1 only — required for WebSocket support |
Go's HTTP/2 implementation strips Connection and Upgrade hop-by-hop headers from incoming requests, preventing WebSocket upgrade detection. Set h2: false on any TLS service that handles WebSocket connections.
Note
The h2 option controls the client-facing listener protocol. The upstream protocol is controlled separately by the proto field in the action configuration.
This setting has no effect on non-TLS services (HTTP/2 requires TLS for ALPN negotiation).
For manual certificate setup, automatic ACME certificates, and advanced TLS options, see TLS & Certificates.
Service config¶
The optional config block tunes HTTP server timeouts and proxy transport behavior for a specific service. All values fall back to built-in defaults when omitted.
Durations accept strings ("5s", "1m30s", "5m") or numbers (interpreted as seconds).
| Field | Default | Description |
|---|---|---|
read_timeout |
10s |
Maximum time to read the full request (headers + body) |
write_timeout |
30s |
Maximum time to write the full response |
idle_timeout |
120s |
Keep-alive idle timeout before closing the connection |
response_header_timeout |
30s |
Maximum time to wait for upstream response headers |
flush_interval |
0 |
How often to flush buffered proxy response data. -1 = flush immediately |
dial_timeout |
action | TCP dial timeout (defaults to the action's timeout) |
keep_alive |
30s |
TCP keep-alive interval |
max_idle_conns |
4096 |
Maximum idle connections in the connection pool |
max_idle_conns_per_host |
4096 |
Maximum idle connections per upstream host |
read_buffer_size |
32768 |
Read buffer size in bytes for proxy transport (32 KB) |
write_buffer_size |
32768 |
Write buffer size in bytes for proxy transport (32 KB) |
tls_handshake_timeout |
10s |
TLS handshake deadline for HTTPS upstreams |
h2_read_idle_timeout |
30s |
HTTP/2: send ping after this idle period |
h2_ping_timeout |
15s |
HTTP/2: deadline for ping response |
max_connections |
0 |
Maximum concurrent connections. 0 = unlimited |
Tip
For streaming protocols (SSE, long-lived HTTP, long-polling), set flush_interval to -1 and increase read_timeout, write_timeout, and response_header_timeout to accommodate long-lived connections.
// Streaming-friendly gateway — long timeouts, immediate flushing.
{
services: {
gateway: {
listen: ":443",
tls: true,
tls_cert: "/etc/prox/certs/",
config: {
read_timeout: "5m",
write_timeout: "5m",
response_header_timeout: "5m",
flush_interval: -1,
},
routes: [...]
},
},
}
File reference¶
A string value loads the service definition from an external JSON5 file:
Relative paths are resolved from the directory of the parent config file.
Directory reference¶
A string pointing to a directory loads all .json5 files from it. Each file becomes a service named after its filename (without extension):
{
services: {
_microservices: "./services/",
// services/web.json5 → service "web"
// services/api.json5 → service "api"
},
}
Non-.json5 files and subdirectories are ignored.
Directory mode (CLI)¶
A directory path may also be passed directly to -config:
Every .json5 file in the directory is treated as a service fragment. No root config file is required.
Service Fragments¶
A service fragment is the file format for external service definitions. It contains a service definition with optional local actions and resources:
// web.json5
{
listen: ":8080",
routes: [
{ match: { path: "/health" }, action: "health" },
{ match: { path: "/*" }, action: "frontend" },
],
// Local actions — merged into the global pool.
actions: {
frontend: { type: "serve", root: "./public" },
},
// Local resources — merged into the global pool.
resources: {
banner: { text: "Welcome!" },
},
}
Merge rules:
- Actions and resources from fragments are merged into the global pool alongside definitions from the root config.
- Duplicate names across any files produce a validation error — rename to avoid collisions.
- Global actions from the root config are accessible to all services (e.g., a shared
healthaction). - Fragments cannot reference other files — only one level of nesting is supported.
Validation¶
Validate configuration before deploying:
The validator checks:
- All action references resolve
- All resource references resolve
- Required fields are present
- HTTP methods are valid
- Path patterns are well-formed
- Domain patterns are well-formed (at most one
*per segment, at least 2 segments,**only at end) - At least one of
pathordomainin each route (or omitmatchfor catch-all) - TLS cert/key are provided when TLS is enabled
passroutes require adomain(SNI matching) and cannot usepathormethodspassactions require anupstream- Balancer type is valid (
roundrobin,random, orleastconn) - Balancer targets are non-empty and unique (empty allowed with plugins)
- Balancer is only used with
proxyorpassactions - Action upstream contains
{target}when a balancer is used - Speed config values are non-negative, at least one direction > 0
- Plugin paths are non-empty
- No duplicate action/resource names across files
- No circular file references
- Reports all issues at once