BareProxy Inbox and Drift Watcher Use Examples
Six short recipes for the two features that arrived in BareProxy 0.16.0, the webhook inbox and the drift watcher. Each one was run on the released Linux binary and the output below is copied from that run. The tested configs used a temporary folder, local ports and names under .test; the configs here use the usual paths and example names, and the output is left as it came, test names included. The webhooks were signed with test secrets in Stripe’s and GitHub’s formats, and the drift recipes ran against a local stand-in for DNS and HTTPS, because the machine had no public DNS.
1. An inbox in front of an app that restarts on every deploy
site hooks.example.com
route /hooks/stripe -> inbox stripe
inbox stripe
deliver app
signature stripe /etc/bareproxy/stripe-secret
retry 5s 2m
pool app
backend 127.0.0.1:8080
health /healthz
bareproxy check on the tested file said ok, 1 site, 1 pool, 2 rules. The app was stopped, one Stripe webhook came in and got 202 in 20 ms, and the app came back 15.4 seconds later. The event reached the app 19.7 seconds after that, on its fourth attempt.
That gap is the backoff at work. Attempts came at 5 and 15 seconds after the webhook arrived, both while the app was down, and the third retry was set for 35 seconds. The health check tells the pool when the app is back, but it doesn’t wake up an event that is already waiting. So pick retry for how long your deploys take. With 5s 2m no event waits more than two minutes between tries; the default ceiling is an hour.
2. Checking Stripe signatures
signature stripe FILE is all it takes. The file holds the endpoint’s signing secret (whsec_...) and nothing else. In the run, a correctly signed webhook got 202, one signed with the wrong secret got 401, and one with the right secret but a timestamp ten minutes old got 401. Neither rejected webhook was stored.
One thing to watch. The inbox keeps the request as it came, Stripe-Signature included, and its t= value is the time Stripe signed it. If your app also checks that header with Stripe’s library, a delivery that waited out an outage will fail the library’s five minute tolerance. Let BareProxy do the check, or widen the tolerance in the app. For repeats, keep the evt_ IDs you have handled: a Stripe retry is a new request to BareProxy, as the duplicates case study shows.
3. Replaying what failed during an outage
When the app was broken long enough for events to pass give-up (15 seconds in this test, three days by default), they were marked failed and kept:
$ bareproxy inbox list github --status failed
Inbox github (line 15), to pool app, in /work/state/inbox/github
0 pending, 0 delivering, 0 delivered, 2 failed
18e39758786c365152c1d6 2026-10-31 10:44:42 failed /hooks/github, 158 B, 5 attempts, last: 500
18e39758638e4c637f884c 2026-10-31 10:44:42 failed /hooks/github, 158 B, 5 attempts, last: 500
$ bareproxy inbox replay github --failed
Replayed 2 events; each delivery carries BareProxy-Inbox-Replay: operator.
Both reached the fixed app at once, marked operator, and were processed. inbox show keeps the whole story of an event, with the sender’s own ID when the inbox has a key-header:
$ bareproxy inbox show github 18e39758638e4c637f884c
Event 18e39758638e4c637f884c in inbox github: delivered
Received 2026-10-31 10:44:42.506 UTC: POST hooks.test:56529/hooks/github, 158 B
Sender's ID: 155493cd-d51f-43f0-bad5-fd661337a3fc
...
Attempt 1 at 2026-10-31 10:44:42: 500
Attempt 2 at 2026-10-31 10:44:44: 500
Attempt 3 at 2026-10-31 10:44:48: 500
Attempt 4 at 2026-10-31 10:44:53: 500
Attempt 5 at 2026-10-31 10:44:58: 500
Attempt 6 at 2026-10-31 10:44:59: 200 (marked operator)
Delivered 2026-10-31 10:44:59 UTC
--body adds the payload, and --json works on all three commands. To replay a handful by hand, list their IDs after the inbox name instead of --failed.
4. Drift in CI, failing the job on alerts
A config with only a drift block is enough for a CI job, and no server needs to run:
global
state /var/lib/bareproxy-ci
drift sites
domains www.example.com shop.example.com
The job runs a small script around the exit code:
#!/bin/sh
bareproxy drift -c drift-ci.conf
case $? in
0) echo "drift: all clear" ;;
3) echo "drift: some parts couldn't be checked, see above" ;;
4) echo "drift: alerts, failing the job"; exit 1 ;;
*) echo "drift: the check couldn't run"; exit 1 ;;
esac
In the run, the shop certificate had 11 days left:
ALERT shop.example.test certificate ends in 11 days (2026-11-12 10:45 UTC), inside the 21-day window
Result: 1 alert, 0 unchecked
drift: alerts, failing the job
(job exit code 1)
With expiry 7d added to the block, the same certificate was outside the window, the result was 0 alerts, 0 unchecked and the job passed. Code 3 is left as a warning here, so a flaky resolver doesn’t fail a build; make it fail too if you’d rather.
Keep the state folder between CI runs, in a cache or an artifact. Without it every run is a first look, and a first look reports standing problems but can’t see a change.
5. Drift every hour inside the server, with a webhook alert
Add every and webhook to a drift block in the server’s own config:
drift sites
domains www.example.com shop.example.com
every 1h
webhook https://alerts.example.com/bareproxy
The server ran its first check five seconds after it started, since the watch had no state yet. After that it waits for every to pass since the last check, across restarts. The alert receiver got the report as JSON, which jq boils down to:
{"watch":"sites","domains":2,"alerts":[{"domain":"shop.example.test","text":"certificate ends in 11 days (2026-11-12 10:45 UTC), inside the 21-day window"}],"unchecked":0}
And bareproxy events showed the check and its alert:
2026-10-31T10:45:07.519Z drift drift sites: 2 domains, 1 alert, 0 unchecked, webhook sent, answered 204
2026-10-31T10:45:07.519Z drift drift sites: shop.example.test certificate ends in 11 days (2026-11-12 10:45 UTC), inside the 21-day window
The webhook only fires when there is something to say, alerts or unchecked parts. A clean check stays in events.
6. Reading the history
After www moved to a new address, the next check alerted once, and the history kept the change:
$ bareproxy drift -c drift-ci.conf --history
Drift watch sites, history:
2026-10-31 10:45:01 shop.example.test first look, recorded: A 127.0.0.1; ...
2026-10-31 10:45:01 www.example.test first look, recorded: A 127.0.0.1; ...
2026-10-31 10:45:07 www.example.test A changed
before: 127.0.0.1
after: 127.0.0.2
As JSON it is one list per watch, and each change has kind, part, before and after. To pull out only the changes:
$ bareproxy drift -c drift-ci.conf --history --json | jq -c '.. | objects | select(has("before") and has("after"))'
{"time":"2026-10-31T12:45:07.671489159+02:00","domain":"www.example.test","kind":"record-changed","part":"A","text":"A changed","before":["127.0.0.1"],"after":["127.0.0.2"]}
The script that ran all six recipes and its full log are in the repository: use-examples.sh and use-examples.log. Longer runs of the same features are in the case studies on an app deploy, a crash mid-delivery, duplicates and a bad deploy and a DNS move.