Skip to main content

Reverse Proxy

In production, Sentinel typically runs behind a reverse proxy, CDN, API gateway, or load balancer — nginx and Cloudflare are common choices. Getting client IP and header forwarding right matters here, since Sentinel's detection features depend on them.

Public vs. internal endpoints

Sentinel serves the web dashboard, the full management API, and the widget-facing endpoints from the same origin — but only two need to be reachable from the public internet, since they're called directly by the browser:

  • /v1/challenge (including /v1/challenge/audio/{token}) — issues challenges to the <altcha-widget>.
  • /v1/verify — verifies the solved challenge the widget submits.

Everything else should be reachable only from your internal network or VPN — the dashboard, /v1/docs, and the management API (/v1/accounts, /v1/users, /v1/admin/*, /v1/security-groups, and so on). Restrict it at the reverse proxy rather than relying on authentication alone; it keeps credential-stuffing and scanning traffic off the admin surface entirely.

/v1/verify/signature depends on who calls it: it verifies the server signature from a POST /v1/verify payload, and that call is always server-to-server, never from the browser. Keep it internal-only if the services doing that verification all live on your internal network. Expose it publicly only if an external service — a form handler or backend outside your network — needs to call it directly to verify a signature.

Forwarding the client IP

Sentinel reads the client IP from the standard X-Forwarded-For header. Set X_FORWARDED_FOR_TRUSTED to your proxy's IP addresses so Sentinel only trusts X-Forwarded-For values coming from a proxy you actually control — values from any other source are rejected, preventing a client from simply spoofing the header itself.

X_FORWARDED_FOR_TRUSTED=10.0.0.1,10.0.0.2

See ENV Variables and IP Resolvers.

Forwarding headers

Forward all client request headers where feasible. At minimum, these feed Sentinel's browser/platform/device detection and shouldn't be stripped by your proxy:

  • Accept
  • Accept-Language
  • Sec-CH-UA
  • Sec-CH-UA-Mobile
  • Sec-CH-UA-Platform
  • User-Agent

Dropping these reduces the accuracy of Detection Signals like header entropy and language detection.

Preserving the response

/v1/challenge and /v1/verify both return application/json — the <altcha-widget> parses that response directly, so the proxy must leave it alone on the way back:

  • Forward the Content-Type response header as-is, or set it to application/json yourself if your proxy or gateway strips/rewrites it (some do, especially API gateways with a default content-type policy). A missing or wrong Content-Type can make the widget — or an intermediate cache/WAF — treat the body as something other than JSON.
  • Return the JSON body byte-for-byte, without modification. No reformatting, minifying, key reordering, compression that isn't transparently reversed, or WAF/gateway "response sanitization" — any of that can invalidate the signed challenge/verification payload or simply fail to parse. Treat these two endpoints as pass-through, not something to be transformed in flight.
  • Forward Sentinel's own cache-control headers (Cache-Control) unmodified rather than letting the proxy or CDN apply its own caching policy. Every /v1/challenge response is single-use and every /v1/verify response is specific to one solve — a proxy or edge cache serving either from cache hands out a stale or already-consumed challenge/result, breaking verification for whoever gets the cached copy.

Start typing to search...

Navigate Select