Demo
BareProxy’s own commands, run against the config on the config reference page. Each one reads the same compiled config the proxy routes with, so what it prints is what the proxy does.
Explain a Request Before It Arrives
explain walks the rules from the top, says why each one did or didn’t match, and shows which backend would get the request right now.
$ bareproxy explain GET https://example.com/api/orders
Running config, version 12
Site example.com (line 5): exact host match
line 6 route /healthz -> respond 200 "ok" no: path is not /healthz
line 7 route /api/* -> api strip match
Sent upstream as GET /orders with Host: example.com
Pool api (line 13): 2 of 3 up, fewest in flight wins
10.0.0.11:8080 up, 0 in flight next pick
10.0.0.12:8080 up, 2 in flight
10.0.0.13:8080 down since 14:02:10, 3 failed checks
Ask What Happened to a Request
Every response carries a BareProxy-Id header, and every error page shows it. Give any unique part of it to why:
$ bareproxy why 7f3a9c
Request 7f3a9c0d12e4b5a6, 1 Oct 2026 14:03:22.418 UTC, config version 12
GET https://example.com/api/orders from 203.0.113.7, TLS 1.3, HTTP/2
Site example.com (line 5)
Rule line 7: route /api/* -> api strip
sent upstream as /orders
Pool api (line 13): 2 of 3 up
10.0.0.13:8080 skipped: down since 14:02:10, 3 failed checks
10.0.0.11:8080 tried first, fewest in flight: connect refused, 0.4 ms
10.0.0.12:8080 tried next: 200 OK, first byte after 36.9 ms
Response 200, 5.0 KB, 38.2 ms in total
See What a Change Will Do
Here a new API version gets its own pool, a beta route is added in the wrong place, and one web backend is retired. plan lists the requests that change hands, and nothing else, and catches the rule that can never match:
$ bareproxy plan
Running version 12 compared with /etc/bareproxy/bareproxy.conf
Requests that change hands
example.com, any method, /api/v2 and below
before v12 line 7 route /api/* -> api strip sent as /v2/...
after new line 7 route /api/v2/* -> api-v2 sent as /api/v2/...
Backends
pool api-v2 new: 10.0.0.31:8080, 10.0.0.32:8080
each gets traffic once it passes its first health check
pool web 10.0.0.22:3000 removed, drains for up to 30s
Warnings
line 8: route /api/v2/beta/* -> beta never matches;
line 7 (route /api/v2/*) takes all of its requests
Plan 3c9e71. To apply exactly this: bareproxy apply --plan 3c9e71
The Record Behind It
Each request leaves one JSON line in the trace log:
{"id":"7f3a9c0d12e4b5a6","time":"2026-10-01T14:03:22.418Z","config":12,
"client":"203.0.113.7","tls":"1.3","proto":"HTTP/2.0",
"method":"GET","host":"example.com","path":"/api/orders",
"site":"example.com","line":7,"action":"pool api strip",
"upstream_path":"/orders",
"attempts":[{"backend":"10.0.0.11:8080","error":"connect refused","ms":0.4},
{"backend":"10.0.0.12:8080","connect_ms":0.6,"first_byte_ms":36.9,
"status":200}],
"status":200,"bytes_out":5120,"ms":38.2,"outcome":"ok"}