Settings
hold reads YAML configuration from the path passed with --config. Using an
explicit path makes service deployments predictable:
hold --config /etc/hold/settings.yaml
The complete starter configuration is embedded below.
server:
host: 127.0.0.1
port: 53
rewriter:
is_recursive: true
blocklist:
url: https://small.oisd.nl/rpz
limit: 100
items:
- source:
name: '{SUBDOMAIN}\.service\.'
records: 'A|AAAA|CNAME'
target:
name: '{SUBDOMAIN}.lan.'
records: CNAME
- source:
name: '{SUBDOMAIN}\.lan\.'
records: 'A|AAAA|CNAME'
target:
name: 192.168.1.10
records: A
- source:
name: 'ads\.example\.'
records: 'A|AAAA|CNAME'
target: BLACKHOLE
client:
default:
url: 'https://{host}/dns-query'
host: dns.google
items:
- source:
name: '{SUBDOMAINS}lan\.'
records: 'A|AAAA|CNAME|PTR'
target:
host: 192.168.1.1
ttl_min: 0
ttl_defaults:
nxdomain: 0
Main sections
server.hostandserver.portselect the DNS listening address.server.rewritercontains the ordered rewrite rules and the downloaded blocklist. See Blocking for supported lists and matching behaviour.server.client.defaultis the default DNS-over-HTTPS resolver.server.client.itemsroutes matching queries to different resolvers. This is useful for local zones, VPN names, and reverse DNS.- Top-level
cacheoptionally changes the directory used for the downloaded blocklist cache.
Rules and upstreams are selected by full regular-expression matches, so literal
dots must be escaped as \.. DNS names are represented with their final dot.
hold also accepts settings through command-line arguments and environment
variables. Nested environment keys use __ and the package prefix is HOLD__;
for example, HOLD__SERVER__PORT=5353. YAML is recommended for rule sets because
the nested structures remain readable.
Command-line values take precedence over the settings file. Complex sections
such as server are passed as JSON and merged with their YAML values, so you can
temporarily change only the DNS port:
hold --config ./settings.yaml --server '{"port":5353}'
Running on port 53
The example uses the standard DNS port, 53. Linux normally prevents unprivileged processes from opening ports below 1024. You can lower the kernel's unprivileged port boundary to 53 until the next reboot:
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=53
This is a system-wide change: unprivileged processes will be able to bind any
otherwise-available port from 53 upward. If that trade-off is unsuitable, grant
the service a narrowly scoped bind capability through your service manager.
Running sudo hold ... is also possible, but running the entire DNS service as
root is not recommended.
The Control API is launched alongside DNS and provides endpoints to clear the response cache, refresh the blocklist, and toggle blocking.