#########################################
module-config: "respip validator iterator" # v1.08 add 'respip' for rpz feature @juched
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: 10.0.0.0/8 allow
access-control: 172.16.0.0/12 allow # v1.10 Martineau Fix CIDR 16->12
access-control: 192.168.0.0/16 allow # v1.10 dave14305 Fix CIDR 24->16
access-control: 103.86.96.0/16 allow
access-control: 103.86.99.0/16 allow
# RFC1918 private IP address - Protects against DNS Rebinding
private-address: 127.0.0.0/8
private-address: 169.254.0.0/16
private-address: 10.0.0.0/8
private-address: 172.16.0.0/12
private-address: 192.168.0.0/16
private-address: fd00::/8 # v1.11 Martineau
private-address: fe80::/10 # v1.11 Martineau
dns64-ignore-aaaa: ".*.*"
do-not-query-address: ::/0
do-not-query-address: ::1
do-ip4: yes
do-udp: yes
do-tcp: yes
prefer-ip4: yes
prefer-ip6: no
#########################################
# integration IPV6
#
do-ip6: no
private-address: ::/0 # v1.11 Martineau Enhance 'do-ip6: no' i.e. explicitly drop ALL IPv6 responses
# do-ip6: no
# edns-buffer-size: 1200 # v1.11 as per @Linux_Chemist https://www.snbforums.com/threads/u...aller-utility-for-unbound-recursive-dns-serve>
# interface: ::0
# access-control: ::0/0 refuse
# access-control: ::1 refuse
# private-address: fd00::/8
# private-address: fe80::/10
#########################################
#module-config: "dns64 respip validator iterator" # v1.08 v1.03 v1.01 perform a query against AAAA record exists
#dns64-prefix: 64:FF9B::/96 # v1.03 v1.01
tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt" # v1.01 as per dave14305 minimal config
# no threads and no memory slabs for threads
num-threads: 4
msg-cache-slabs: 4
rrset-cache-slabs: 4
infra-cache-slabs: 4
key-cache-slabs: 4
ip-ratelimit-slabs: 4
ratelimit-slabs: 4
# tiny memory cache
extended-statistics: yes # v1.06 Martineau for @juched GUI TAB
key-cache-size: 50m
msg-cache-size: 50m
rrset-cache-size: 100m
ip-ratelimit-size: 16m
ratelimit-size: 16m
http-query-buffer-size: 16m
http-response-buffer-size: 16m
stream-wait-size: 50m
quic-size: 16m
cache-max-ttl: 14400 # v1.08 Martineau
cache-min-ttl: 0 # v1.08 Martineau
# prefetch
prefetch: yes
prefetch-key: yes
minimal-responses: yes
serve-expired: yes
serve-expired-ttl: 86400 # v1.12 as per @juched
serve-expired-ttl-reset: yes # v1.13 as per @jumpsmm7 Set the TTL of expired records to the serve-expired-ttl value after a failed attempt to retrieve the record from upstream.
incoming-num-tcp: 950
outgoing-num-tcp: 200
num-queries-per-thread: 100
outgoing-range: 200
ip-ratelimit: 2000 # v1.04 as per @L&LD as it impacts ipleak.net?
edns-buffer-size: 1200 # v1.01 as per dave14305 minimal config
max-udp-size: 2505 # v1.13 as per @jumpsmm7 mitigate DDOS threats when using dnssec, reduce potential for fragmentation.
#outgoing-port-avoid: 0-32767 # v1.13 as per @jumpsmm7 avoid grabbing udp ports commonly used / only for users with UDP port availability problems
#outgoing-port-permit: 32768-65535 # v1.13 as per @jumpsmm7 ports to permit / Not necessary if port-avoid is not used. limits port randomization.
jostle-timeout: 2000
sock-queue-timeout: 5
infra-cache-numhosts: 40000
discard-timeout: 6200
unwanted-reply-threshold: 5000000
infra-keep-probing: no
infra-host-ttl: 900
so-reuseport: yes
tcp-reuse-timeout: 60000
msg-buffer-size: 65552
max-global-quota: 600
delay-close: 60000
http-max-streams: 600
tls-use-sni: no
pad-responses: yes
pad-responses-block-size: 400
pad-queries: yes
pad-queries-block-size: 109
val-bogus-ttl: 90
wait-limit-cookie: 60000
wait-limit: 6000
infra-cache-min-rtt: 60
infra-cache-max-rtt: 180000
tcp-idle-timeout: 60000
max-reuse-tcp-queries: 600
tcp-auth-query-timeout: 6000
unknown-server-time-limit: 6000
neg-cache-size: 8m
val-sig-skew-min: 3600
val-sig-skew-max: 86400
cache-min-negative-ttl: 0
cache-max-negative-ttl: 3600
serve-expired-client-timeout: 6000
iter-scrub-ns: 20
iter-scrub-cname: 11
max-sent-count: 32
answer-cookie: yes
target-fetch-policy: "0 0 0 0 0 0 0 0 0 0 0 0"
ip-ratelimit-cookie: 60000
val-max-restart: 5
val-nsec3-keysize-iterations: "1024 150 2048 150 4096 150"
serve-expired-reply-ttl: 45
outbound-msg-retry: 5
serve-original-ttl: yes
max-query-restarts: 11
ip-freebind: yes
ip-ratelimit-factor: 10
ratelimit-factor: 10
udp-connect: yes
tcp-mss: 1200
outgoing-tcp-mss: 1150
# Ensure kernel buffer is large enough to not lose messages in traffic spikes
#so-rcvbuf: 2m # v1.05 Martineau see DEFAULT /proc/sys/net/core/rmem_default
#so-sndbuf: 2m
#########################################
# Options for integration with TCP/TLS Stubby
# udp-upstream-without-downstream: no
#########################################
# gentle on recursion
hide-identity: yes
hide-version: yes
do-not-query-localhost: yes
qname-minimisation: yes
harden-glue: yes
harden-below-nxdomain: yes
rrset-roundrobin: yes
aggressive-nsec: yes
deny-any: yes
use-caps-for-id: yes
harden-referral-path: no
harden-algo-downgrade: yes
harden-large-queries: yes
harden-short-bufsize: yes
val-clean-additional: yes
harden-dnssec-stripped: yes
qname-minimisation-strict: no
harden-unverified-glue: yes
hide-http-user-agent: no
# Self jail Unbound with user "nobody" to /var/lib/unbound
username: "nobody"
directory: "/opt/var/lib/unbound"
chroot: "/opt/var/lib/unbound"
# The pid file
pidfile: "/opt/var/run/unbound.pid"
# ROOT Server's
root-hints: "/opt/var/lib/unbound/root.hints"
# DNSSEC
auto-trust-anchor-file: "/opt/var/lib/unbound/root.key"
(fixes vpn ping 60 and ping restart 180 when VPN is binded) (infra-cache-max-rtt: 180000)
surgical precision.
Lowered cache values as they were set to high in my config
unbound.docs.nlnetlabs.nl
this is official guide if you have any questions
Copy and paste if you like the setup (1 gig ram 4 core router setup)
tuned for VPN
remote-cert-tls server
remote-random
nobind
resolv-retry infinite
persist-key
persist-tun
auth-nocache
tls-version-min 1.2
tls-version-max 1.3
tls-ciphersuites TLS_AES_256_GCM_SHA384
tls-cert-profile preferred
data-ciphers AES-256-GCM
tls-groups X25519
verify-x509-name CN=ca1407.nordvpn.com
reneg-sec 3600
tun-mtu 1500
tun-mtu-extra 32
mssfix 1450
ping 60
ping-restart 180
ping-timer-rem
pull
pull-filter ignore "ifconfig-ipv6"
pull-filter ignore "route-ipv6"
pull-filter ignore "redirect-gateway ipv6"
pull-filter ignore "dhcp-option DNS"
pull-filter ignore "dhcp-option DNS6"
pull-filter ignore "block-outside-dns"
block-ipv6
mute-replay-warnings
#log /tmp/vpn.log
Most vales are changed to respect Authoritative DNS servers set the Time to Live (TTL). Best used with Dynamic IP from wan or VPN. If you have this type of setup these values might interest you.
use vpn director and add 192.168.0.0/16 to killswitch and thank me later (same as unbounds config)
pull-filter ignore "block-outside-dns" discards the server's block-outside-dns push, which would otherwise block non-VPN DNS traffic . This avoids conflicts when using local resolvers like Unbound
dhcp-option DNS 127.0.0.1 overrides any server-pushed DNS servers, setting your system's resolver exclusively to localhost (Unbound). Combined, they ensure VPN connections don't hijack DNS while maintaining leak protection via Unbound's recursive forwarding over the tunnel.
Local: root → TLD → authoritative
I did a dig test with this config with Nord open VPN and it worked perfect.
Client app → 127.0.0.1:53 (forced by dhcp-option) Unbound (recursive, do-ip6: no) (all upstream queries)VPN tun0 interface → root/TLD servers
Full Recursive (Privacy-Max)
Feb 7 20:49:37 ovpn-client1[31980]: [caxxxx.nordvpn.com] Peer Connection Initiated with [AF_INET]xxxxxxxxxxx
Feb 7 20:49:37 ovpn-client1[31980]: TLS: move_session: dest=TM_ACTIVE src=TM_INITIAL reinit_src=1
Feb 7 20:49:37 ovpn-client1[31980]: TLS: tls_multi_process: initial untrusted session promoted to trusted
Feb 7 20:49:39 ovpn-client1[31980]: SENT CONTROL [caxxxx.nordvpn.com]: 'PUSH_REQUEST' (status=1)
Feb 7 20:49:39 ovpn-client1[31980]: PUSH: Received control message: 'PUSH_REPLY,redirect-gateway def1,dhcp-option DNS 103.86.96.100,dhcp-option DNS 103.86.99.100,explicit-exit-notify,comp-lzo no,route-gateway 10.100.0.1,topology subnet,ping 60,ping-restart 180,ifconfig 10.100.0.2 255.255.0.0,peer-id 14,cipher AES-256-GCM'
Feb 7 20:49:39 ovpn-client1[31980]: Pushed option removed by filter: 'dhcp-option DNS 103.86.96.100'
Feb 7 20:49:39 ovpn-client1[31980]: Pushed option removed by filter: 'dhcp-option DNS 103.86.99.100'
Feb 7 20:49:39 ovpn-client1[31980]: OPTIONS IMPORT: --ifconfig/up options modified
Feb 7 20:49:39 ovpn-client1[31980]: OPTIONS IMPORT: route options modified
Feb 7 20:49:39 ovpn-client1[31980]: OPTIONS IMPORT: route-related options modified
Feb 7 20:49:39 ovpn-client1[31980]: TUN/TAP device tun11 opened
Feb 7 20:49:39 ovpn-client1[31980]: TUN/TAP TX queue length set to 1000
Feb 7 20:49:39 ovpn-client1[31980]: /usr/sbin/ip link set dev tun11 up mtu 1500
Feb 7 20:49:39 ovpn-client1[31980]: /usr/sbin/ip link set dev tun11 up
Feb 7 20:49:39 ovpn-client1[31980]: /usr/sbin/ip addr add dev tun11 10.100.0.2/16 broadcast +
Feb 7 20:49:39 ovpn-client1[31980]: ovpn-up 1 client tun11 1500 0 10.100.0.2 255.255.0.0 init
Feb 7 20:49:39 openvpn-routing: Setting client 1 routing table's default route through the tunnel
Feb 7 20:49:39 vpndirector: Routing to vpn from 192.168.0.0/16 to any through ovpnc1
Feb 7 20:49:39 ovpn-client1[31980]: Data Channel: cipher 'AES-256-GCM', peer-id: 14, compression: 'stub'
Feb 7 20:49:39 ovpn-client1[31980]: Timers: ping 60, ping-restart 180
Feb 7 20:49:39 ovpn-client1[31980]: Protocol options: explicit-exit-notify 1
Feb 7 20:49:41 ovpn-client1[31980]: Initialization Sequence Completed
module-config: "respip validator iterator" # v1.08 add 'respip' for rpz feature @juched
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: 10.0.0.0/8 allow
access-control: 172.16.0.0/12 allow # v1.10 Martineau Fix CIDR 16->12
access-control: 192.168.0.0/16 allow # v1.10 dave14305 Fix CIDR 24->16
access-control: 103.86.96.0/16 allow
access-control: 103.86.99.0/16 allow
# RFC1918 private IP address - Protects against DNS Rebinding
private-address: 127.0.0.0/8
private-address: 169.254.0.0/16
private-address: 10.0.0.0/8
private-address: 172.16.0.0/12
private-address: 192.168.0.0/16
private-address: fd00::/8 # v1.11 Martineau
private-address: fe80::/10 # v1.11 Martineau
dns64-ignore-aaaa: ".*.*"
do-not-query-address: ::/0
do-not-query-address: ::1
do-ip4: yes
do-udp: yes
do-tcp: yes
prefer-ip4: yes
prefer-ip6: no
#########################################
# integration IPV6
#
do-ip6: no
private-address: ::/0 # v1.11 Martineau Enhance 'do-ip6: no' i.e. explicitly drop ALL IPv6 responses
# do-ip6: no
# edns-buffer-size: 1200 # v1.11 as per @Linux_Chemist https://www.snbforums.com/threads/u...aller-utility-for-unbound-recursive-dns-serve>
# interface: ::0
# access-control: ::0/0 refuse
# access-control: ::1 refuse
# private-address: fd00::/8
# private-address: fe80::/10
#########################################
#module-config: "dns64 respip validator iterator" # v1.08 v1.03 v1.01 perform a query against AAAA record exists
#dns64-prefix: 64:FF9B::/96 # v1.03 v1.01
tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt" # v1.01 as per dave14305 minimal config
# no threads and no memory slabs for threads
num-threads: 4
msg-cache-slabs: 4
rrset-cache-slabs: 4
infra-cache-slabs: 4
key-cache-slabs: 4
ip-ratelimit-slabs: 4
ratelimit-slabs: 4
# tiny memory cache
extended-statistics: yes # v1.06 Martineau for @juched GUI TAB
key-cache-size: 50m
msg-cache-size: 50m
rrset-cache-size: 100m
ip-ratelimit-size: 16m
ratelimit-size: 16m
http-query-buffer-size: 16m
http-response-buffer-size: 16m
stream-wait-size: 50m
quic-size: 16m
cache-max-ttl: 14400 # v1.08 Martineau
cache-min-ttl: 0 # v1.08 Martineau
# prefetch
prefetch: yes
prefetch-key: yes
minimal-responses: yes
serve-expired: yes
serve-expired-ttl: 86400 # v1.12 as per @juched
serve-expired-ttl-reset: yes # v1.13 as per @jumpsmm7 Set the TTL of expired records to the serve-expired-ttl value after a failed attempt to retrieve the record from upstream.
incoming-num-tcp: 950
outgoing-num-tcp: 200
num-queries-per-thread: 100
outgoing-range: 200
ip-ratelimit: 2000 # v1.04 as per @L&LD as it impacts ipleak.net?
edns-buffer-size: 1200 # v1.01 as per dave14305 minimal config
max-udp-size: 2505 # v1.13 as per @jumpsmm7 mitigate DDOS threats when using dnssec, reduce potential for fragmentation.
#outgoing-port-avoid: 0-32767 # v1.13 as per @jumpsmm7 avoid grabbing udp ports commonly used / only for users with UDP port availability problems
#outgoing-port-permit: 32768-65535 # v1.13 as per @jumpsmm7 ports to permit / Not necessary if port-avoid is not used. limits port randomization.
jostle-timeout: 2000
sock-queue-timeout: 5
infra-cache-numhosts: 40000
discard-timeout: 6200
unwanted-reply-threshold: 5000000
infra-keep-probing: no
infra-host-ttl: 900
so-reuseport: yes
tcp-reuse-timeout: 60000
msg-buffer-size: 65552
max-global-quota: 600
delay-close: 60000
http-max-streams: 600
tls-use-sni: no
pad-responses: yes
pad-responses-block-size: 400
pad-queries: yes
pad-queries-block-size: 109
val-bogus-ttl: 90
wait-limit-cookie: 60000
wait-limit: 6000
infra-cache-min-rtt: 60
infra-cache-max-rtt: 180000
tcp-idle-timeout: 60000
max-reuse-tcp-queries: 600
tcp-auth-query-timeout: 6000
unknown-server-time-limit: 6000
neg-cache-size: 8m
val-sig-skew-min: 3600
val-sig-skew-max: 86400
cache-min-negative-ttl: 0
cache-max-negative-ttl: 3600
serve-expired-client-timeout: 6000
iter-scrub-ns: 20
iter-scrub-cname: 11
max-sent-count: 32
answer-cookie: yes
target-fetch-policy: "0 0 0 0 0 0 0 0 0 0 0 0"
ip-ratelimit-cookie: 60000
val-max-restart: 5
val-nsec3-keysize-iterations: "1024 150 2048 150 4096 150"
serve-expired-reply-ttl: 45
outbound-msg-retry: 5
serve-original-ttl: yes
max-query-restarts: 11
ip-freebind: yes
ip-ratelimit-factor: 10
ratelimit-factor: 10
udp-connect: yes
tcp-mss: 1200
outgoing-tcp-mss: 1150
# Ensure kernel buffer is large enough to not lose messages in traffic spikes
#so-rcvbuf: 2m # v1.05 Martineau see DEFAULT /proc/sys/net/core/rmem_default
#so-sndbuf: 2m
#########################################
# Options for integration with TCP/TLS Stubby
# udp-upstream-without-downstream: no
#########################################
# gentle on recursion
hide-identity: yes
hide-version: yes
do-not-query-localhost: yes
qname-minimisation: yes
harden-glue: yes
harden-below-nxdomain: yes
rrset-roundrobin: yes
aggressive-nsec: yes
deny-any: yes
use-caps-for-id: yes
harden-referral-path: no
harden-algo-downgrade: yes
harden-large-queries: yes
harden-short-bufsize: yes
val-clean-additional: yes
harden-dnssec-stripped: yes
qname-minimisation-strict: no
harden-unverified-glue: yes
hide-http-user-agent: no
# Self jail Unbound with user "nobody" to /var/lib/unbound
username: "nobody"
directory: "/opt/var/lib/unbound"
chroot: "/opt/var/lib/unbound"
# The pid file
pidfile: "/opt/var/run/unbound.pid"
# ROOT Server's
root-hints: "/opt/var/lib/unbound/root.hints"
# DNSSEC
auto-trust-anchor-file: "/opt/var/lib/unbound/root.key"
(fixes vpn ping 60 and ping restart 180 when VPN is binded) (infra-cache-max-rtt: 180000)
surgical precision.
Lowered cache values as they were set to high in my config
- Hit ratio stays high (80-95%) for home traffic patterns.
- No memory pressure — avoids OOM kills during peak usage.
unbound.conf(5) — Unbound 1.24.2 documentation
unbound.docs.nlnetlabs.nl
this is official guide if you have any questions
Copy and paste if you like the setup (1 gig ram 4 core router setup)
tuned for VPN
remote-cert-tls server
remote-random
nobind
resolv-retry infinite
persist-key
persist-tun
auth-nocache
tls-version-min 1.2
tls-version-max 1.3
tls-ciphersuites TLS_AES_256_GCM_SHA384
tls-cert-profile preferred
data-ciphers AES-256-GCM
tls-groups X25519
verify-x509-name CN=ca1407.nordvpn.com
reneg-sec 3600
tun-mtu 1500
tun-mtu-extra 32
mssfix 1450
ping 60
ping-restart 180
ping-timer-rem
pull
pull-filter ignore "ifconfig-ipv6"
pull-filter ignore "route-ipv6"
pull-filter ignore "redirect-gateway ipv6"
pull-filter ignore "dhcp-option DNS"
pull-filter ignore "dhcp-option DNS6"
pull-filter ignore "block-outside-dns"
block-ipv6
mute-replay-warnings
#log /tmp/vpn.log
Most vales are changed to respect Authoritative DNS servers set the Time to Live (TTL). Best used with Dynamic IP from wan or VPN. If you have this type of setup these values might interest you.
use vpn director and add 192.168.0.0/16 to killswitch and thank me later (same as unbounds config)
pull-filter ignore "block-outside-dns" discards the server's block-outside-dns push, which would otherwise block non-VPN DNS traffic . This avoids conflicts when using local resolvers like Unbound
dhcp-option DNS 127.0.0.1 overrides any server-pushed DNS servers, setting your system's resolver exclusively to localhost (Unbound). Combined, they ensure VPN connections don't hijack DNS while maintaining leak protection via Unbound's recursive forwarding over the tunnel.
Local: root → TLD → authoritative
I did a dig test with this config with Nord open VPN and it worked perfect.
Client app → 127.0.0.1:53 (forced by dhcp-option) Unbound (recursive, do-ip6: no) (all upstream queries)VPN tun0 interface → root/TLD servers
Full Recursive (Privacy-Max)
Feb 7 20:49:37 ovpn-client1[31980]: [caxxxx.nordvpn.com] Peer Connection Initiated with [AF_INET]xxxxxxxxxxx
Feb 7 20:49:37 ovpn-client1[31980]: TLS: move_session: dest=TM_ACTIVE src=TM_INITIAL reinit_src=1
Feb 7 20:49:37 ovpn-client1[31980]: TLS: tls_multi_process: initial untrusted session promoted to trusted
Feb 7 20:49:39 ovpn-client1[31980]: SENT CONTROL [caxxxx.nordvpn.com]: 'PUSH_REQUEST' (status=1)
Feb 7 20:49:39 ovpn-client1[31980]: PUSH: Received control message: 'PUSH_REPLY,redirect-gateway def1,dhcp-option DNS 103.86.96.100,dhcp-option DNS 103.86.99.100,explicit-exit-notify,comp-lzo no,route-gateway 10.100.0.1,topology subnet,ping 60,ping-restart 180,ifconfig 10.100.0.2 255.255.0.0,peer-id 14,cipher AES-256-GCM'
Feb 7 20:49:39 ovpn-client1[31980]: Pushed option removed by filter: 'dhcp-option DNS 103.86.96.100'
Feb 7 20:49:39 ovpn-client1[31980]: Pushed option removed by filter: 'dhcp-option DNS 103.86.99.100'
Feb 7 20:49:39 ovpn-client1[31980]: OPTIONS IMPORT: --ifconfig/up options modified
Feb 7 20:49:39 ovpn-client1[31980]: OPTIONS IMPORT: route options modified
Feb 7 20:49:39 ovpn-client1[31980]: OPTIONS IMPORT: route-related options modified
Feb 7 20:49:39 ovpn-client1[31980]: TUN/TAP device tun11 opened
Feb 7 20:49:39 ovpn-client1[31980]: TUN/TAP TX queue length set to 1000
Feb 7 20:49:39 ovpn-client1[31980]: /usr/sbin/ip link set dev tun11 up mtu 1500
Feb 7 20:49:39 ovpn-client1[31980]: /usr/sbin/ip link set dev tun11 up
Feb 7 20:49:39 ovpn-client1[31980]: /usr/sbin/ip addr add dev tun11 10.100.0.2/16 broadcast +
Feb 7 20:49:39 ovpn-client1[31980]: ovpn-up 1 client tun11 1500 0 10.100.0.2 255.255.0.0 init
Feb 7 20:49:39 openvpn-routing: Setting client 1 routing table's default route through the tunnel
Feb 7 20:49:39 vpndirector: Routing to vpn from 192.168.0.0/16 to any through ovpnc1
Feb 7 20:49:39 ovpn-client1[31980]: Data Channel: cipher 'AES-256-GCM', peer-id: 14, compression: 'stub'
Feb 7 20:49:39 ovpn-client1[31980]: Timers: ping 60, ping-restart 180
Feb 7 20:49:39 ovpn-client1[31980]: Protocol options: explicit-exit-notify 1
Feb 7 20:49:41 ovpn-client1[31980]: Initialization Sequence Completed