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
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):
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.
Defining providers is optional — targets can also list IPs inline via ipList.
| 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 |
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 definition while maintaining independent rotation state.
Defining pools is optional — targets can also list IPs inline.
ipPools:
- name: pool-name
ipRequests: # draw IPs from providers (randomly sampled at startup)
- provider: name
count: 5
ipList: # or list IPs inline (can be combined with ipRequests)
- "host:port"
ipRequests fields
| Field | Type | Description |
|---|
provider | string | Name of a proxyProviders entry |
count | int | Number of IPs to randomly sample from that provider’s list |
ipPools:
- name: global-pool
ipRequests:
- provider: provider-us
count: 5
- provider: provider-au
count: 5
Inline IPs in ipPools.ipList have no provider metadata — they won’t appear with provider or region labels in Prometheus metrics.
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 |
ipList | list | required* | Inline proxy addresses — host:port or bare host |
defaultProxyPort | int | 8080 | Port applied to bare IPs in ipList |
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 |
identity | block | — | Per-(IP, target) client identity — see below |
* Exactly one of ipPool or ipList must be provided per target.
targets:
- name: google-apis
regex: '\.googleapis\.com'
ipPool: us-pool
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 |
profile | string | random | Fixed fingerprint profile name. Omit to pick a random profile per identity. Valid values: chrome-windows, chrome-macos, safari-macos, firefox-windows, firefox-linux |
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 |
identity:
enabled: true
cookies: true
# profile: chrome-windows # omit for random per identity
rotateAfterRequests: 100
rotateOn429: true
warmup:
enabled: true
path: /
See Client 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 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) |
oidc | block | — | OIDC/SSO configuration (see SSO) |
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>
server
All server fields can be set in three places — see Config priority. See 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 |
adminPort | PROXY_HOPPER_ADMIN_PORT | 8081 | Admin API port (when admin is enabled) |
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 |
metrics | PROXY_HOPPER_METRICS | false | Enable Prometheus /metrics endpoint |
metricsPort | PROXY_HOPPER_METRICS_PORT | 9090 | Metrics server port |
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. |
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.