> ## Documentation Index
> Fetch the complete documentation index at: https://verifyngo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# verifyngo config.json: all fields, types, and defaults

> Every field accepted by verifyngo's config.json, with types, default values, and plain-English descriptions of what each setting does.

This page lists every field recognised in `config.json`. Fields marked **required** have no default and must be set before verifyngo will start. All duration values use Go's duration string format: `"30s"`, `"10m"`, `"2h"`, `"168h"` (7 days).

***

## Core

| Field            | Type       | Default         | Description                                                                                                                                                   |
| ---------------- | ---------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `listen_addr`    | `string`   | —               | Address and port verifyngo listens on, e.g. `"127.0.0.1:8080"`.                                                                                               |
| `upstream_url`   | `string`   | **required**    | Base URL of the backend that verifyngo proxies to, e.g. `"http://127.0.0.1:8886"`.                                                                            |
| `cookie_secret`  | `string`   | **required**    | Secret used to sign the verification cookie. Must stay constant across restarts or all existing cookies become invalid. Generate with `openssl rand -hex 32`. |
| `cookie_name`    | `string`   | `"cp_verified"` | Name of the verification cookie set in the visitor's browser.                                                                                                 |
| `cookie_ttl`     | `duration` | `"168h"`        | How long a solved CAPTCHA cookie is valid. Default is 7 days.                                                                                                 |
| `default_action` | `string`   | `"challenge"`   | What to do when no rule matches. Accepted values: `"challenge"`, `"allow"`, `"deny"`.                                                                         |

***

## IP Trust

| Field             | Type       | Default | Description                                                                                                                                                                                |
| ----------------- | ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `trust_real_ip`   | `bool`     | `false` | When `true`, verifyngo reads the visitor IP from `X-Forwarded-For` instead of the TCP connection.                                                                                          |
| `trusted_proxies` | `[]string` | `[]`    | List of IP addresses or CIDR ranges whose `X-Forwarded-For` headers are trusted. Only used when `trust_real_ip` is `true`. If omitted, only loopback and RFC-1918 ranges are auto-trusted. |
| `whitelist`       | `[]string` | `[]`    | IP addresses or CIDR ranges that always bypass all checks and are never challenged.                                                                                                        |

***

## Paths

| Field               | Type       | Default   | Description                                                                                                                                                                                                                 |
| ------------------- | ---------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `bypass_paths`      | `[]string` | See below | Regex patterns matched against the request path. Matching requests are never challenged. Defaults to a built-in list covering common static assets (see below). Set to `null` (omit the field) to restore the default list. |
| `always_pass_paths` | `[]string` | `[]`      | Regex patterns for paths that are always proxied upstream unconditionally, even if the visitor is banned. Useful for health-check endpoints.                                                                                |
| `static_dir`        | `string`   | `""`      | Path prefix for verifyngo's own built-in static assets (challenge page resources).                                                                                                                                          |
| `rules_file`        | `string`   | `""`      | Path to an external rules file. Hot-reloaded every \~10 seconds.                                                                                                                                                            |
| `policy_file`       | `string`   | `""`      | Path to an external policy file (ASN-based rules). Hot-reloaded every \~10 seconds. If both `rules_file` and `policy_file` are set, `policy_file` takes priority and is the only file watched for changes.                  |

**Default `bypass_paths` list**

When `bypass_paths` is not set in `config.json`, verifyngo uses the following patterns:

```text theme={null}
^/favicon\.ico$
^/robots\.txt$
^/sitemap\.xml$
^/\.well-known/
^/(?:manifest\.json|site\.webmanifest|manifest\.webmanifest)$
\.webmanifest$
^/browserconfig\.xml$
^/apple-touch-icon(?:-precomposed)?(?:-\d+x\d+)?\.png$
\.(?:css|js|mjs|png|jpe?g|gif|svg|webp|avif|ico|woff2?|ttf|otf|eot|wasm|mp4|webm)$
```

***

## CAPTCHA

### Provider selection

| Field      | Type     | Default      | Description                                                                           |
| ---------- | -------- | ------------ | ------------------------------------------------------------------------------------- |
| `provider` | `string` | **required** | Which CAPTCHA provider to use. Accepted values: `"cap"`, `"turnstile"`, `"hcaptcha"`. |

### `cap` (self-hosted Cap)

| Field                   | Type     | Default | Description                                                                                                                                               |
| ----------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cap.api_url`           | `string` | `""`    | Public URL of the Cap instance, shown to the visitor's browser, e.g. `"https://captcha.example.com"`.                                                     |
| `cap.verify_url`        | `string` | `""`    | Internal URL used by verifyngo to verify tokens server-side, e.g. `"http://127.0.0.1:3000"`. Must be reachable by the verifyngo process, not the browser. |
| `cap.site_key`          | `string` | `""`    | Cap site key.                                                                                                                                             |
| `cap.secret_key`        | `string` | `""`    | Cap secret key used for server-side verification.                                                                                                         |
| `cap.widget_script_url` | `string` | `""`    | Override URL for the Cap widget script. Leave empty to use the default from `api_url`.                                                                    |

### `turnstile` (Cloudflare Turnstile)

| Field                  | Type     | Default | Description                                             |
| ---------------------- | -------- | ------- | ------------------------------------------------------- |
| `turnstile.site_key`   | `string` | `""`    | Turnstile site key from the Cloudflare dashboard.       |
| `turnstile.secret_key` | `string` | `""`    | Turnstile secret key used for server-side verification. |

### `hcaptcha`

| Field                 | Type     | Default | Description                                            |
| --------------------- | -------- | ------- | ------------------------------------------------------ |
| `hcaptcha.site_key`   | `string` | `""`    | hCaptcha site key.                                     |
| `hcaptcha.secret_key` | `string` | `""`    | hCaptcha secret key used for server-side verification. |

***

## Walk-away & Ban

Walk-away tracking counts how many times a visitor abandons the challenge page without solving it. When the threshold is exceeded the visitor is banned.

| Field                | Type       | Default | Description                                                  |
| -------------------- | ---------- | ------- | ------------------------------------------------------------ |
| `walkaway.threshold` | `int`      | `10`    | Number of walk-aways before the visitor's IP is banned.      |
| `walkaway.ttl`       | `duration` | `"2h"`  | How long a walk-away counter entry lives before it is reset. |
| `ban.duration`       | `duration` | `"24h"` | How long a banned IP remains banned.                         |

***

## Progressive

Progressive mode observes traffic passively on specified paths before deciding to challenge. Visitors who exceed `max_requests` within `request_window` are challenged.

| Field                        | Type       | Default | Description                                                                                                                                  |
| ---------------------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `progressive.enabled`        | `bool`     | `false` | Enable progressive challenge mode.                                                                                                           |
| `progressive.passive_paths`  | `[]string` | `[]`    | Regex patterns for paths observed in passive mode. Requests to these paths increment the counter without immediately triggering a challenge. |
| `progressive.passive_ttl`    | `duration` | `"30m"` | How long a passive observation window entry lives.                                                                                           |
| `progressive.max_requests`   | `int`      | `50`    | Number of requests within `request_window` that triggers a challenge.                                                                        |
| `progressive.request_window` | `duration` | `"10m"` | Sliding window duration for counting requests.                                                                                               |

***

## Store

The store holds ban state, walk-away counters, and progressive counters.

| Field           | Type     | Default    | Description                                                        |
| --------------- | -------- | ---------- | ------------------------------------------------------------------ |
| `store.backend` | `string` | `"memory"` | Storage backend. Accepted values: `"memory"`, `"file"`, `"redis"`. |

### `store.file` (file backend)

| Field                      | Type       | Default | Description                                       |
| -------------------------- | ---------- | ------- | ------------------------------------------------- |
| `store.file.path`          | `string`   | `""`    | Path to the JSON file used to persist store data. |
| `store.file.save_interval` | `duration` | `"30s"` | How often the in-memory state is flushed to disk. |

### `store.redis` (Redis backend)

| Field                    | Type     | Default            | Description                                      |
| ------------------------ | -------- | ------------------ | ------------------------------------------------ |
| `store.redis.addr`       | `string` | `"127.0.0.1:6379"` | Address of the Redis server.                     |
| `store.redis.password`   | `string` | `""`               | Redis password (leave empty if not set).         |
| `store.redis.db`         | `int`    | `0`                | Redis database index.                            |
| `store.redis.key_prefix` | `string` | `"verifyngo"`      | Prefix applied to all keys written by verifyngo. |

***

## ASN

ASN lookups power policy-file rules that match on autonomous system numbers or organisation names.

| Field               | Type       | Default               | Description                                                                                                                                                |
| ------------------- | ---------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `asn.geoip_db_path` | `string`   | `""`                  | Path to a MaxMind GeoLite2-ASN `.mmdb` file. Required for ASN-based rules when whois is disabled.                                                          |
| `asn.whois_enabled` | `bool`     | `true`                | Use WHOIS to resolve ASN information at startup.                                                                                                           |
| `asn.whois_addr`    | `string`   | `"whois.radb.net:43"` | WHOIS server address used for lookups.                                                                                                                     |
| `asn.whois_timeout` | `duration` | `"30s"`               | Timeout for each WHOIS query.                                                                                                                              |
| `asn.whois_strict`  | `bool`     | `false`               | When `true`, a WHOIS timeout or error during startup is treated as fatal and verifyngo will exit. When `false`, a warning is logged and startup continues. |

***

## AbuseIPDB

When enabled, verifyngo reports banned IPs to [AbuseIPDB](https://www.abuseipdb.com/) after they have been banned a configurable number of times.

| Field                         | Type     | Default | Description                                                                  |
| ----------------------------- | -------- | ------- | ---------------------------------------------------------------------------- |
| `abuseipdb.enabled`           | `bool`   | `false` | Enable AbuseIPDB reporting.                                                  |
| `abuseipdb.api_key`           | `string` | `""`    | Your AbuseIPDB API key.                                                      |
| `abuseipdb.categories`        | `string` | `""`    | Comma-separated AbuseIPDB category IDs to attach to reports, e.g. `"19,21"`. |
| `abuseipdb.comment`           | `string` | `""`    | Comment included with each report.                                           |
| `abuseipdb.report_after_bans` | `int`    | `3`     | Number of bans an IP must accumulate before it is reported.                  |

***

## Branding

All branding fields are optional. They customise the appearance of the challenge page shown to visitors.

| Field                       | Type     | Default        | Description                                                                  |
| --------------------------- | -------- | -------------- | ---------------------------------------------------------------------------- |
| `branding.logo_url`         | `string` | `""`           | URL of a logo image displayed on the challenge page.                         |
| `branding.css_url`          | `string` | `""`           | URL of a custom stylesheet that overrides the default challenge page styles. |
| `branding.accent_color`     | `string` | `"#4A90D9"`    | Primary accent colour used for buttons and highlights.                       |
| `branding.background_color` | `string` | `"#000000"`    | Challenge page background colour.                                            |
| `branding.text_color`       | `string` | `"#f2f2f2"`    | Challenge page body text colour.                                             |
| `branding.font_family`      | `string` | `"sans-serif"` | CSS `font-family` value applied to the challenge page.                       |
| `branding.font_url`         | `string` | `""`           | URL of a web font stylesheet to load (e.g. a Google Fonts URL).              |
| `branding.title`            | `string` | `""`           | Site name shown in the challenge page heading.                               |
| `branding.details_text`     | `string` | See below      | Explanatory paragraph shown beneath the CAPTCHA widget.                      |
| `branding.contact_url`      | `string` | `""`           | URL linked from a "contact us" prompt on the challenge page.                 |

**Default `branding.details_text`**

```text theme={null}
This page runs a quick, one-time check to confirm you're a real visitor and
not an automated bot. It only takes a moment, and once you've solved it you
won't see this again for a while.
```

***

<Accordion title="Full example config.json">
  ```json theme={null}
  {
    "listen_addr": "127.0.0.1:8080",
    "upstream_url": "http://127.0.0.1:8886",
    "cookie_secret": "CHANGE_ME_openssl_rand_hex_32",
    "cookie_name": "cp_verified",
    "cookie_ttl": "168h",
    "provider": "cap",
    "cap": {
      "api_url": "https://captcha.example.com",
      "verify_url": "http://127.0.0.1:3000",
      "site_key": "your-cap-site-key",
      "secret_key": "your-cap-secret-key",
      "widget_script_url": ""
    },
    "turnstile": {
      "site_key": "",
      "secret_key": ""
    },
    "hcaptcha": {
      "site_key": "",
      "secret_key": ""
    },
    "trust_real_ip": false,
    "trusted_proxies": [],
    "static_dir": "/static",
    "rules_file": "/rules.txt",
    "policy_file": "",
    "always_pass_paths": ["^/health$", "^/healthz$", "^/status$"],
    "asn": {
      "geoip_db_path": "",
      "whois_enabled": true,
      "whois_addr": "whois.radb.net:43",
      "whois_timeout": "30s",
      "whois_strict": false
    },
    "store": {
      "backend": "memory",
      "file": {
        "path": "/data/store.json",
        "save_interval": "30s"
      },
      "redis": {
        "addr": "redis:6379",
        "password": "",
        "db": 0,
        "key_prefix": "verifyngo"
      }
    },
    "progressive": {
      "enabled": false,
      "passive_paths": [
        "^/$",
        "/this-specific-path"
      ],
      "passive_ttl": "30m",
      "max_requests": 50,
      "request_window": "10m"
    },
    "branding": {
      "logo_url": "/static/logo.svg",
      "css_url": "/static/custom.css",
      "title": "My Website",
      "accent_color": "#444444",
      "background_color": "#000000",
      "text_color": "#f2f2f2",
      "font_family": "'My Font', sans-serif",
      "font_url": "",
      "details_text": "This page runs a quick, one-time check to confirm you're a real visitor and not an automated bot. It only takes a moment, and once you've solved it you won't see this again for a while.",
      "contact_url": "mailto:contact@example.com"
    },
    "whitelist": [
      "203.0.113.10",
      "198.51.100.0/24"
    ],
    "default_action": "challenge",
    "rules": [
      {
        "match": { "path": "^/api/" },
        "action": "allow"
      },
      {
        "match": { "ua": "python-requests|curl/|Go-http-client" },
        "action": "deny"
      },
      {
        "match": { "cidr": ["185.220.0.0/16"] },
        "action": "deny"
      },
      {
        "match": { "path": "^/search" },
        "action": "challenge"
      }
    ],
    "walkaway": {
      "threshold": 10,
      "ttl": "2h"
    },
    "ban": {
      "duration": "24h"
    },
    "abuseipdb": {
      "enabled": false,
      "api_key": "",
      "categories": "19,21",
      "comment": "verifyngo: exceeded walk-away threshold",
      "report_after_bans": 3
    }
  }
  ```
</Accordion>
