initial commit

This commit is contained in:
developer committed 2026-09-27 11:20:34 +00:00
1 parent 5b935301e5
commit 85453852d5
105 files changed
+24846

No files matched your search

+204
View File
@@ -0,0 +1,204 @@
# fancy-dns — example configuration.
#
# Every value below is a default; delete what you do not need. The admin API
# rewrites this file when you save from the console, so keep it in git and
# review the diff.
version: 0
server:
# In-flight upstream resolutions. Excess queries get SERVFAIL rather than
# queueing without bound.
max_concurrent: 1024
timeouts:
udp: 2s
tcp: 4s
tls: 4s
query: 5s
upstream: 2s
list_fetch: 60s
dns:
udp: ["0.0.0.0:53", "[::]:53"]
tcp: ["0.0.0.0:53", "[::]:53"]
# Advertised EDNS0 buffer size for our own answers.
max_udp_size: 1232
serve_stale: 0s
edns0:
# Forward the client's EDNS-Client-Subnet so upstream picks a nearby
# anycast location.
client_subnet: true
ipv4_bits: 24
ipv6_bits: 56
preserve: true
dot:
enabled: false
listen: ["0.0.0.0:853"]
cert_file: /etc/fancy-dns/tls/fullchain.pem
key_file: /etc/fancy-dns/tls/privkey.pem
min_version: "1.2"
doh:
enabled: false
listen: ["0.0.0.0:443"]
base_path: /dns-query
cert_file: /etc/fancy-dns/tls/fullchain.pem
key_file: /etc/fancy-dns/tls/privkey.pem
min_version: "1.2"
allow_post: true
transport:
mode: auto
upstream:
# parallel: race them, take the first good answer. random: try N at random.
# failover: walk the list in order.
policy: parallel
max_attempts: 3
healthcheck_interval: 30s
breaker_threshold: 5
breaker_cooldown: 30s
servers:
- addr: 9.9.9.9:53
proto: udp
health_name: dns.quad9.net
- addr: 149.112.112.112:53
proto: udp
health_name: dns.quad9.net
- addr: 1.1.1.1:53
proto: tls
server_name: cloudflare-dns.com
- addr: 9.9.9.9:853
proto: tls
server_name: dns.quad9.net
cache:
enabled: true
size: 200000
shards: 32
min_ttl: 0s
max_ttl: 1h
# Keep expired answers around this long so a dead upstream costs latency,
# not availability.
serve_stale: 30m
prefetch: true
negative_ttl: 30m
persist:
enabled: true
path: data/cache.db
interval: 30s
max_entries: 500000
load_on_start: true
prewarm: []
blocklist:
enabled: true
# nxdomain | zero | redirect | drop | refused
default_action: nxdomain
response_ip: 0.0.0.0
response_ipv6: "::"
response_ttl: 60s
# RPZ-style policy zones and/or local authoritative data, as master files.
local_zones: []
# Inline rules. "*.example.com" covers subdomains, "**.example.com" covers
# the apex too, a bare name matches only itself.
block_entries: []
allow_entries: []
lists:
- name: haas
format: plain
url: https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
path: data/lists/hosts
enabled: true
refresh: 24h
categories: [ads, tracking]
- name: easylist
format: adblock
url: https://easylist.to/easylist/easylist.txt
path: data/lists/easylist.txt
enabled: false
refresh: 24h
categories: [ads]
- name: local-rpz
format: rpz
path: zones/local.rpz.zone
enabled: true
refresh: 0s
acl:
# allow | deny | block_only
default_policy: allow
default_rate_limit: 0
groups:
- name: guests
comment: Blocklists apply, but the kitchen-sink allowlist does not.
match:
cidrs: ["192.168.90.0/24"]
policy: block_only
rate_limit: 50
- name: printers
comment: No recursion at all; they only need DHCP.
match:
cidrs: ["192.168.91.0/24"]
policy: deny
qlog:
enabled: true
path: data/queries.db
max_entries: 200000
flush_interval: 1s
# 1.0 logs every query. Lower it on a busy instance: the per-domain
# counters are what the dashboard actually needs.
sample_rate: 1.0
log_blocked: true
log_cached: false
log_errors: true
live_buffer: 2000
top_domains: 5000
top_ttl: 5m
cluster:
enabled: false
# node_id: dns-1
# advertise: http://10.0.0.10:8080
peer_ttl: 15s
valkey:
addrs: ["valkey:6379"]
prefix: fancydns
pool_size: 10
dial_timeout: 2s
read_timeout: 2s
# Only the lease holder fetches lists, so N instances do not hit a
# mirror N times.
leader_ttl: 30s
api:
enabled: true
listen: ["127.0.0.1:8080"]
# tls_listen: ["0.0.0.0:8443"]
base_path: /api
ui: true
allow_config_write: true
allow_blocklist_write: true
# Only these proxies may set X-Forwarded-For; anything else is ignored, so a
# client cannot spoof its identity past the ACL or the rate limiter.
trusted_proxies: []
cors_origins: []
auth:
# none | apikey | basic
mode: apikey
api_keys: ["CHANGE-ME-long-random-string"]
read_only_api_keys: []
trust_loopback: true
session_ttl: 12h
rate_limit:
per_minute: 600
failures: 10
lockout: 5m
metrics:
enabled: true
path: /metrics
protect: true
log:
level: info
format: text
+25
View File
@@ -0,0 +1,25 @@
; Local authoritative data. fancy-dns answers for these names itself, which
; removes the need for a second nameserver for a handful of records.
$TTL 300
@ SOA ns1.lan. hostmaster.lan. 2024010101 3600 600 604800 300
@ NS ns1.lan.
@ NS ns2.lan.
ns1 A 192.168.1.2
ns2 A 192.168.1.3
router A 192.168.1.1
nas A 192.168.1.10
nas AAAA fd00::10
; A wildcard covers one label: printer.lan., host.lan., ...
*.lan A 192.168.1.50
; A wildcard deeper down.
*.internal.lan A 10.0.0.50
; Services.
_ntp._udp.lan. SRV 0 0 123 ns1.lan.
_ldap._tcp.lan. SRV 10 0 389 nas.lan.
_dmarc._domain.lan. TXT "v=DMARC1; p=reject; rua=mailto:dmarc.lan"
_lan. TXT "internal network, do not use on the open internet"
+23
View File
@@ -0,0 +1,23 @@
; Example RPZ-style policy zone.
;
; Drop everything from these services, for this host and its subdomains.
$TTL 60
@ SOA localhost. hostmaster.localhost. 1 3600 600 604800 60
@ NS localhost.
; *.doubleclick.net CNAME . -> NXDOMAIN
*.doubleclick.net CNAME .
*.ads.example.com CNAME .
*.tracker.example.net CNAME .
analytics.example.org CNAME .
; CNAME rpz-drop. -> answer with silence
*.noisy-cdn.example CNAME rpz-drop.
; CNAME rpz-passthru. -> ignore blocklists for this name
metrics.internal. CNAME rpz-passthru.
; A/AAAA records in a policy zone are returned verbatim, which is the cleanest
; way to point a blocked name at a local landing page.
blocked.example A 192.0.2.10
AAAA 2001:db8::10