Plugins¶
Plugins are external executables that extend prox at runtime. They dynamically manage balancer targets, authorize HTTP requests, modify upstream responses, and gate L4 TCP connections.
Overview¶
- Plugins communicate with prox over stdin/stdout (JSON) for lifecycle events and Unix sockets (msgpack) for request-response hooks.
- Each plugin runs as a child process, automatically restarted on crash.
- The Go SDK handles all transport details — plugin authors register callbacks only.
- Target updates are applied atomically with zero lock contention on the data plane.
Windows
Push-only plugins can use stdin/stdout on Windows. Request-response hooks require Unix domain sockets and are supported on Linux and macOS.
Modes¶
| Mode | Hooks | Transport | Use Case |
|---|---|---|---|
| Push-only | OnConfigure |
stdin/stdout | Target discovery, DNS resolution |
| Request-response | OnRequest, OnResponse, OnConnect |
Unix socket (msgpack) | Auth, rate limiting, header injection |
| Fire-and-forget | OnDisconnect |
Unix socket (msgpack) | Connection statistics, usage tracking |
| Hybrid | All | Both | Full middleware + discovery |
Building Plugins¶
Plugins written as .go source files or Go package directories must be compiled with prox build before starting the server. Pre-compiled binaries are used as-is and must be executable.
This compiles each plugin source and places the binary alongside the source file. Rebuilds are skipped if the binary is newer than the source (mtime check).
Single file — path ends in .go:
Directory — path points to a Go package:
Tip
Run prox build in CI/CD pipelines or Dockerfile build stages. prox serve expects pre-compiled binaries and returns an error if plugin source has not been compiled.
Configuration¶
Plugins are defined in the global plugins block and attached at three levels: route, service, or action.
Route-Level¶
Plugins apply only to the specific route:
Service-Level¶
Plugins apply to all routes in the service:
services: {
web: {
listen: ":443",
plugins: ["auth"],
routes: [
{ match: { path: "/api/*" }, action: "api" },
{ match: { path: "/ws" }, action: "proxy" }, // also gets "auth"
]
}
}
Action-Level¶
Plugins apply to all routes that reference the action:
Merge Order¶
Plugins from all levels are merged per route in this order: service → action → route. Duplicates are removed (first occurrence wins). The effective list determines execution order — service-level plugins run first, then action-level, then route-level.
Fields¶
| Field | Type | Default | Description |
|---|---|---|---|
plugins |
[]string |
— | Plugin aliases or literal paths. Available on routes, services, and actions. |
plugin_timeout |
duration |
5s |
Per-request timeout for plugin hook calls. Route-level only. |
autostart |
bool |
false |
Start plugin at proxy startup without route bindings. |
Rules¶
- Plugin paths accept
.gosource files or Go package directories — compile withprox buildbefore starting the server. - A
balanceris required only when using target discovery (not for auth-only plugins). - Multiple plugins attach to a single route with sequential execution; deny verdicts short-circuit the chain.
- Plugins with
autostart: truespawn at startup without route bindings — suitable for background routines, metrics, and health monitors.
Lifecycle¶
1. prox starts → spawns plugin process
2. prox sends "configure" for each bound route (or empty route for autostart plugins)
3. Plugin optionally sends "ready" with socket path and hooks
4. prox connects to the Unix socket (connection pool)
5. Plugin pushes "set_targets" whenever data changes
6. For each request: prox calls hooks over socket, plugin responds
7. On config reload → prox sends new "configure"
8. On prox shutdown → stdin closes → plugin exits
Crash Recovery¶
If a plugin process exits unexpectedly:
- Targets freeze at the last known state.
- Request-response hooks fail open (requests pass through).
- prox restarts the plugin with exponential backoff (1s → 2s → 4s → … → 30s max).
- After restart, prox re-sends
configurefor all bound routes. - The backoff resets after a successful message.
Stderr¶
Plugin stderr is forwarded to the prox logger at debug level, tagged with the plugin alias from config:
The tag resolves from the plugins registry key. For raw path references (not registered in plugins), the binary basename is used.
Performance¶
| Operation | Overhead |
|---|---|
| Request routing (no hooks) | None — unchanged hot path |
on_request hook |
~50–100μs per call (Unix socket + msgpack) |
on_response hook |
~50–100μs per call |
on_connect hook (L4) |
~50–100μs per call |
set_targets push |
O(1) atomic pointer store |
| Plugin crash | Targets freeze, hooks fail open, auto-restart |