Configuration¶
The proxy reads a single YAML file. On the shipped RPM the systemd unit passes
/etc/pdns-pf/proxy-tcp.yaml to the binary. A heavily-commented example
template ships alongside it as /etc/pdns-pf/proxy-tcp.example.yaml.
The proxy can also run entirely from command-line flags, with no config file at all. A small set of common flags override YAML values after the file loads; see Operations → Command-line flags. This page documents the YAML form.
Environment variables in the YAML are expanded before parsing: $VAR and
${VAR} references are replaced with their values from the service's
environment. This is the recommended way to inject secrets such as the simulator
HTTP API key. Unknown keys are rejected — a typo in a field name stops the proxy
from starting rather than being silently ignored.
Every config option is documented on this page. Use your browser's in-page search (Ctrl/⌘-F) to jump straight to the field you care about.
Top-level structure¶
| Parameter | Type | Default | Description |
|---|---|---|---|
tcp |
TCP |
see tcp | Timeouts, buffer size, and stats interval shared by every listener. |
nats |
NATS |
{prefix: pdnspf} |
NATS connection for the nats decision backend and for pause control. |
decision |
Decision |
{backend: nats, timeout: 1s} |
Which remote filtering backend the proxy uses. |
listeners |
[]Listener |
[] |
Bind addresses and per-listener routing. At least one is required. |
status |
Status |
{} |
Optional status page and Prometheus metrics HTTP server. Disabled unless address is set. |
log |
Log |
{level: connection, format: human} |
Log level and output format. |
Deprecation policy¶
None. Every field on this page is current as of this release. The proxy has no deprecated or removed config fields to migrate away from.
Full example¶
The file below is the example template shipped alongside the RPM. The per-section reference below it is authoritative.
Click to expand the shipped example
tcp:
# Bounds the initial HTTP request-header read or TLS ClientHello read.
# Default: 5s
initial_read_timeout: 5s
# Bounds DNS lookups and each upstream dial attempt.
# Default: 5s
dial_timeout: 5s
# Scratch buffer size used for each proxied direction. Unit-suffixed values
# such as kB, MB, and GB are accepted.
# Default: 32kB
copy_buffer_size: 32kB
# Periodic active-connection summary log interval. Set to 0 to disable the
# periodic summaries while keeping final per-connection logs.
# Default: 10s
active_stats_interval: 10s
nats:
# The proxy follows the repo-style nats.itsy shape.
itsy:
# Optional. When omitted, command config assembly still applies ITSY_URL and
# then the legacy NATS_URL fallback before validation.
url: nats://127.0.0.1:4222
# Default: pdnspf
prefix: pdnspf
decision:
# Supported backends:
# - nats: remote filtering over the simulator NATS service
# - http: remote filtering over the simulator HTTP API
# - none: disable remote filtering explicitly
# Default: nats
backend: nats
# Bounds one remote filtering request.
# Default: 1s
timeout: 1s
simulator_http:
# Only required when backend is http.
url: http://127.0.0.1:8080
# Optional API key sent as X-API-Key when backend is http.
api_key: ${SIMULATOR_HTTP_API_KEY}
# Optional file containing the API key. Useful for Kubernetes Secret volume
# mounts. Surrounding whitespace and newlines are ignored. Do not set this
# together with api_key.
# api_key_file: /run/secrets/simulator-api-key
# Optional go-tlsconfig client TLS settings for HTTPS simulator endpoints.
tls:
# ca_file: /etc/pdns-pf/simulator-ca.pem
# cert_file: /etc/pdns-pf/proxy-client.pem
# key_file: /etc/pdns-pf/proxy-client-key.pem
listeners:
# Multiple listeners for the same protocol are allowed.
- name: office-http
protocol: http
address: :9980
remote_port: 80
proxy_protocol: false
vhost: office-proxy
profile: 42
fail_open: false
- name: office-https
protocol: https
address: :9943
remote_port: 443
# The SOCKS5 listener accepts only CONNECT to ports 80 and 443 and then
# routes based on the later HTTP Host or TLS SNI.
- name: office-socks5
protocol: socks5
address: :9990
status:
# Serves a status page on /, Prometheus metrics on /metrics, and a liveness
# probe on /healthz. Empty address disables it.
# Default: disabled
address: "127.0.0.1:9919"
# Add a per-connection details table to the status page. Exposes client
# addresses and destination hosts; not recommended in production.
# Default: false
connections: false
log:
# Supported levels: debug, connection, info, warn, error.
# Default: connection
level: connection
# Supported formats: human, logfmt, json.
# Default: human
format: human
tcp¶
The tcp section holds runtime settings that apply uniformly to every listener:
the timeouts that bound the inspect, decision, and dial stages, the per-direction
copy buffer size, and the periodic stats interval.
The copy_buffer_size value accepts unit-suffixed forms such as 32kB, 1MB,
or 1GB, and must be greater than zero and no larger than 1GB. It is the
scratch buffer used for each direction of the proxied stream; the default suits
normal web traffic and rarely needs changing.
| Parameter | Type | Default | Description |
|---|---|---|---|
initial_read_timeout |
go: Duration |
5s |
Bounds the first HTTP request-header read or TLS ClientHello read. Must be greater than zero. |
dial_timeout |
go: Duration |
5s |
Bounds DNS lookups and each upstream dial attempt. Must be greater than zero. |
copy_buffer_size |
bytes |
32kB |
Per-direction proxy scratch buffer. Unit-suffixed (kB, MB, GB). Range >0 to 1GB. |
active_stats_interval |
go: Duration |
10s |
Cadence of the periodic active-connection summary log. Set to 0 to disable the periodic summaries while keeping the final per-connection logs. |
nats¶
The nats section configures the NATS connection used by the nats decision
backend and by pause control. It is required when
decision.backend is nats; the proxy refuses to start if that backend is
selected with no NATS URL. For the http and none backends it can be left
out, unless you still want pause control.
URL resolution¶
The NATS URL is resolved in this order: the nats.itsy.url field, then the
ITSY_URL environment variable, then the legacy NATS_URL environment
variable. The URL credentials are masked when the proxy logs its effective
configuration at startup.
NATS fields¶
| Parameter | Type | Default | Description |
|---|---|---|---|
itsy |
itsy.Config |
{prefix: pdnspf} |
NATS connection, prefix, and TLS. See the itsy sub-table below and the full itsy reference. |
itsy¶
Nested NATS connection config, passed through to
github.com/PowerDNS/itsy. The two fields
the proxy most cares about are listed here; see the full
itsy reference for all fields,
including TLS and the environment variable overrides.
| Parameter | Type | Default | Description |
|---|---|---|---|
url |
string |
— | NATS server URL, e.g. nats://127.0.0.1:4222. Resolved from this field, then ITSY_URL, then NATS_URL. Required for the nats backend. |
prefix |
string |
pdnspf |
Subject prefix for the simulator and pause services. The pause subjects live under <prefix>.proxy-tcp.* — see Pause control. |
decision¶
The decision section selects the remote filtering backend and bounds each
decision request. See Architecture → Decision backends
for what each backend does and how fail-open interacts with it.
Backend requirements¶
The required fields depend on the chosen backend:
nats(default) needs a usable NATS URL in thenatssection (or theITSY_URL/NATS_URLenvironment variables).httpneedssimulator_http.url.noneneeds nothing further and disables remote filtering.
The proxy refuses to start if the selected backend's required field is missing.
Decision fields¶
| Parameter | Type | Default | Description |
|---|---|---|---|
backend |
string |
nats |
Remote filtering backend: nats, http, or none. |
timeout |
go: Duration |
1s |
Bounds one remote filtering request. Must be greater than zero. |
simulator_http |
SimulatorHTTP |
{} |
Settings for the http backend. See the sub-table below. |
simulator_http¶
Settings for the simulator REST API backend. Only used when decision.backend
is http, in which case url is required and the proxy calls
<url>/api/v1/simulate.
Warning
Set either api_key or api_key_file, never both. The proxy refuses to
start if both are set.
Inject the key from the environment rather than hard-coding it in the file:
For Kubernetes, mount the key as a Secret volume and point api_key_file at it;
surrounding whitespace and newlines are trimmed. The API key value is masked
when the proxy logs its effective configuration at startup.
| Parameter | Type | Default | Description |
|---|---|---|---|
url |
string |
— | Base URL of the simulator HTTP API, e.g. http://127.0.0.1:8080. Must use http or https and include a host. Required for the http backend. |
api_key |
string |
"" |
Optional API key sent as the X-API-Key header. Masked in startup log output. Mutually exclusive with api_key_file. |
api_key_file |
string |
"" |
Optional path to a file holding the API key. Whitespace is trimmed. Mutually exclusive with api_key. |
tls |
tlsconfig.Config |
{} |
PowerDNS go-tlsconfig block for HTTPS simulator endpoints. Leave as {} for plain HTTP. |
listeners¶
The listeners section is a list of bind addresses, each with its own protocol
and routing options. At least one listener must be configured or the proxy
refuses to start. Multiple listeners of the same protocol are allowed, so one
instance can serve HTTP, HTTPS, and SOCKS5 on different ports at once.
Per-listener routing context¶
The vhost and profile fields attach a static decision context to every
request from that listener, letting the simulator apply a specific policy. Both
are optional; leave them unset to let the simulator decide from the client IP
and host alone. fail_open is decided per listener — see
Architecture → Fail-open and fail-closed.
SOCKS5 restrictions¶
Note
A socks5 listener derives its upstream port (80 or 443) from each SOCKS
CONNECT request, so remote_port is not allowed on it. proxy_protocol
is also not supported on SOCKS5 listeners. Setting either is refused at
startup.
Listener fields¶
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
string |
{protocol}@{address} |
Stable label used in logs. Falls back to a generated name from the protocol and address when omitted. |
protocol |
string |
— | http, https, or socks5. Required. |
address |
string |
— | TCP bind address in host:port form, e.g. :9980 or 127.0.0.1:9980. Required. |
remote_port |
int |
80 for http, 443 for https |
Upstream TCP port used after inspection. Not allowed for socks5. Valid range 0–65535. |
proxy_protocol |
boolean |
false |
Require an HAProxy PROXY protocol v1 header before the inspected bytes. http and https only — see Architecture → PROXY protocol. |
vhost |
string |
"" |
Optional static vhost sent with every decision request from this listener. |
profile |
int |
— | Optional static profile number sent with every decision request from this listener. |
fail_open |
boolean |
false |
Allow proxying when the decision backend fails. See fail-open. |
status¶
The status section enables an optional HTTP server that serves a summary
status page on /, Prometheus metrics on /metrics, and a liveness probe on
/healthz. It is disabled by default; set address to turn it on. See
Operations → Status and metrics server
and the Metrics page.
The --status-address flag overrides
address, and --dev-listeners enables the server on 127.0.0.1:9919 with
connections turned on.
Warning
connections: true adds a per-connection table to the status page that
exposes client addresses and destination hosts, and snapshots every active
connection on each page load. Keep it off in production.
| Parameter | Type | Default | Description |
|---|---|---|---|
address |
string |
"" |
TCP bind address in host:port form for the status server. Empty disables it. |
connections |
boolean |
false |
Add a per-connection details table to the status page. Exposes client addresses and destination hosts; not recommended in production. |
log¶
The log section picks the log level and output format. Logs go to standard
error, which under the default systemd unit is captured by the journal under the
pdns-pf-proxy-tcp identifier.
The connection level is specific to this proxy: it sits between debug and
info so the per-session lifecycle logs stay on by default without the volume of
full debug logging. See Operations → Observability.
| Parameter | Type | Default | Description |
|---|---|---|---|
level |
string |
connection |
Log level: debug, connection, info, warn, or error. The --debug flag overrides this to debug at startup. |
format |
string |
human |
Output format: human (colorized in a terminal), logfmt (structured key=value), or json. |