# Integration Troubleshooting & FAQ
Source: https://humanymous.net/how-to/troubleshooting-faq.html
Project: humanymous — defensive anti-bot / browser-automation detection (Apache-2.0).
---
# Integration troubleshooting & FAQ
**Diátaxis quadrant:** How-to (FAQ). **Audience:** integrators standing up humanymous Gate for the first time and working through the errors that show up mid-integration.
This page is a symptom → cause → fix reference for the problems you are most likely to hit while wiring humanymous Gate ("Gate" after first mention) in front of your origin. Gate is the reverse-proxy enforcement layer: it terminates TLS, streams the detection bundle into your HTML, scores layers L1–L7 inline, enforces a verdict (ALLOW / CHALLENGE / DENY) at the edge, and writes every decision to a tamper-evident audit log.
Everything below is written against the reference implementation. Some behaviors you might expect from a production install (real certificates, shared fleet state, and more) are intentionally not in the reference — those are called out as prod-delta. For the full boundary, see [Production vs reference](../reference/production-vs-reference.md).
For flags, environment variables, presets, and defaults referenced throughout, see [CLI, config & policy reference](../reference/cli-config-policy.md).
---
## Your browser shows a certificate warning
**Symptom.** You open the edge listener in a browser and get a security warning ("your connection is not private", self-signed / untrusted issuer), or a command-line client refuses the TLS handshake.
**Cause.** The reference implementation serves a self-signed certificate generated in memory. It is not issued by a trusted authority, so browsers and default TLS clients reject it. This is expected in development.
**Fix.** In development, tell your client to skip certificate verification. With `curl`, use `-k`:
```
curl -k https://localhost:8444/
```
For a browser, proceed through the warning (or trust the dev certificate locally). Do not treat the warning as a Gate fault — it is the expected state of the in-memory dev certificate.
> **Note:** Real certificates (ACME / a managed CA) and a real KMS/HSM for key material are prod-delta — the reference does not ship them. Plan certificate issuance as part of your production deployment; see [Production vs reference](../reference/production-vs-reference.md).
---
## Requests come back with HTTP 421
**Symptom.** Some requests to your origin return `421`.
**Cause.** A `421` is hard rule HR-24: a request reached the origin directly, bypassing Gate. Once you set `-origin-key`, Gate signs traffic it forwards with the `X-Hmny-Origin-Auth` header (origin cloaking), and the origin validates that header. A request that arrives without a valid `X-Hmny-Origin-Auth` — that is, one that did not pass through the edge — is rejected with `421`.
**Fix.** Route all client traffic through the Gate edge listener (default `:8444`) rather than letting clients reach the origin (default `:9000`) directly. Confirm:
- `-origin-key` is set to the same value that the origin uses to validate `X-Hmny-Origin-Auth`.
- Your load balancer, DNS, or firewall sends external traffic to the edge, and the origin is only reachable from Gate.
The `-origin-key` value is separate from the sealed keystore; see [Key management, rotation & recovery](./key-management.md) for how it fits alongside the other key material.
---
## The detection bundle is not appearing in my page
**Symptom.** You expected Gate's control-plane script to be injected, but the page source that reaches the browser has no injected `
```
If you see the `` marker but no bundle behavior, the page was injected but the loader may be blocked by your CSP (see [The control plane and the injected bundle](../explanation/control-plane-and-bundle.md)). If you see neither, the response was not treated as HTML, or the head boundary was beyond the 64 KiB look-ahead.
---
## Legitimate users are getting CHALLENGE'd
**Symptom.** Real people hit the proof-of-work (PoW) challenge interstitial when you did not expect them to.
**Cause.** When Gate cannot form a verdict (Unknown), it **fails closed** on strict routes and on all unsafe methods (POST, PUT, PATCH, DELETE) — those requests are challenged rather than passed. This is deliberate: the default policy routes sensitive paths such as `/login`, `/checkout`, and `/admin` to the `strict` preset. It fails open (passes) only for safe `GET`/`HEAD` requests on non-strict routes, a documented, accepted residual covered by fingerprint and subnet rate metering. Some heuristic hard rules can also challenge real people — for example HR-12 (no interaction over the window) is explicitly a heuristic that can catch some humans.
**Fix.**
- Start in monitor mode to observe verdicts without enforcing them, then tune before you enforce. Monitor mode lets you see what *would* be challenged or denied against real traffic first.
- Rely on the PoW upgrade path: a score-based CHALLENGE (one with no hard rule behind it) upgrades to ALLOW once the client solves the proof of work (`l7.pow.solved`). A real human completing the interstitial passes. The PoW upgrade never overrides a hard rule. On an **`attested`** route this bare solve is not enough: the solve must **also** mint a step-up receipt that redeems at `POST /__hmn/stepup` for an `hmn_su` cookie, or the attestation floor keeps pricing the ALLOW back to a Pass (see the FAQ entry below).
- Review which routes are mapped to `strict`. Presets are startup configuration (`Config.Routes`); there is no runtime per-route policy-write endpoint. Adjust the route-to-preset mapping at startup if a route is stricter than you need.
For a fuller treatment of what changes for real users and how to de-risk enforcement, see [Will this break my app?](../explanation/will-this-break-my-app.md).
---
## The Ledger will not authenticate, or returns 404
**Symptom.** The Ledger (or an admin API call) returns `404`, or your bearer token is not accepted.
**Cause.** Two things commonly cause this:
1. **Deny-by-default auth.** Admin authentication is bearer-token, compared in constant time. A missing or invalid token returns `404` (not `401`) — the endpoint does not reveal itself to an unauthenticated caller.
2. **Wrong listener.** The Ledger and the whole admin API live on a **separate admin listener** (default `127.0.0.1:8445` (loopback)) at `/__hmn/admin/`. On the public edge listener, `/__hmn/admin/*` returns `404` by design. If you are calling the admin path on the edge port, you will always get `404`.
**Fix.**
- Use the admin listener. The console is served at `https://localhost:8445/__hmn/admin/console`, and the admin API base is `/__hmn/admin`.
- Present a valid token. If you did not set `HMN_ADMIN_TOKENS`, Gate generates random tokens per boot and prints them at startup — read them from the startup log. To set them yourself, use `HMN_ADMIN_TOKENS`:
```
HMN_ADMIN_TOKENS="auditor:,operator:,approver:,dpo:" bin/gate.exe -addr :8444 -admin-addr :8445
```
- Send the token as a bearer credential, for example:
```
curl -k -H "Authorization: Bearer " https://localhost:8445/__hmn/admin/whoami
```
Every admin access is meta-audited (`admin.access`), and the actor identity is derived by the server from the token — a body-supplied actor is ignored. Role capabilities differ (Auditor / Operator / Approver / DPO); see [RBAC & separation of duties](../reference/rbac-separation-of-duties.md).
---
## "Port already in use" on startup
**Symptom.** Gate fails to bind a listener at boot with an address-in-use error.
**Cause.** A default port is already taken. The reference uses three:
| Listener | Default | Flag |
|----------|---------|------|
| Edge (public) | `:8444` | `-addr` |
| Admin | `:8445` | `-admin-addr` |
| Origin / upstream | `:9000` (as `http://127.0.0.1:9000`) | `-upstream` |
**Fix.** Free the conflicting port, or point the relevant flag at a different one. For example, to move the edge and admin listeners:
```
bin/gate.exe -addr :18444 -admin-addr :18445 -upstream http://127.0.0.1:9000
```
The origin address comes from your `-upstream` target; make sure that host and port are the one your origin app actually listens on.
---
## Keystore boot failure
**Symptom.** Gate exits at startup instead of coming up, when you have configured a keystore.
**Cause.** When `-keystore` is set, the `HMN_UNSEAL` environment variable is **required** — the passphrase opens (or creates) the sealed file. Boot fails if `-keystore` is set and `HMN_UNSEAL` is unset.
**Fix.** Provide the passphrase in the environment alongside the flag:
```
HMN_UNSEAL="" bin/gate.exe -keystore /var/lib/gate/keystore.sealed -addr :8444 -admin-addr :8445
```
> **Warning:** Losing `HMN_UNSEAL` means you cannot open the sealed identity, which is equivalent to a mass cryptographic erasure (crypto-shred) of the linkage it protects. Back the passphrase up out-of-band. See [Key management, rotation & recovery](./key-management.md).
---
## A restart lost all pseudonym linkage, or the verifier public key changed
**Symptom.** After a restart, pseudonyms no longer resolve to the same subjects, and/or the public key your audit-log verifier expects no longer matches.
**Cause.** You are running without a keystore, so the keys are **ephemeral** (held in memory only). On restart, Gate mints a new signing key — so the verifier's expected public key changes — and creates a new vault, so the per-subject pseudonym linkage from before the restart is lost (effectively a mass crypto-shred).
**Fix.** Persist node identity by running with a sealed keystore. Set both `-keystore` and `HMN_UNSEAL`:
```
HMN_UNSEAL="" bin/gate.exe -keystore /var/lib/gate/keystore.sealed -addr :8444 -admin-addr :8445
```
With the keystore, the SigningSeed (Ed25519 STH key), HMACKey, and vault snapshot persist across restarts, so the verifier public key stays stable and pseudonym linkage survives. Full detail — what each key protects, sealing (`scrypt` N=2^15 + AES-256-GCM), and recovery — is in [Key management, rotation & recovery](./key-management.md).
---
## Quick FAQ
**Is the self-signed certificate a bug?** No. The reference generates it in memory; use `curl -k` in development. Real certificates are prod-delta.
**Why `404` instead of `401` from the admin API?** Deny-by-default: a missing or invalid bearer token returns `404` so the admin surface does not announce itself. Check both the token and that you are on the admin listener (`:8445`), not the edge.
**Can I change route policy while Gate is running?** Presets (`off` / `monitor` / `balanced` / `strict` / `attested`) are startup configuration. There is no runtime per-route policy-write endpoint. The runtime levers are the fleet-wide kill switch and the global `-monitor` switch.
**How do I stop enforcement without stopping traffic?** The kill switch demotes hard-rule enforcement to monitor fleet-wide — detection stops and traffic flows, though manually placed bans still enforce. It is dual-control (committed by a distinct Approver).
> **Warning:** The kill switch is fleet-wide. Enabling it stops hard-rule enforcement everywhere Gate runs, not just on one node.
**Why is an ALLOW still challenged on my high-value (`attested`) route?** That is the attestation floor (ceiling-guard #1) doing its job: on an `attested` route a scoring-ALLOW — and even a valid verdict-token fast-path — is priced to a Pass challenge unless the session presents possession or an `hmn_su` step-up proof. The fix is to give humans a way to satisfy the floor: either wire a credential verifier (WebAuthn / Privacy Pass / Web Bot Auth) so possession pre-gates and forwards first, **or** run the Core Pass server and Gate with a **shared `HMN_TOKEN_KEY`** and the same cookie jar so a Pass solve's receipt redeems at `POST /__hmn/stepup` and mints `hmn_su`. Without one of those, humans re-solve the Pass forever — a Pass-for-everyone friction wall. (Note: `attested` also requires the shared `HMN_TOKEN_KEY` across Core and Gate to start at all; the Gate refuses to boot without it.)
**Where do I see what Gate decided?** Observability is the audit stream (`GET /audit`), the Integrity view/endpoint, and the Overview KPIs in the Ledger, plus a Prometheus `GET /__hmn/admin/metrics` gauge snapshot on the admin plane and the `GET /__hmn/healthz` (liveness) / `GET /__hmn/readyz` (readiness) probes answered by Gate itself. Per-verdict rates come from the audit stream; SIEM shipping of that stream is the prod-delta.
---
## Related pages
- [CLI, config & policy reference](../reference/cli-config-policy.md) — flags, environment variables, presets, defaults.
- [Will this break my app?](../explanation/will-this-break-my-app.md) — what enforcement changes for real users, and how to de-risk it.
- [The control plane and the detection bundle](../explanation/control-plane-and-bundle.md) — how injection, the beacon, and `/__hmn/*` work.
- [Key management, rotation & recovery](./key-management.md) — the keystore, `HMN_UNSEAL`, `-origin-key`, and what breaks when key material is lost.
- [Production vs reference](../reference/production-vs-reference.md) — the full prod-delta boundary.