> ## Documentation Index
> Fetch the complete documentation index at: https://proxy-hopper.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Config Reference

> Complete reference for all Proxy Hopper configuration fields.

## Config priority

Settings are resolved in this order (highest wins):

| Priority | Source                                    |
| -------- | ----------------------------------------- |
| 1        | CLI flags (`--port`, `--log-level`, etc.) |
| 2        | `server:` block in the YAML config file   |
| 3        | `PROXY_HOPPER_*` environment variables    |
| 4        | Built-in defaults                         |

## File structure

```yaml theme={}
proxyProviders:   # optional — named proxy suppliers with credentials and region tags
  - ...

ipPools:          # optional — named pools that draw IPs from providers
  - ...

targets:          # required — URL-matching routing rules
  - ...

auth:             # optional — authentication for proxy access
  ...

server:           # optional — all fields have defaults
  ...
```

## Duration values

All duration fields accept a suffix (`1s`, `5m`, `2h`) or a bare integer (seconds):

```yaml theme={}
minRequestInterval: 1s    # one second
maxQueueWait: 30s         # thirty seconds
quarantineTime: 2m        # two minutes
```

***

## proxyProviders

Named groups of external proxy IPs with shared authentication and an optional region tag.
At least one provider is required — IPs are declared here and referenced by pools.

| Field           | Type   | Default              | Description                                                                                                                                                                      |
| --------------- | ------ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`          | string | required             | Unique identifier referenced from `ipPools.ipRequests`                                                                                                                           |
| `auth`          | block  | —                    | Omit for open or IP-whitelisted proxies                                                                                                                                          |
| `auth.type`     | string | `basic`              | Auth type — currently `basic`                                                                                                                                                    |
| `auth.username` | string | required if auth set | Username for HTTP Basic auth                                                                                                                                                     |
| `auth.password` | string | `""`                 | Password for HTTP Basic auth                                                                                                                                                     |
| `ipList`        | list   | required             | Proxy addresses — `host:port` or bare host                                                                                                                                       |
| `regionTag`     | string | —                    | Region label attached to Prometheus metrics                                                                                                                                      |
| `mutable`       | bool   | `true`               | When `false`, the provider cannot be updated or removed via the admin API                                                                                                        |
| `static`        | bool   | `true`               | When `true` (default for YAML-defined providers), the provider is always overwritten from config on startup. Set `false` to allow API mutations while still seeding on first run |

```yaml theme={}
proxyProviders:
  - name: provider-us
    auth:
      type: basic
      username: user
      password: secret
    ipList:
      - "10.0.0.1:3128"
      - "10.0.0.2:3128"
    regionTag: US-East

  - name: provider-open           # no auth — IP whitelisted
    ipList:
      - "10.1.0.1:3128"
    regionTag: EU-West
```

***

## ipPools

Named collections of proxy IPs referenced by targets. Pools decouple the IP list from the target config — multiple targets can reference the same pool while maintaining independent rotation state.

```yaml theme={}
ipPools:
  - name: pool-name
    ipRequests:              # draw IPs from providers
      - provider: name
        count: 5
```

### ipPools fields

| Field        | Type   | Default  | Description                                                                                         |
| ------------ | ------ | -------- | --------------------------------------------------------------------------------------------------- |
| `name`       | string | required | Unique identifier referenced from `targets[].ipPool`                                                |
| `ipRequests` | list   | required | One or more provider draws — see below                                                              |
| `mutable`    | bool   | `true`   | When `false`, the pool cannot be updated or removed via the admin API                               |
| `static`     | bool   | `true`   | When `true` (default for YAML-defined pools), the pool is always overwritten from config on startup |

### ipRequests fields

| Field      | Type   | Description                                                                               |
| ---------- | ------ | ----------------------------------------------------------------------------------------- |
| `provider` | string | Name of a `proxyProviders` entry                                                          |
| `count`    | int    | Number of IPs to take from that provider's list (first N; graceful if provider has fewer) |

Multiple `ipRequests` entries combine IPs from different providers into one pool:

```yaml theme={}
ipPools:
  - name: global-pool
    ipRequests:
      - provider: provider-us
        count: 5
      - provider: provider-au
        count: 5
```

***

## targets

The core routing config. Each inbound request is matched against the target list top-to-bottom — the first regex match handles the request. At least one target is required.

| Field                       | Type     | Default  | Description                                                                                                                                                              |
| --------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`                      | string   | required | Label used in logs and metrics                                                                                                                                           |
| `regex`                     | string   | required | Python regex matched against the full destination URL                                                                                                                    |
| `ipPool`                    | string   | required | Name of a shared `ipPools` entry                                                                                                                                         |
| `minRequestInterval`        | duration | `1s`     | How long an IP is held off the pool after any request                                                                                                                    |
| `maxQueueWait`              | duration | `30s`    | How long a request waits for a free IP before failing with 503                                                                                                           |
| `numRetries`                | int      | `3`      | Retry attempts on failure, each using a different IP                                                                                                                     |
| `ipFailuresUntilQuarantine` | int      | `5`      | Consecutive failures before an IP is quarantined                                                                                                                         |
| `quarantineTime`            | duration | `120s`   | How long a quarantined IP sits out before returning                                                                                                                      |
| `defaultProxyPort`          | int      | `8080`   | Port used when a pool IP has no explicit port                                                                                                                            |
| `spoofUserAgent`            | bool     | `true`   | Replace the `User-Agent` header with a random browser UA. Override per-request with `X-Proxy-Hopper-User-Agent`                                                          |
| `authManaged`               | bool     | `false`  | When `true`, Proxy Hopper calls the configured `server.authServer` before forwarding each request and injects the returned headers — see [authServer](#authserver) below |
| `mutable`                   | bool     | `true`   | Whether this target can be updated or removed via the admin API                                                                                                          |
| `static`                    | bool     | `true`   | When `true` (default for YAML-defined targets), the target is always overwritten from config on startup                                                                  |
| `identity`                  | block    | —        | Per-(IP, target) client identity — see [below](#identity)                                                                                                                |

```yaml theme={}
targets:
  - name: google-apis
    regex: '\.googleapis\.com'
    ipPool: us-pool           # must reference an ipPools entry
    minRequestInterval: 5s
    maxQueueWait: 30s
    numRetries: 3
    ipFailuresUntilQuarantine: 5
    quarantineTime: 10m

  - name: general
    regex: '.*'
    ipPool: us-pool
    minRequestInterval: 1s
    maxQueueWait: 30s
    numRetries: 3
    ipFailuresUntilQuarantine: 5
    quarantineTime: 2m
```

### identity

Attaches a persistent browser persona to each (IP, target) pair. **Disabled by default** — add the `identity:` block to enable.

| Field                 | Type   | Default | Description                                                                          |
| --------------------- | ------ | ------- | ------------------------------------------------------------------------------------ |
| `enabled`             | bool   | `false` | Master switch                                                                        |
| `cookies`             | bool   | `true`  | Persist and replay session cookies per IP                                            |
| `rotateAfterRequests` | int    | —       | Voluntarily rotate the identity after this many successful requests. Omit to disable |
| `rotateOn429`         | bool   | `true`  | Rotate identity immediately on a 429 response                                        |
| `warmup`              | block  | —       | Warmup request sent through a fresh identity before it enters service                |
| `warmup.enabled`      | bool   | `true`  | Enable the warmup request                                                            |
| `warmup.path`         | string | `/`     | URL path for the warmup GET request                                                  |

```yaml theme={}
identity:
  enabled: true
  cookies: true
  rotateAfterRequests: 100
  rotateOn429: true
  warmup:
    enabled: true
    path: /
```

See [Client Identities](/concepts/identities) for the full concept guide.

***

## auth

Authentication is **disabled by default**. When enabled, every proxy request must include an `X-Proxy-Hopper-Auth: Bearer <token>` header.

See the [Authentication](/admin/authentication/overview) section for full configuration guides.

| Field                | Type   | Default         | Description                                                                                  |
| -------------------- | ------ | --------------- | -------------------------------------------------------------------------------------------- |
| `enabled`            | bool   | `false`         | Enable authentication                                                                        |
| `jwtSecret`          | string | auto-generated  | Secret for signing/verifying locally-issued JWTs. Set explicitly so tokens survive restarts. |
| `jwtExpiryMinutes`   | int    | `60`            | JWT lifetime in minutes                                                                      |
| `apiKeys`            | list   | —               | Service-to-service API keys                                                                  |
| `apiKeys[].name`     | string | required        | Identifier used in logs and error messages                                                   |
| `apiKeys[].key`      | string | required        | The secret key string                                                                        |
| `apiKeys[].targets`  | list   | `["*"]`         | Target names this key can access. `["*"]` = all targets.                                     |
| `admin`              | block  | —               | Local admin user for the admin API                                                           |
| `admin.username`     | string | required if set | Admin username                                                                               |
| `admin.passwordHash` | string | required if set | Bcrypt hash — generate with `proxy-hopper hash-password`                                     |
| `roles`              | map    | —               | Custom roles for JWT/OIDC users (see [User-based auth](/admin/authentication/user-based))    |
| `oidc`               | block  | —               | OIDC/SSO configuration (see [SSO](/admin/authentication/sso))                                |

```yaml theme={}
auth:
  enabled: true
  jwtSecret: "change-me-to-a-long-random-string"
  jwtExpiryMinutes: 60

  apiKeys:
    - name: my-service
      key: "ph_changeme"
      targets: ["*"]          # allow all targets

    - name: reporting-service
      key: "ph_reporting_key"
      targets: ["analytics"]  # restrict to one target

  admin:
    username: admin
    passwordHash: "$2b$12$..."  # proxy-hopper hash-password <password>
```

***

## authServer

Configuration for the external **token server** that backs [managed auth](/concepts/managed-auth) — required only if at least one target sets `authManaged: true`. Lives under `server.authServer` (nested inside the `server:` block, not top-level).

| Field                     | Type   | Default  | Description                                                                                                                                        |
| ------------------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`                     | string | required | Base URL of the token server, e.g. `http://token-server:9000`                                                                                      |
| `timeoutSeconds`          | float  | `10`     | Hard timeout for each `POST /token` call                                                                                                           |
| `refreshThresholdSeconds` | float  | `60`     | Proactively refresh a token this many seconds before it expires                                                                                    |
| `retryIntervalSeconds`    | float  | `30`     | Cooldown before retrying a failed token server call, and before attempting recovery from `AUTH_BROKEN`                                             |
| `maxRetries`              | int    | `5`      | Consecutive token server failures before an IP is marked `AUTH_BROKEN`                                                                             |
| `exposeProxyUrl`          | bool   | `true`   | Include Proxy Hopper's own public URL in the `/token` request body, so the token server can route its own auth requests through the same pinned IP |

```yaml theme={}
server:
  authServer:
    url: "http://token-server:9000"
    timeoutSeconds: 10
    refreshThresholdSeconds: 60
    retryIntervalSeconds: 30
    maxRetries: 5
    exposeProxyUrl: false
```

<Note>
  Unlike the rest of `server:`, `authServer` has no `PROXY_HOPPER_AUTH_SERVER_*` environment variables and no CLI flags — it's YAML-only.
</Note>

See [Token Server](/admin/token-server/overview) for deployment and operations, and [Building a Token Server](/developers/token-server) for implementing one.

***

## server

All server fields can be set in three places — see [Config priority](#config-priority). See [Environment Variables](/admin/configuration/environment-variables) for the full env var reference.

| Field (YAML)       | Env var                           | Default                    | Description                                                                                                                                                                                                                                                                                                      |
| ------------------ | --------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `host`             | `PROXY_HOPPER_HOST`               | `0.0.0.0`                  | Bind address                                                                                                                                                                                                                                                                                                     |
| `port`             | `PROXY_HOPPER_PORT`               | `8080`                     | Proxy server port                                                                                                                                                                                                                                                                                                |
| `admin`            | `PROXY_HOPPER_ADMIN`              | `false`                    | Enable the admin server (GraphQL API + REST endpoints)                                                                                                                                                                                                                                                           |
| `adminPort`        | `PROXY_HOPPER_ADMIN_PORT`         | `8081`                     | Admin server port                                                                                                                                                                                                                                                                                                |
| `adminHost`        | `PROXY_HOPPER_ADMIN_HOST`         | `0.0.0.0`                  | Admin server bind address                                                                                                                                                                                                                                                                                        |
| `logLevel`         | `PROXY_HOPPER_LOG_LEVEL`          | `INFO`                     | `TRACE` \| `DEBUG` \| `INFO` \| `WARNING` \| `ERROR`                                                                                                                                                                                                                                                             |
| `logFormat`        | `PROXY_HOPPER_LOG_FORMAT`         | `text`                     | `text` \| `json`                                                                                                                                                                                                                                                                                                 |
| `logFile`          | `PROXY_HOPPER_LOG_FILE`           | stderr                     | Path to log file                                                                                                                                                                                                                                                                                                 |
| `backend`          | `PROXY_HOPPER_BACKEND`            | `memory`                   | `memory` \| `redis`                                                                                                                                                                                                                                                                                              |
| `redisUrl`         | `PROXY_HOPPER_REDIS_URL`          | `redis://localhost:6379/0` | Redis connection URL                                                                                                                                                                                                                                                                                             |
| `proxyReadTimeout` | `PROXY_HOPPER_PROXY_READ_TIMEOUT` | —                          | Timeout in seconds for reading the upstream response body. Omit to use aiohttp's default                                                                                                                                                                                                                         |
| `metrics`          | `PROXY_HOPPER_METRICS`            | `false`                    | Enable Prometheus `/metrics` endpoint                                                                                                                                                                                                                                                                            |
| `metricsPort`      | `PROXY_HOPPER_METRICS_PORT`       | `9090`                     | Metrics server port                                                                                                                                                                                                                                                                                              |
| `prometheusUrl`    | `PROXY_HOPPER_PROMETHEUS_URL`     | unset                      | External Prometheus the admin UI's per-target metrics panel queries server-side. See [Admin UI metrics panel](/admin/observability/metrics#admin-ui-metrics-panel). Unrelated to `metrics`/`metricsPort` above — those control Proxy Hopper as a scrape *target*; this is Proxy Hopper as a Prometheus *client*. |
| `probe`            | `PROXY_HOPPER_PROBE`              | `true`                     | Enable background IP health prober                                                                                                                                                                                                                                                                               |
| `probeInterval`    | `PROXY_HOPPER_PROBE_INTERVAL`     | `60`                       | Seconds between probe rounds                                                                                                                                                                                                                                                                                     |
| `probeTimeout`     | `PROXY_HOPPER_PROBE_TIMEOUT`      | `10`                       | Per-probe HTTP timeout (seconds)                                                                                                                                                                                                                                                                                 |
| `probeUrls`        | `PROXY_HOPPER_PROBE_URLS`         | Cloudflare + Google        | Endpoints probed through each IP. Comma-separated as env var.                                                                                                                                                                                                                                                    |
| `debugQuarantine`  | `PROXY_HOPPER_DEBUG_QUARANTINE`   | `false`                    | Log quarantine and cooldown events at DEBUG level                                                                                                                                                                                                                                                                |
| `debugProbes`      | `PROXY_HOPPER_DEBUG_PROBES`       | `false`                    | Log probe results at DEBUG level                                                                                                                                                                                                                                                                                 |
| `debugBackend`     | `PROXY_HOPPER_DEBUG_BACKEND`      | `false`                    | Log backend storage operations at DEBUG level                                                                                                                                                                                                                                                                    |
| `authServer`       | — (YAML only)                     | unset                      | Token server config block for managed auth — see [authServer](#authserver) above                                                                                                                                                                                                                                 |

```yaml theme={}
server:
  host: 0.0.0.0
  port: 8080
  logLevel: INFO
  logFormat: json
  backend: memory
  redisUrl: redis://localhost:6379/0
  metrics: true
  metricsPort: 9090
```

## CLI flags

CLI flags override all other sources and cover the most operationally useful overrides:

```
proxy-hopper run --config config.yaml [OPTIONS]

  --config / -c PATH       Path to YAML config file  [required]
  --host TEXT              Bind address
  --port INT               Proxy server port
  --log-level CHOICE       TRACE|DEBUG|INFO|WARNING|ERROR
  --log-format CHOICE      text|json
  --log-file PATH          Write logs to file instead of stderr
  --metrics / --no-metrics Enable Prometheus /metrics
  --metrics-port INT       Metrics server port
  --backend CHOICE         memory|redis
  --redis-url TEXT         Redis connection URL
  --probe / --no-probe     Enable background IP health prober
  --probe-interval FLOAT   Seconds between probe rounds
  --probe-timeout FLOAT    Per-probe HTTP timeout
  --probe-urls TEXT        Comma-separated probe endpoints

proxy-hopper validate --config config.yaml
  Validates the config file and prints a summary without starting the server.

proxy-hopper hash-password <password>
  Generates a bcrypt hash suitable for auth.admin.passwordHash.
```
