Every visitor is challenged, even after solving the CAPTCHA
Every visitor is challenged, even after solving the CAPTCHA
If visitors keep seeing the challenge page after solving it, the problem is almost always with the verification cookie.
-
cookie_secretchanged. Ifcookie_secretis different from the value used when the cookie was issued, verifyngo rejects the cookie as invalid. Make surecookie_secretis the same value across every restart and config reload. If you rotated it intentionally, visitors simply need to solve the challenge once more. -
cookie_namechanged. If you renamedcookie_namebetween config reloads, the browser is still sending the old cookie name — verifyngo won’t recognise it. Ensure the name is consistent, or instruct visitors to clear their cookies. -
Cookie domain or path mismatch. If the browser is sending the cookie but verifyngo isn’t reading it, check that the domain the visitor uses matches where the cookie was set. This can happen when you have multiple subdomains or when the proxy strips the
Cookieheader.
verifyngo is seeing the wrong IP (e.g. the proxy's IP instead of the visitor's IP)
verifyngo is seeing the wrong IP (e.g. the proxy's IP instead of the visitor's IP)
By default, verifyngo uses the TCP connection’s remote address as the visitor IP. When verifyngo sits behind a reverse proxy (nginx, Caddy, a load balancer), that address is the proxy’s IP — not the visitor’s.
- Set
"trust_real_ip": trueinconfig.json. - Add your reverse proxy’s IP address or CIDR range to
trusted_proxies, for example: - Confirm your reverse proxy is forwarding
X-Forwarded-For. Most do this by default, but double-check your proxy configuration.
trust_real_ip is enabled, verifyngo reads the first IP address from the X-Forwarded-For header sent by a trusted proxy. If trusted_proxies is omitted, verifyngo only trusts X-Forwarded-For from connecting addresses that are loopback or RFC-1918 private. If your proxy connects from a public IP, you must add it to trusted_proxies explicitly, otherwise verifyngo will ignore the X-Forwarded-For header and fall back to the direct connection address.Rules or policy changes aren't being picked up
Rules or policy changes aren't being picked up
verifyngo hot-reloads file-based rules and policies, but there are a few things that can prevent changes from taking effect.
-
Wait a moment. Changes to
rules_fileorpolicy_fileare detected on a ~10-second polling interval. If you just saved the file, wait up to 10 seconds and try again. -
policy_filetakes priority overrules_file. If both are set, onlypolicy_fileis used and watched for changes. Updates torules_filewill be ignored whilepolicy_fileis configured. -
Check for parse errors. If the file contains a syntax or compile error, verifyngo keeps the previous valid rules active and logs a
parse/compile errormessage. Check your verifyngo log output for that message, fix the file, and the reload will retry automatically. -
Inline rules require a restart. Rules written directly in the
"rules"array insideconfig.jsonare only loaded at startup. Only file-based rules (rules_file,policy_file) support hot-reload without a restart.
The CAPTCHA isn't verifying (visitor solves it but keeps getting challenged)
The CAPTCHA isn't verifying (visitor solves it but keeps getting challenged)
When a visitor solves the CAPTCHA but verifyngo still challenges them, the server-side token verification is failing.
-
Check the logs first. Look for
verify errororverify failedin verifyngo’s output. The error message usually tells you exactly what went wrong (HTTP error, network timeout, invalid secret, etc.). -
Cap (
provider: "cap"): Make surecap.verify_urlpoints to the internal address your Cap instance listens on, not its public URL. Token verification is performed server-side by verifyngo, soverify_urlmust be reachable from the verifyngo process itself (e.g.http://127.0.0.1:3000), not from the visitor’s browser.cap.api_urlis the public URL shown to the browser — these are two separate fields. -
Turnstile / hCaptcha: Make sure
secret_keyis correct. A common mistake is swapping the site key and the secret key — only the secret key is used server-side. -
Network / firewall. Check that verifyngo can reach the verify endpoint. If you’re running in a container or behind strict firewall rules, the verification request may be blocked. Test with
curlfrom the verifyngo host.
Static assets are being challenged
Static assets are being challenged
If CSS, JavaScript, images, or fonts are being intercepted by the challenge page,
bypass_paths may not be covering them.-
Default list is already broad. By default, verifyngo bypasses requests matching common static-asset extensions (
.css,.js,.png,.jpg,.gif,.svg,.webp,.avif,.ico,.woff,.woff2,.ttf,.otf,.eot,.wasm,.mp4,.webm) as well as/favicon.ico,/robots.txt,/sitemap.xml, and/.well-known/paths. If you haven’t overriddenbypass_paths, these are already excluded. -
Custom
bypass_pathsoverrides the entire default list. If you setbypass_pathsto a custom array, the built-in defaults are replaced — not merged. Make sure your custom list includes all extensions you need. -
Restore defaults. To go back to the built-in list, remove the
bypass_pathskey fromconfig.jsonentirely (or set it tonull).
Visitor is immediately banned without hitting the walk-away threshold
Visitor is immediately banned without hitting the walk-away threshold
If a visitor is blocked before they’ve had a chance to fail enough challenges, they may already be carrying an existing ban.
-
Previous session ban. The visitor may have been banned in an earlier session. With
store.backend: "memory", bans persist until verifyngo restarts. Withstore.backend: "redis"or"file", bans persist across restarts until the TTL expires. -
Check
ban.duration. The default is"24h". If a visitor hit the threshold yesterday, their ban is still active. You can reduceban.durationor manually clear the store (restart verifyngo for the memory backend, or delete the Redis key / file for the persistent backends). -
Check
walkaway.threshold. The default is10. If you lowered this value, visitors may be hitting the threshold faster than expected.
verifyngo fails to start
verifyngo fails to start
If verifyngo exits immediately on startup, the most common causes are a config error, a missing required field, or a WHOIS timeout.
-
JSON syntax error. Look for a
config:prefix in the log output — it’s followed by the specific parse error and usually includes a line/offset hint. Validate yourconfig.jsonwith a JSON linter. -
Missing required fields. verifyngo requires at minimum:
upstream_url,cookie_secret, and a correctly configured provider (with matchingsite_keyandsecret_keyset). If any of these are absent or empty, verifyngo will refuse to start. -
WHOIS timeout with
whois_strict: true. If yourpolicy_filecontains ASN entries andasn.whois_strictistrue, a WHOIS lookup timeout during startup is treated as a fatal error. Set"whois_strict": falseto allow verifyngo to start with a warning instead, and investigate the WHOIS connectivity separately.