Configuration¶
The Organization Manager is configured by a single YAML file. The
shipped systemd unit passes /etc/pdns-pf/orgmanager.yaml to the
binary; a heavily-commented template ships alongside it as
/etc/pdns-pf/orgmanager.example.yaml.
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 — most importantly the PostgreSQL password — from a systemd
drop-in rather than hard-coding them in the file. There is no flag
to turn this off.
The PostgreSQL DSN is masked in the startup log line that dumps the
effective config, so credentials passed in via env-var expansion
do not end up in journalctl.
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 |
|---|---|---|---|
http |
HTTP |
{} |
REST API listener, status page, Prometheus /metrics, /health. |
database |
Database |
{} |
PostgreSQL connection. Required — the service refuses to start without it. |
nats |
NATS |
{request_timeout: 10s} |
NATS transport for publishing session updates to the IP Mapper. Leaving the URL empty disables publishing. |
deploy |
Deploy |
see below | Asynchronous deployment worker pool and the two periodic timers. |
log |
Log |
see Common configuration | Log level and format. |
deploy defaults to {workers: 4, version_check_interval: 60s, full_redeploy_interval: 0}.
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 block below is the shipped example template. The per-section reference below it is authoritative; the example exists for orientation.
Click to expand the shipped example
# Orgmanager Configuration Example
#
# The Organization Manager (orgmanager) provides a REST API to manage IP CIDR
# blocks within an organization. This file documents all available configuration
# options with example values.
# HTTP server configuration
http:
# Address to listen on (host:port or :port)
# Leave empty to disable the HTTP server
address: ":8080"
# TLS configuration (optional)
# Uses github.com/PowerDNS/go-tlsconfig
tls:
# Path to CA certificate file for client verification
# ca_file: /etc/ssl/certs/ca.pem
# Path to server certificate file
# cert_file: /etc/ssl/certs/server.pem
# Path to server private key file
# key_file: /etc/ssl/private/server-key.pem
# Database configuration
database:
# PostgreSQL connection string
# Supports environment variable expansion: ${VAR_NAME}
# Format: postgres://user:password@host:port/database?sslmode=disable
dsn: "postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:5432/orgmanager?sslmode=disable"
# For development/testing with SQLite (prefix with "sqlite:" to auto-detect driver):
# dsn: "sqlite:file:orgmanager.db?cache=shared&_fk=1"
# Or in-memory:
# dsn: "sqlite:file::memory:?cache=shared&_fk=1"
# NATS configuration for publishing range updates to ipmapper
nats:
# Timeout for each request/reply call to ipmapper.
# Timed-out deployments are retried by the deploy worker.
request_timeout: 10s
itsy:
# NATS server URL
# Leave url empty to disable NATS publishing
url: "nats://localhost:4222"
# Subject prefix for NATS messages
# Messages are published to: {prefix}.ipmapper.{command}
# Must match the ipmapper's itsy prefix so that the orgmanager
# publishes to the same subjects the ipmapper subscribes to.
prefix: "pdnspf"
# TLS configuration for NATS connection (optional)
tls:
# ca_file: /etc/ssl/certs/nats-ca.pem
# cert_file: /etc/ssl/certs/nats-client.pem
# key_file: /etc/ssl/private/nats-client-key.pem
# Asynchronous deployment worker pool configuration.
# Write operations (prefix changes, override upserts) commit to the database and
# return immediately. Deployment to ipmapper happens asynchronously via a pool of
# worker goroutines. Multiple writes during a deployment are coalesced into one
# follow-up deploy, reducing NATS round-trips under load.
deploy:
# Number of concurrent deployment worker goroutines.
# Each worker processes one org at a time. Increase if you have many orgs
# that change concurrently.
workers: 4
# How often to check all organization versions against the database.
# Detects remote changes (e.g. Django admin) and triggers redeployment.
# On startup, an immediate check runs to discover and deploy all existing orgs.
# Set to 0 to disable periodic version checking.
# Format: Go duration string (e.g., "60s", "1m", "5m")
version_check_interval: 60s
# Interval for periodically redeploying all known orgs to ipmapper.
# Set to 0 to disable. Useful as a safety net to ensure ipmapper stays in sync.
# Format: Go duration string (e.g., "1h", "30m")
full_redeploy_interval: 0
# Logging configuration
log:
# Log level: debug, info, warn, error
level: info
# Log format: human (colored, for terminals), logfmt (structured), json
format: human
# Use UTC timestamps (recommended for production)
utc: true
http¶
REST API listener plus the status page, the Prometheus /metrics
scrape endpoint, and /health. Leaving address empty disables the
listener entirely — useful in odd test setups, but a deployed
instance always has it set.
| Parameter | Type | Default | Description |
|---|---|---|---|
address |
string |
"" (disabled) |
Bind address in host:port form (e.g. :8080, 127.0.0.1:8080). Leave empty to disable the HTTP server. |
tls |
tlsconfig.Config |
{} |
PowerDNS go-tlsconfig block. Leave as {} for plain HTTP; populate to enable HTTPS. |
database¶
PostgreSQL connection. Required — the service refuses to start with
an empty DSN. SQLite is supported for dev and tests via a sqlite:
prefix, but the production RPM does not ship the SQLite driver — see
SQLite is dev-only below.
| Parameter | Type | Default | Description |
|---|---|---|---|
dsn |
string |
"" (required) |
PostgreSQL connection string. Supports ${VAR} env-var expansion for secrets. Masked in the startup config dump. |
Connecting to PostgreSQL¶
The DSN accepts the standard postgres:// URL form. Common shapes:
- Plain TCP, password from systemd env:
- Verified TLS to a managed PostgreSQL:
database:
dsn: "postgres://orgmanager@db.internal:5432/orgmanager?sslmode=verify-full&sslrootcert=/etc/pki/tls/certs/db-ca.pem"
- Local Unix socket (no password needed when peer auth is on):
- Read-write replica with failover uses the standard
target_session_attrs=read-writeplus a comma-separated host list:
database:
dsn: "postgres://orgmanager@db-1,db-2,db-3:5432/orgmanager?sslmode=verify-full&target_session_attrs=read-write"
Env-var expansion applies to the whole DSN, so the recommended pattern is to keep the user, host, and port literal in the YAML and pass the password through a systemd drop-in:
SQLite is dev-only¶
The example file shows a sqlite: DSN for convenience when running
the binary out of the source tree. The production RPM is built
without CGO support, so the SQLite driver is not linked in.
Configuring a sqlite: DSN on a deployed box will fail at startup
with a message that names the missing CGO build. Operators on
deployed boxes should ignore the SQLite line in the example and
keep the DSN pointed at PostgreSQL.
nats¶
NATS transport for publishing session updates and cleanup commands
to the IP Mapper. Leaving itsy.url empty disables publishing —
the service still serves the REST API and writes to PostgreSQL,
which is occasionally useful for staging or for running the API
without an IP Mapper attached.
| Parameter | Type | Default | Description |
|---|---|---|---|
request_timeout |
go: Duration |
10s |
Timeout for each request/reply call to the IP Mapper. A timed-out deploy request fails the current attempt and is retried by the deploy worker. |
itsy |
itsy.Config |
{} |
NATS connection, subject prefix, and TLS. See the common configuration reference for every field. |
itsy.prefix must match the IP Mapper¶
Subjects on the wire are {itsy.prefix}.ipmapper.{command}. The IP
Mapper subscribes on the same convention and only sees messages on
its configured prefix, so a mismatch is silent — orgmanager will
publish, the IP Mapper will not see anything, and only the absence
of expected sessions will tip operators off. Set itsy.prefix to
the value the receiving IP Mapper is configured with.
Disabling NATS¶
The service logs NATS publishing disabled at startup. Writes still
commit to PostgreSQL and the deploy queue still drains, but
nothing is sent over the wire.
deploy¶
The asynchronous deployment worker pool plus the two periodic timers. See Architecture → Async deployment to the IP Mapper for the full picture; this section covers the knobs.
| Parameter | Type | Default | Description |
|---|---|---|---|
workers |
int |
4 |
Number of concurrent deployment workers. Each worker processes one organisation at a time. |
pending_queue_size |
int |
10000 |
Number of organisation IDs that can wait for deploy workers. The default absorbs startup/version-scan and bulk admin bursts while still bounding memory if workers cannot drain the queue. |
version_check_interval |
go: Duration |
60s |
How often to walk every organisation's org_version and queue redeploys for drifted, newly-discovered, or disappeared organisations. 0 disables the periodic scan. The startup scan still runs even at 0. |
full_redeploy_interval |
go: Duration |
0 (disabled) |
How often to queue a full redeploy of every cached organisation as a safety net. 0 disables it. |
Sizing workers¶
The worker pool is the limit on parallel deploys, not on REST
throughput — REST writes commit to PostgreSQL and return immediately,
they do not wait for a worker. Bump workers if many organisations
change at the same time and the deploy queue runs deep, which the
status page and the orgmanager_deploy_queue_size metric both
expose.
Tuning version_check_interval¶
The scan is a single SELECT org_id, version FROM organizations
followed by an in-memory diff. The cost is dominated by the PostgreSQL
round-trip, not the workload. For typical deployments the default
60 seconds is fine; lowering it tightens the worst-case latency
between an out-of-band write (admin portal, second orgmanager) and
the IP Mapper seeing it.
Setting version_check_interval: 0 disables the periodic scan but
not the startup scan — every restart runs one initial pass to
populate the in-memory state. Disable the periodic scan only if all
writes flow through this orgmanager instance.
Tuning full_redeploy_interval¶
Periodic full redeploy exists as a safety net — the diffing path
already keeps the IP Mapper in sync. Hours are a typical setting
(1h, 4h); minutes are usually too aggressive and produce
unnecessary NATS traffic. Leave it at 0 unless you have a
specific reason to enable it; the IP Mapper has its own paths for
detecting drift.
log¶
Log level and format. See Common configuration → log
for every field. The CLI flag --debug overrides log.level to
debug.