Securing Paddock
The threat model, briefly
Section titled “The threat model, briefly”A Paddock keeper is a real Claude Code session with tools. Someone who reaches an unprotected instance can make it execute code, spend your Anthropic budget, exfiltrate whatever the box can see, and push to any repo its token allows. “It’s only on my LAN” is not a defense — other devices, guests, and compromised IoT gadgets share that LAN.
So there are two jobs, and you should do both:
- Limit who can reach it on the network.
- Authenticate every request that does reach it.
1. Limit reachability
Section titled “1. Limit reachability”- Don’t expose it to the internet unless you have a real reason. The safest setup is Paddock bound to localhost/LAN and reached over a VPN or overlay network (WireGuard, Tailscale, etc.).
- If you do publish it, publish only the reverse proxy, never Paddock’s port.
- Note: Paddock’s built-in dev/preview servers (the
pm-managed ports agents use to show you a running app) bypass Paddock’s own request handling — keep those ports LAN-only or behind the same auth, and never expose them directly.
2. Authenticate every request
Section titled “2. Authenticate every request”Paddock is designed to sit behind an authenticating reverse proxy and read the
identity that proxy establishes. It has three auth modes (set with
PADDOCK_AUTH_MODE; full details in Authentication):
| Mode | What it does | Use when |
|---|---|---|
none (default) | No identity check at all | Only if Paddock is fully isolated (VPN-only) and you still add a proxy password |
trusted-header | Trusts an identity header (e.g. X-Authentik-Username) set by your proxy | Your proxy authenticates the user and injects a header |
jwt | Verifies a signed JWT from your identity provider against a JWKS URL | You run an SSO/IdP and want Paddock to validate tokens itself (strongest) |
The key rule for trusted-header: it is only as safe as your proxy. The proxy must
authenticate the user and overwrite (never pass through) the identity header, and
Paddock must be reachable only via that proxy — otherwise anyone can forge the
header.
The simplest thing that’s safe: Caddy + a password
Section titled “The simplest thing that’s safe: Caddy + a password”Even at home, put a password in front. Caddy makes this a few lines and gives you automatic HTTPS:
paddock.example.com { basic_auth { # generate the hash with: caddy hash-password you $2a$14$…bcrypt-hash… } reverse_proxy localhost:4000}That’s the floor, not the ceiling: HTTP basic auth is a single shared password with no MFA and no per-user accounts. It’s fine for a solo user on a private network; it is not how you’d protect anything shared or exposed.
Better: single sign-on in front (how the author does it)
Section titled “Better: single sign-on in front (how the author does it)”For real accounts, MFA, and one login across many self-hosted apps, put an SSO
provider in front — Authentik or
Authelia — and have Caddy delegate auth to it with
forward_auth. The author runs Authentik as a shared IdP and fronts every app
(Paddock included) with it:
paddock.example.com { # Hand every request to the SSO outpost first… reverse_proxy /outpost.goauthentik.io/* authentik-outpost:9000 forward_auth authentik-outpost:9000 { uri /outpost.goauthentik.io/auth/caddy # …and copy the identity it establishes onto the request. copy_headers X-Authentik-Username X-Authentik-Email X-Authentik-Groups X-Authentik-Jwt } reverse_proxy localhost:4000}Then point Paddock at that identity. Two options:
- Trusted header — simplest:
Terminal window PADDOCK_AUTH_MODE=trusted-headerPADDOCK_AUTH_USER_HEADER=X-Authentik-Username - JWT — strongest; Paddock verifies the SSO-signed token itself, so a
misconfigured proxy can’t spoof a user:
Terminal window PADDOCK_AUTH_MODE=jwtPADDOCK_AUTH_JWT_HEADER=X-Authentik-JwtPADDOCK_AUTH_JWKS_URL=https://sso.example.com/application/o/paddock/jwks/
With SSO you get per-user accounts, MFA, and — if you run several apps — one login for all of them. Because Paddock captures the authenticated user, this is also what makes its per-user features (like read-state) meaningful.
Protect the secrets too
Section titled “Protect the secrets too”Security isn’t only the front door — it’s also what the agents can reach:
- Keep
CLAUDE_CODE_OAUTH_TOKEN/ANTHROPIC_API_KEYand anyghtoken in the environment or a secrets file, never committed to a repo. - Scope GitHub tokens to the minimum — a fine-grained PAT limited to just the repos that instance should touch. If the box is ever compromised, that’s the blast radius.
- Prefer delivering secrets at runtime (from a secrets manager into
/run, tmpfs) over baking them into images or.envfiles on disk. See A home-lab setup.
Checklist
Section titled “Checklist”- Paddock’s port is not on a public interface — only the proxy is.
- There is an auth layer (password at minimum; SSO ideally) on every path.
-
PADDOCK_AUTH_MODEmatches how your proxy establishes identity. -
trusted-header: the proxy sets/overwrites the header and is the only route in. - Preview/
pmports are LAN-only or behind the same auth. - Tokens are scoped-minimal and never committed.