Skip to content

Configuration

The Simulator HTTP Server is configured by a single YAML file. On the shipped RPM the systemd unit passes /etc/pdns-pf/simulator-server.yaml to the binary, and a /etc/pdns-pf/simulator-server.example.yaml template ships alongside it.

Environment variables in the YAML are always expanded before parsing: $VAR and ${VAR} references get replaced with their values from the service's environment. This is the recommended way to inject secrets (for example, an API key) from a systemd drop-in rather than hard-coding them in the file. There is no CLI flag to turn this off.

Unknown YAML keys are rejected — a typo in a field name will refuse to start the service rather than be 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

The YAML has four top-level sections. All four are optional in the strict parsing sense, but in practice every deployment sets at least http.address (so there is a predictable metrics endpoint to scrape) and lua (to point at the actual filter engine script).

Parameter Type Default Description
http HTTP {} HTTP server for the REST API, status page, Prometheus /metrics, and pprof. The server is started even when http.address is empty.
nats NATS {} Optional NATS transport. Enabled when nats.itsy.url (or the NATS_URL env var) is set.
lua Lua {workers: 1, file: "/usr/share/pdns-pf-lua-dist/share/lua/5.1/pdns-pf/simulator/server.lua"} Lua worker pool that runs the filter engine.
log Log {format: logfmt} Logging format and level.

Deprecation policy

None. Every field on this page is current as of this release. The service has no deprecated or removed config fields to migrate away from.

Full example

The file below is the example template shipped alongside the RPM. It is the smallest reasonable configuration: HTTP on a fixed port, NATS enabled, one Lua worker, and debug-level logging. The per-section reference below it is authoritative.

Click to expand the shipped example
http:
    # http address for the simulator API
    address: ":8671"
    tls: {}
    api_keys: []
nats:
    # As defined by: https://github.com/PowerDNS/itsy
    itsy:
        url: "nats://nats:4222"
        # Optional prefix, if not set it will default to svc meaning
        # subjects will look like svc.simulator.abc
        prefix: "pdnspf"
        topologies: []
        meta: {}
        tls: {}
lua:
    workers: 1
    file: "/platform-filter/pdns-pf/simulator/server.lua"
log:
    format: "logfmt"
    level: "debug"

http

The http section controls the internal webserver that exposes the REST API, the HTML status page at /, the Prometheus /metrics endpoint, and the Go net/http/pprof profiling handlers. All four share the same bind address; there is no way to split them onto different listeners.

The current binary always starts the webserver. If http.address is left empty, the address is passed through to Go's net/http server; that server uses :http (port 80) for an empty address. This is not a headless or NATS-only mode, and it may fail under the shipped non-root systemd service because binding port 80 normally requires elevated privileges. Set an explicit address such as :8671 or 127.0.0.1:8671 so the listener is predictable. There is currently no configuration switch that disables the HTTP listener entirely.

API key enforcement

When api_keys is non-empty, the three API endpoints that talk to the Lua side — /api/v1/domain, /api/v1/simulate, and /api/v1/codemappings — require the caller to present a valid key. Keys must be sent in the X-API-Key HTTP header. A missing key returns 401 Unauthorized; an unknown key returns the same status.

The status page, /api/v1/info, /metrics, and the pprof handlers are not behind the API key check, so a Prometheus scraper does not need to know any keys.

When api_keys is left empty, the API is open to anyone who can reach the address. In a deployment where the service is exposed beyond localhost, populate this list, and inject the keys from an environment variable rather than committing them to the YAML. If a proxy uses this simulator as a remote decision backend, set that proxy's API key setting to one of these keys. For the current OpenResty proxy, that setting is proxyremoteapikey:

http:
    api_keys:
        - "${SIMULATOR_API_KEY_ADMIN}"
        - "${SIMULATOR_API_KEY_OPERATOR}"

HTTP fields

Parameter Type Default Description
address string "" Bind address in host:port form (e.g. :8671 for all interfaces, 127.0.0.1:8671 for local only). Empty is passed to Go net/http, which listens on :http (port 80); it does not disable the webserver.
tls tlsconfig.Config {} PowerDNS go-tlsconfig block. Leave as {} for plain HTTP; populate to enable HTTPS.
api_keys []string [] Accepted API keys for the three Lua-backed endpoints. Empty leaves the API open. See API key enforcement.

Example:

http:
    address: ":8671"
    tls: {}
    api_keys:
        - "${SIMULATOR_API_KEY}"

See Operations → Observability for the list of served endpoints.

nats

The nats section enables the NATS transport. When nats.itsy.url is set (or the NATS_URL environment variable is set at startup), the service connects to NATS via the itsy library and serves the same request types it serves over HTTP. When both are empty, the NATS goroutine never starts and the instance is HTTP-only.

NATS and HTTP can be enabled together. They share the same Lua worker pool, so requests on either transport queue up on the same workers.

itsy

Nested NATS connection config, passed through to itsy. The most commonly-touched fields are listed here; see the full itsy reference for all fields including environment variable overrides.

Parameter Type Default Description
url string "" NATS server URL, e.g. nats://nats:4222 or tls://nats.example.com:4222. Empty leaves NATS disabled unless NATS_URL is set in the environment.
prefix string "svc" Subject prefix used for all itsy-managed subjects. The simulator's transport subjects are <prefix>.simulator.domain, <prefix>.simulator.simulate, <prefix>.simulator.codemappings, and <prefix>.simulator.info.
topologies []string [] Advanced NATS topology config (dotted strings like eu.amsterdam.az1). Leave empty unless you have specific requirements.
meta map[string]string {} Free-form metadata attached to this NATS service registration, visible to NATS monitoring tooling.
tls tlsconfig.Config {} TLS config for the NATS connection. Populate to enable authenticated/encrypted transport.

Example:

nats:
    itsy:
        url: "nats://nats.example.com:4222"
        prefix: "pdnspf"
        tls: {}

lua

The lua section controls the pool of LuaJIT workers that run the actual filter engine. Each worker is an independent LuaJIT state with its own copy of the filter code; the Go side dispatches incoming requests across the pool.

Picking the worker count

workers: 1 is enough for an Admin Portal that only fires a query when an operator clicks a button. Raise it when the service is also serving automated workloads — bulk simulation runs, regression suites, a NATS topology with several callers, or proxies using it as a remote decision backend — that would otherwise queue behind a single worker.

Each additional worker independently keeps its own copy of the filter engine's working set in memory; the cost is roughly linear in process RSS. There is no benefit to going beyond the number of CPUs the service can use.

Lua file path

lua.file points at the entry-point script the workers load. On a shipped deployment this is the file the pdns-pf-simulator RPM installs at /usr/share/pdns-pf-lua-dist/share/lua/5.1/pdns-pf/simulator/server.lua.

If the file does not load (missing file, Lua parse error, missing required module), worker startup fails and the service exits with the relevant error logged. There is no fallback path.

Lua fields

Parameter Type Default Description
workers int 1 Number of independent LuaJIT workers. See Picking the worker count.
file string /usr/share/pdns-pf-lua-dist/share/lua/5.1/pdns-pf/simulator/server.lua Filesystem path to the Lua entry point.

Example:

lua:
    workers: 2
    file: "/usr/share/pdns-pf-lua-dist/share/lua/5.1/pdns-pf/simulator/server.lua"

log

The log section picks the output format and level for the service's logs. Logs go to standard error, which under the default systemd unit is captured by the journal under the pdns-pf-simulator-server identifier.

Parameter Type Default Description
format string logfmt Log output format. Accepted values: logfmt (structured key=value, easy to grep) or json.
level string info Log level. Accepted values: debug, info, warn, error. The --debug CLI flag overrides this to debug at startup.

Example:

log:
    format: logfmt
    level: info