Documentation → Configuration

Configuration

BoronDNS is configured through a single TOML file, typically at /etc/borondns-secondary/config.toml. The path is set with --config at startup (or via BORONDNS_CONFIG environment variable). When both are omitted, the default path is used.

Validate and inspect

# Validate config without starting the server
borondns --validate-config /etc/borondns-secondary/config.toml

# Dump the effective config (inline TSIG secrets are redacted)
borondns --dump-config /etc/borondns-secondary/config.toml

# Print the built-in example config
borondns --example-config

Minimal configuration

A working minimal config requires an [interfaces.dns] block and at least one [[zones]] entry:

[interfaces.dns]
bind_address = "0.0.0.0"
port = 53

[[zones]]
name     = "example.com."
primaries = [{ address = "10.0.0.1", port = 53 }]
notify_sources = ["10.0.0.1"]

Interfaces

[interfaces.dns]
# Addresses and port for authoritative DNS service (UDP and TCP).
bind_address = "0.0.0.0"
port = 53

[interfaces.mgmt]
# Management HTTP listener for health, readiness, and metrics endpoints.
# Keep this on a private address — never expose port 8080 to the internet.
bind_address = "127.0.0.1"
port = 8080

[interfaces.transfer]
# Optional: bind address for outgoing AXFR/IXFR connections.
# Defaults to the OS routing table.
# bind_address = "10.0.0.2"

Zone blocks

Each [[zones]] entry declares a secondary zone to track:

[[zones]]
# Zone name (trailing dot optional, added automatically)
name = "example.com."

# Primary nameserver(s) to AXFR/IXFR from
primaries = [
  { address = "10.0.0.1", port = 53 },
]

# Addresses from which NOTIFY messages are accepted
notify_sources = ["10.0.0.1"]

# TSIG key name for authenticating transfers. Must match a [tsig.*] entry.
tsig_name = "my-primary-key"

# Use XoT (DNS over TLS) for zone transfers
# xot = { trust_anchor = "/etc/borondns-secondary/ca.pem" }

Multiple zones

[[zones]]
name       = "example.com."
primaries  = [{ address = "10.0.0.1", port = 53 }]
notify_sources = ["10.0.0.1"]
tsig_name  = "key-a"

[[zones]]
name       = "example.net."
primaries  = [{ address = "10.0.0.2", port = 53 }]
notify_sources = ["10.0.0.2"]
tsig_name  = "key-b"

[[zones]]
name       = "10.in-addr.arpa."
primaries  = [{ address = "10.0.0.1", port = 53 }]
notify_sources = ["10.0.0.1"]
tsig_name  = "key-a"

TSIG keys

TSIG keys authenticate zone transfers between the primary and BoronDNS:

[tsig."my-primary-key"]
# Algorithm: hmac-sha256 (recommended), hmac-sha512, hmac-sha384, hmac-sha1
algorithm = "hmac-sha256"

# Secret loaded from a file (preferred — keeps the secret out of the config)
secret_file = "/etc/borondns-secondary/keys/my-primary-key.key"

# Alternatively, inline base64-encoded secret (less secure):
# secret = "dGhpcyBpcyBhIHNhbXBsZSBzZWNyZXQga2V5IGZvciBkb2NzCg=="

Generate a new key:

# 32 random bytes, base64-encoded — suitable for hmac-sha256
openssl rand -base64 32 | sudo tee /etc/borondns-secondary/keys/my-primary-key.key
sudo chmod 640 /etc/borondns-secondary/keys/my-primary-key.key
sudo chown borondns:borondns /etc/borondns-secondary/keys/my-primary-key.key

Process settings

[process]
# Maximum open file descriptors. BoronDNS checks this at startup.
# Default: system limit.
# max_open_files = 65536

# Drop privileges to this user after binding sockets.
# run_as_user = "borondns"

# Disable core dumps (recommended in production).
disable_core_dumps = true

# Block new privileges after startup.
no_new_privileges = true

Logging

[log]
# Level: error, warn, info, debug, trace. Default: info
level = "info"

# Format: text (human-readable), json (structured, for log aggregators)
format = "json"

Health and metrics

[health]
# Bind the management HTTP listener. Inherits from [interfaces.mgmt] by default.
# bind_address = "127.0.0.1"
# port = 8080

# Enable Prometheus /metrics endpoint. Default: true
metrics_enabled = true

Access control

[acl]
# Accept NOTIFY messages only from these addresses (CIDR or exact).
# When unset, NOTIFY is accepted from any source (but still authenticated by TSIG).
notify_allow = ["10.0.0.0/8", "192.168.1.0/24"]

Rate limiting (RRL) and DNS Cookies

[rrl]
# Enable Response Rate Limiting.
enabled = true

# Responses per second per client before slipping or dropping.
responses_per_second = 20

# Window size in seconds for the RRL sliding window.
window = 15

[dns_cookies]
# Enable RFC 7873 / RFC 9018 DNS Cookies.
enabled = true

# Shared server secret(s) for anycast/load-balanced deployments.
# Two secrets enable staged rollover.
# server_secret  = "/etc/borondns-secondary/cookie-secret-current.key"
# server_secret2 = "/etc/borondns-secondary/cookie-secret-previous.key"

Full example

[interfaces.dns]
bind_address = "0.0.0.0"
port = 53

[interfaces.mgmt]
bind_address = "127.0.0.1"
port = 8080

[log]
level  = "info"
format = "json"

[health]
metrics_enabled = true

[acl]
notify_allow = ["10.0.0.0/8"]

[process]
disable_core_dumps = true
no_new_privileges  = true

[rrl]
enabled              = true
responses_per_second = 20

[tsig."primary-key"]
algorithm   = "hmac-sha256"
secret_file = "/etc/borondns-secondary/keys/primary-key.key"

[[zones]]
name           = "example.com."
primaries      = [{ address = "10.0.0.1", port = 53 }]
notify_sources = ["10.0.0.1"]
tsig_name      = "primary-key"

[[zones]]
name           = "10.in-addr.arpa."
primaries      = [{ address = "10.0.0.1", port = 53 }]
notify_sources = ["10.0.0.1"]
tsig_name      = "primary-key"

Next: TSIG Setup — key generation and primary server configuration.