Caddy v2 Plugin (Zero-Code)
The official Caddy v2 plugin for Hansestack enables Decoupled Security: You can attach the k-Anonymity leak check directly to your reverse proxy without touching a single line of code in your backend.
The plugin intercepts requests, securely checks contained passwords, and enriches the request or response with the outcome. Your backend never has to import a client library or call an API.
Resources & Hands-on
- 🐙 Source Code: Find the source code, releases, and issue tracker in the caddy-hansestack repository.
- 👾 Try the Sandbox: Want to see the plugin in action? Clone our Demo Repo, type
docker-compose up, and watch the provided Grafana dashboard to see exactly how the leak check (and the fail-open fallback) performs under load.
Installation
There are two ways to deploy the plugin in your infrastructure.
Option A: Build with xcaddy (Recommended)
If you build your own Caddy binaries, use xcaddy:
xcaddy build --with github.com/hansestack/caddy-hansestackOption B: Pre-built Docker Image
We provide a pre-built Docker image based on the official Caddy image:
# docker-compose.yml
services:
caddy:
image: ghcr.io/hansestack/caddy-hansestack:latest
ports:
- "80:80"
- "443:443"(Tip: In production, pin a specific version instead of :latest, e.g. :v1.0.0)
Configuration (Caddyfile)
Configuration is handled natively via the Caddyfile. The plugin registers itself to always run before the reverse_proxy directive in Caddy's execution order.
:443 {
hansestack /login* leakcheck {
api_key {$HANSESTACK_API_KEY}
mode enrich_response
password_field "password"
# Optional circuit breaker tuning for high resilience
timeout 500ms
circuit_breaker_threshold 5
circuit_breaker_cooldown 30s
}
reverse_proxy backend:8080
}Configuration Directives
| Directive | Default | Description |
|---|---|---|
api_key | (Required) | Your Hansestack API key. (Use {$ENV_VAR} to inject via env variables). |
mode | enrich_request | Execution mode: enrich_request, enrich_response or block. |
password_field | password | The key in the JSON or form-data body holding the password. |
header_leaked | X-Hansestack-Leaked | Header containing the result (true/false). |
header_count | X-Hansestack-Leak-Count | Header containing the number of breach occurrences. |
block_status | 401 | HTTP status code returned when mode=block triggers. |
timeout | 500ms | Maximum wait time for the API call (fail-open takes over after this). |
circuit_breaker_threshold | disabled (0) | Number of consecutive failures before the breaker trips. |
circuit_breaker_cooldown | 30s | How long the circuit stays open, locally skipping checks instantly. |
Operation Modes
Depending on your auth flow architecture, the plugin offers three modes:
enrich_response(Recommended): Asynchronous. The leak check runs concurrently with your backend processing. It adds zero latency to your login. The leak headers are injected into the outgoing response back to the client.
sequenceDiagram
participant C as Client
participant P as Caddy (Plugin)
participant B as Your Backend
participant H as Hansestack API
C->>P: POST /login (Credentials)
par Asynchronous Leak-Check
P->>H: Send Hash Prefix
H-->>P: Suffix List (No Leak)
and Normal Login Flow
P->>B: POST /login (Original Body)
Note over B: Backend verifies Login
B-->>P: HTTP 201 (Session Token)
end
P-->>C: HTTP 201 + X-Hansestack-Leaked Header
enrich_request: Synchronous. Waits for the API (maxtimeout) and injects the leak headers into the incoming request. Your backend can read these headers and decide how to act.block: Synchronous. The only mode capable of rejecting a request. Only if a leak is affirmatively confirmed will Caddy short-circuit the request and return e.g. HTTP 401. Your backend is never invoked in this scenario.
In all modes: In case of API timeouts, rate limits, or network errors, the request is always passed through unmodified. A disruption in the leak check service will never lock your legitimate users out of their accounts.
Metrics (Prometheus)
If you enable Caddy's global metrics option, the plugin exposes its own metrics on the admin endpoint. These are perfect for Grafana dashboards to visualize credential stuffing attacks:
hansestack_leakcheck_checks_total{result="leaked|not_leaked"}hansestack_leakcheck_check_outcomes_total{outcome="..."}(Details whether a check succeeded or a timeout/circuit breaker intervened)hansestack_leakcheck_check_errors_total