This guide covers configuration of Knot Resolver for both version 6.x (YAML/JSON) and version 5.x (Lua).
⚠️ Important Version Note:
- Version 6.x uses declarative YAML/JSON configuration with kres-manager
- Version 5.x uses Lua scripting configuration
- Configuration formats are not compatible between versions
| Aspect | Version 6.x | Version 5.x |
|---|---|---|
| Format | YAML 1.1 or JSON | Lua scripting |
| File | /etc/knot-resolver/config.yaml |
/etc/knot-resolver/kresd.conf |
| Validation | Pre-validation with datamodel | Runtime Lua errors |
| Management | kres-manager + HTTP API | Console (kresctl) |
| Schema | JSON Schema available | N/A |
| Learning Curve | Easy (declarative) | Moderate (requires Lua) |
Location: /etc/knot-resolver/config.yaml
Structure:
# Main configuration sections
server:
# Network interfaces
dnssec:
# DNSSEC settings
cache:
# Cache configuration
forward:
# Upstream forwarders
tls:
# DNS over TLS
http:
# DNS over HTTPS
policy:
# Access control and policies
rate_limiting:
# Rate limiting
logging:
# Logging settings
monitoring:
# Monitoring and metrics
Location: /etc/knot-resolver/kresd.conf
Structure:
-- Global settings
interfaces { '0.0.0.0@53' }
-- Modules
modules = { 'dnssec', 'stats' }
-- Functions and configuration
forward('1.0.0.1')
cache.size = 500 * 1024 * 1024
-- Custom Lua scripting
add_action(function(state)
-- Custom logic
end)
# /etc/knot-resolver/config.yaml
server:
interfaces:
- "0.0.0.0:53"
- ":::53"
dnssec:
enable: true
forward:
- address: "1.0.0.1"
- address: "8.8.8.8"
cache:
max_size: 524288000 # 500 MB
-- /etc/knot-resolver/kresd.conf
interfaces { '0.0.0.0@53', '::@53' }
modules = { 'dnssec' }
forward('1.0.0.1')
forward('8.8.8.8')
cache.size = 500 * 1024 * 1024
Version 6.x:
kresctl validate
Version 5.x:
# Attempt reload to check syntax
sudo systemctl reload knot-resolver
Version 6.x:
server:
interfaces:
- "0.0.0.0:53" # IPv4 all interfaces
- ":::53" # IPv6 all interfaces
- "192.168.1.1:53" # Specific interface
Version 5.x:
interfaces {
'0.0.0.0@53',
'::@53',
'192.168.1.1@53'
}
Version 6.x:
server:
workers: 4 # Worker threads
network:
tcp_max_clients: 1000
udp_max_clients: 10000
tcp_timeout: 30 # seconds
Version 5.x:
workers = 4
tcp.max_clients = 1000
udp.max_clients = 10000
tcp.timeout = 30
Version 6.x:
dnssec:
enable: true
# Optional: Custom trust anchor
# trust_anchor: "/etc/knot-resolver/trust-anchor.xml"
# Validation options
validation_failure_log: true
Version 5.x:
modules = { 'dnssec' }
-- Optional: Custom trust anchor
-- trust_anchors.add_file('/etc/knot-resolver/trust-anchor.xml')
-- Validation options
dnssec.validation_failure_log = true
Version 6.x:
dnssec:
enable: true
trust_anchor: "/etc/knot-resolver/root.key"
Version 5.x:
modules = { 'dnssec' }
trust_anchors.add_file('/etc/knot-resolver/root.key')
# Version 6.x
kresctl dnssec check
kresctl stats | grep dnssec
# Version 5.x
sudo kresctl
> dnssec.check()
> stats()
Version 6.x:
cache:
max_size: 1073741824 # 1 GB
Version 5.x:
cache.size = 1024 * 1024 * 1024 -- 1 GB
Version 6.x:
cache:
max_size: 524288000
max_ttl: 604800 # 1 week maximum
min_ttl: 60 # 1 minute minimum
negative_ttl: 3600 # Negative cache TTL
Version 5.x:
cache.size = 500 * 1024 * 1024
cache.max_ttl = 604800
cache.min_ttl = 60
cache.negative_ttl = 3600
cache:
prefetch:
enable: true
expiring: true # Prefetch expiring records
prediction: true # Predict frequently used records
threshold: 10 # Prefetch when TTL < threshold seconds
cache:
serve_stale:
enable: true
max_age: 86400 # Serve stale up to 1 day
# View cache statistics
kresctl cache stats # v6
sudo kresctl > cache.stats() # v5
# Clear cache
kresctl cache clear # v6
sudo kresctl > cache.clear() # v5
# Get specific record
kresctl cache get example.com # v6
Version 6.x:
forward:
- address: "1.0.0.1"
- address: "8.8.8.8"
- address: "9.9.9.9"
Version 5.x:
forward('1.0.0.1')
forward('8.8.8.8')
forward('9.9.9.9')
Version 6.x:
forward:
- address: "1.0.0.1"
tls_auth_name: "cloudflare-dns.com"
- address: "8.8.8.8"
tls_auth_name: "dns.google"
Version 5.x:
forward('1.0.0.1', { tls_auth_name = 'cloudflare-dns.com' })
forward('8.8.8.8', { tls_auth_name = 'dns.google' })
Version 6.x:
forward:
- domain: "internal.example.com"
address: "192.168.1.10"
- domain: "corp.local"
address: "192.168.1.11"
- address: "1.0.0.1" -- Default forwarder
Version 5.x:
forward('internal.example.com', '192.168.1.10')
forward('corp.local', '192.168.1.11')
forward('1.0.0.1') -- Default
fallback:
enable: true
timeout: 5000 # ms before trying next forwarder
retry: 3 # Number of retries
Version 6.x:
tls:
enable: true
listen:
- address: "0.0.0.0:853"
cert: "/etc/knot-resolver/certs/tls.crt"
key: "/etc/knot-resolver/certs/tls.key"
# TLS settings
ciphers: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
min_protocol: "TLSv1.2"
Version 5.x:
modules = { 'tls' }
tls('0.0.0.0:853',
'/etc/knot-resolver/certs/tls.crt',
'/etc/knot-resolver/certs/tls.key')
tls_config {
ciphers = 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384',
min_protocol = 'TLSv1.2'
}
Version 6.x:
forward:
- address: "1.0.0.1"
tls_auth_name: "cloudflare-dns.com"
- address: "8.8.8.8"
tls_auth_name: "dns.google"
Version 5.x:
forward('1.0.0.1', { tls_auth_name = 'cloudflare-dns.com' })
forward('8.8.8.8', { tls_auth_name = 'dns.google' })
tls:
enable: true
auto_reload: true # Auto-reload certificates on change
reload_interval: 3600 # Check every hour
Version 6.x:
http:
enable: true
listen:
- address: "0.0.0.0:443"
cert: "/etc/knot-resolver/certs/tls.crt"
key: "/etc/knot-resolver/certs/tls.key"
path: "/dns-query"
# HTTP/2 settings
max_concurrent_streams: 100
Version 5.x:
modules = { 'http2' }
http2('0.0.0.0:443',
'/etc/knot-resolver/certs/tls.crt',
'/etc/knot-resolver/certs/tls.key')
http2.path = '/dns-query'
Version 6.x:
http:
enable: true
authentication:
type: "basic" # or "token"
users:
- username: "admin"
password: "secure-password"
Version 6.x:
policy:
access_control:
- network: "10.0.0.0/8"
action: "allow"
- network: "192.168.0.0/16"
action: "allow"
- network: "0.0.0.0/0"
action: "deny" -- Deny all others
Version 5.x:
access_control('10.0.0.0/8', policy.ALLOW)
access_control('192.168.0.0/16', policy.ALLOW)
access_control('0.0.0.0/0', policy.DENY)
policy:
views:
- name: "internal"
match:
- network: "192.168.0.0/16"
forward:
- address: "192.168.1.10"
- name: "external"
match:
- network: "0.0.0.0/0"
forward:
- address: "1.0.0.1"
Version 6.x:
rate_limiting:
enable: true
limit: 100 # queries per second per IP
window: 1 # Time window in seconds
action: "drop" -- or "refuse"
Version 5.x:
rate_limit = 100 -- queries per second per IP
rate_limiting:
enable: true
# Per-network limits
limits:
- network: "10.0.0.0/8"
limit: 200
- network: "0.0.0.0/0"
limit: 50
# Whitelist
whitelist:
- "192.168.1.1"
- "192.168.1.2"
Version 6.x:
policy:
rpz:
- file: "/etc/knot-resolver/malware.rpz"
action: "drop"
- file: "/etc/knot-resolver/ads.rpz"
action: "nxdomain"
Version 5.x:
modules = { 'rpz' }
rpz {
file = '/etc/knot-resolver/malware.rpz',
action = policy.DROP
}
rpz {
file = '/etc/knot-resolver/ads.rpz',
action = policy.NXDOMAIN
}
-- Custom query filtering
add_action(function(state)
-- Block specific domains
if state.qname:endswith('malware-domain.com') then
state:drop()
end
-- Log specific queries
if state.qname:endswith('suspicious.com') then
kr.log_info('Suspicious query: ' .. tostring(state.qname))
end
end)
-- Custom response modification
add_answer_filter(function(state)
-- Add custom EDNS options
-- Modify responses
end)
Version 6.x:
policy:
static_hosts:
- name: "internal.example.com"
address: "192.168.1.10"
- name: "printer.local"
address: "192.168.1.50"
Version 5.x:
hints.set('internal.example.com', '192.168.1.10')
hints.set('printer.local', '192.168.1.50')
Version 6.x:
logging:
level: "notice" -- crit, err, warning, notice, info, debug
Version 5.x:
log_level = 'notice'
-- Log to syslog
log_target('syslog')
-- Log to stderr
log_target('stderr')
-- Log to file
log_target('file', '/var/log/knot-resolver.log')
logging:
level: "debug"
groups:
- "cache"
- "network"
- "dnssec"
- "policy"
logging:
dnstap:
enable: true
log_queries: false
log_responses: true
socket: "/var/run/knot-resolver/dnstap.sock"
Version 6.x:
monitoring:
metrics: true
port: 8453
namespace: "resolver_"
Version 5.x:
modules = { 'stats', 'http' }
http.prometheus.namespace = 'resolver_'
modules = {
graphite = {
prefix = hostname() .. worker.id,
host = '127.0.0.1',
port = 2003,
interval = 5 * sec,
tcp = false
}
}
# Version 6.x
kresctl stats
kresctl stats frequent # Most frequent queries
kresctl stats upstreams # Upstream server stats
# Version 5.x
sudo kresctl
> stats()
> stats.frequent()
> stats.upstreams()
sudo cp /etc/knot-resolver/kresd.conf /etc/knot-resolver/kresd.conf.backup
sudo cp -r /etc/knot-resolver /etc/knot-resolver.backup
# Debian/Ubuntu
sudo apt update
sudo apt install --only-upgrade knot-resolver
# Fedora/RHEL
sudo dnf upgrade knot-resolver
# Automatic migration (if available)
kresctl migrate
# Or manual conversion
Basic Configuration:
| Version 5.x (Lua) | Version 6.x (YAML) |
|---|---|
interfaces { '0.0.0.0@53' } |
server.interfaces: ["0.0.0.0:53"] |
modules = { 'dnssec' } |
dnssec.enable: true |
forward('1.0.0.1') |
forward: [{address: "1.0.0.1"}] |
cache.size = 500MB |
cache.max_size: 524288000 |
Complete Example Conversion:
Version 5.x:
interfaces { '0.0.0.0@53', '::@53' }
modules = { 'dnssec', 'stats' }
forward('1.0.0.1')
forward('8.8.8.8')
cache.size = 500 * 1024 * 1024
rate_limit = 100
Version 6.x:
server:
interfaces:
- "0.0.0.0:53"
- ":::53"
dnssec:
enable: true
forward:
- address: "1.0.0.1"
- address: "8.8.8.8"
cache:
max_size: 524288000
rate_limiting:
enable: true
limit: 100
monitoring:
metrics: true
kresctl validate
sudo systemctl restart knot-resolver
The following experimental/debugging options were removed in version 6:
/dnssec/refresh-time/dnssec/hold-down-time/dnssec/time-skew-detection/logging/debugging/max-workers/webmgmtThese are now Lua-only or managed differently.
# Version 6.x
kresctl validate
# Common errors:
# - Invalid port number
# - Unknown configuration key
# - Invalid value type
# Check logs
sudo journalctl -u knot-resolver -f
# Check configuration syntax
kresctl validate
# Verify file permissions
ls -la /etc/knot-resolver/
# Debian/Ubuntu
sudo apt install knot-resolver=5.7.6-1
sudo systemctl restart knot-resolver
# Restore backup
sudo cp /etc/knot-resolver.backup/kresd.conf /etc/knot-resolver/
Every DNS resolver deployment is unique. We provide consulting for:
Get personalized assistance: office@linux-server-admin.com | Contact Page