Skip to content

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 the nats section (or the ITSY_URL / NATS_URL environment variables).
  • http needs simulator_http.url.
  • none needs 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:

decision:
  simulator_http:
    url: https://simulator.example.com
    api_key: "${SIMULATOR_HTTP_API_KEY}"

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 065535.
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.