Repository navigation
Routing diagnostic traffic to a debug only TPS
Sometimes you need to reproduce a problem against a TPS that is built or configured differently from production -- extra logging, a patched binary, a tweaked token budget or lifetime -- without exposing that instance to the public or disturbing real traffic. The trick is to run a second "debug" TPS on its own port and let your front proxy send only your requests to it, keyed on a cookie that only you set.
Say production TPS listens on :18888 and an always-debug instance listens on
:18889. You want :18889 to handle a request only when it carries the cookie
debug-tps=secret-key; everyone else keeps hitting :18888. In Caddy, add a
cookie matcher in front of the normal TPS handler and route matching requests
to the debug port:
https://{$SITE_HOST:localhost} {
tls internal
log
# The paths that go through TPS at all.
@protected {
path /protected/* /static-protected/*
}
# ...of those, the ones carrying our private debug cookie go to the
# always-debug TPS on 18889. Use header_regexp (not a loose
# `header Cookie *...*` substring match) so an unrelated cookie value can't
# accidentally satisfy it.
@debug_tps {
path /protected/* /static-protected/*
header_regexp Cookie "(^|;\s*)debug-tps=secret-key(\s*;|$)"
}
# Order matters: handle blocks are mutually exclusive and evaluated top to
# bottom, so the more specific debug matcher has to come first.
handle @debug_tps {
reverse_proxy 127.0.0.1:18889
}
handle @protected {
reverse_proxy 127.0.0.1:18888
}
handle {
reverse_proxy app:8080
}
}Set the cookie yourself when you want to opt into the debug path, e.g. from the
browser devtools console (document.cookie = "debug-tps=secret-key; path=/")
or with curl:
curl -b "debug-tps=secret-key" https://your.host/protected/search?q=testA few things to keep in mind:
-
Keep the debug port private. Bind the debug TPS to localhost (or an
internal interface) and never publish it directly. The only way in should be
through Caddy, which is what enforces the cookie gate. Treat
secret-keyas an actual secret -- anyone who knows it can route themselves to the debug instance. -
Tokens are per-instance. The request budget and IP-switch state live in
each instance's memory, so a session that bounces between
:18888and:18889is tracked separately on each. If you want a token solved on one instance to be accepted by the other (so flipping the cookie on/off doesn't force a fresh challenge), give both instances the sameJWT_SIGNING_KEYand matchingTOKEN_BIND_*settings. If you want them fully independent, give them different signing keys. -
It's just a router. TPS doesn't know about the
debug-tpscookie at all; Caddy makes the routing decision and TPS only ever sees the request that was forwarded to it. You can use any cookie name and value you like, as long as the matcher and the cookie you set agree.
The most browser-agnostic way to set the cookie is from the dev-tools
JavaScript console (usually F12, then the "Console" tab) while you're on the
protected site — cookies are scoped to the site's domain, so you have to be on
it. Paste a line like:
document.cookie = "debug-tps=secret-key; path=/; max-age=86400";-
path=/makes the cookie apply to every path on the site (the default would scope it to just the current page's path). -
max-ageis in seconds;86400is one day, so the cookie sticks around instead of vanishing when you close the tab. Usemax-age=0to delete it when you're done debugging. - If your protected content spans subdomains, add
; domain=.example.comto cover them all.
This works the same in every major browser and in private/incognito windows (just re-run it for that session). Reload the page after setting the cookie.