Skill in deployment
proxy-client-address
Forward the real client address from a server-side proxy to a backend without trusting forgeable headers. Use when an API behind a BFF or reverse proxy rate-limits or audits every user as one address.
- Arguments
- (optional) the front-end proxy file and the backend's middleware
Install
As a plugin
Bundled in the deploy plugin. Add the marketplace once, then install the bundle; it updates with the marketplace.
/plugin marketplace add KhaledSaeed18/dotclaude/plugin install deploy@dotclaudeAs a single item
Run from the project root; the skill lands under .claude/. Copy it to ~/.claude/ to make it global.
npx shadcn@latest add KhaledSaeed18/dotclaude/proxy-client-addressFiles installed
.claude/skills/proxy-client-address/SKILL.md.claude/skills/proxy-client-address/reference/snippets.md
What it does
When a browser calls a front-end server that forwards to an API, the API's peer is the front-end for every user: one rate-limit bucket and one audit address for everyone. Fix it with a named address the API believes only next to a shared secret, derived from the one forwarded header the edge proxy wrote itself.
Hard rules: never break these
- Never trust
X-Forwarded-Forfrom the client side. Only the entry the edge proxy appended is real; confirm which entry that is for the proxy in front of you before relying on it. - The secret is runtime, server-only, identical on both sides, generated by the owner (
openssl rand -base64 32), pasted into both deployments, never in a repository or a client bundle. - Strip the headers on the way in. The front-end deletes any
x-<app>-proxy-secretorx-<app>-client-ipa browser sent before setting its own; the API deletes both after reading them. - Compare the secret in constant time on digests, so length and content leak nothing.
- Without the secret, behave as before. The front-end falls back to the plain rewrite; the API falls back to
req.ip. Rollout is safe in any order.
Step 1: Establish the proxy's behaviour
Read the edge proxy's configuration (Traefik: docker inspect coolify-proxy --format '{{json .Args}}' | grep -i forwarded). With no trusted IPs configured, Traefik discards client-sent X-Forwarded-* and writes the peer address itself, so the last entry is the client; a platform edge behaves the same. If trusted IPs or insecure are set, the client's forged entries survive in front of the real one and the last entry is still the real one. A Node server does not append. Document the finding.
Step 2: Front-end side (the BFF)
In the Next.js proxy (or middleware), for /api/* requests: when the secret is configured, rewrite to the API origin with two added request headers, else return nothing and let next.config rewrites handle it. Server-side fetches (Server Components) add the same headers from next/headers. Snippets in reference/snippets.md.
Step 3: API side
A middleware early in the chain: read both headers, delete them, verify the presented secret against the configured one on SHA-256 digests with timingSafeEqual, accept the named address only if it is a valid IP, else use req.ip. Store the result on the request (req.clientIp) and make the rate limiter's key generator and the audit writer read it. trust proxy stays set for req.ip to be meaningful behind the edge.
Step 4: Roll out and prove it
- Ship both code sides (they are inert without the secret).
- Owner sets
API_PROXY_SECRETon the front-end app andDASHBOARD_PROXY_SECRET(or the chosen name) on the API, same value, then redeploys both. - Prove it: a request through the front-end to a non-existent API route with a forged
X-Forwarded-For: 203.0.113.9, from two different networks, must be logged by the API with each real address; the same forged header plus a wrong secret sent straight to the API must be logged with the sender's address. Thedeploy-verificationskill has the commands.
Report the proxy finding, the header names chosen, the variable names on each side, and the proof lines from the API log.
This is the skill as installed, rendered from its source on GitHub. Read it as Markdown.
More in deployment
- coolify-image-appCreate and configure a Coolify application that runs a prebuilt image from a registry. Use when adding an app to Coolify, fixing its health check...
- coolify-vps-baselinePrepare a Linux VPS to run production containers under Coolify. Use when setting up a new server, auditing an existing one, or connecting a registry...
- deploy-verificationProve a deployment from the server side. Use when a deploy finished and needs sign-off, when a rolling update may have dropped requests, or when a proxy...
- express-prisma-coolify-imagePackage an Express and Prisma API as a runtime-only image that migrates its Postgres database at start. Use when containerising a Node API with a...
- ghcr-coolify-pipelineWrite the single GitHub Actions workflow that takes a repository from pull request to production through GHCR and Coolify. Use when adding deployment to a...
- live-domain-cutoverMove a live domain from one host to another without downtime or lost sessions, with a rehearsal, a timed DNS switch, a soak and the old host removed. Use...