-
Notifications
You must be signed in to change notification settings - Fork 100
Expand file tree
/
Copy pathnuma.toml
More file actions
248 lines (228 loc) · 12.4 KB
/
Copy pathnuma.toml
File metadata and controls
248 lines (228 loc) · 12.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
[server]
bind_addr = "0.0.0.0:53" # or a list: ["10.0.0.1:53", "127.0.0.1:53"]
api_port = 5380
# api_bind_addr = "127.0.0.1" # default; set to "0.0.0.0" for LAN dashboard access
# api_token = "…" # loopback is exempt, every other client needs this.
# Minted on first start (logged once, stored in
# data_dir) unless set here or via NUMA_API_TOKEN.
# data_dir = "/var/lib/numa" # where numa stores TLS CA and cert material
# Defaults: /var/lib/numa on linux (FHS),
# /usr/local/var/numa on macos (homebrew prefix),
# %PROGRAMDATA%\numa on windows. Override for
# containerized deploys or tests that can't
# write to the system path.
# filter_aaaa = true # on IPv4-only networks, answer AAAA queries with
# NODATA (NOERROR + empty answer) so Happy Eyeballs
# clients don't wait on a v6 attempt that can't
# succeed. Also strips `ipv6hint` from HTTPS/SVCB
# records (RFC 9460) so modern browsers (Chrome
# ≥103, Firefox, Safari) don't bypass the AAAA
# filter via SVCB hints. Local zones, overrides,
# and the .numa proxy are NOT filtered — you can
# still configure v6 records for local services.
# Default: false.
# ── Client-IP allowlist ────────────────────────────────────────────
# Required on WAN-facing binds, or numa becomes an open recursive
# resolver. Loopback always allowed. Denied peers: silent UDP drop,
# TLS close pre-handshake, DoH 403.
#
# allow_from = ["10.0.0.0/8", "192.168.0.0/16", "fd00::/8"]
# [upstream]
# mode = "forward" # "forward" (default) — relay to upstream
# # "recursive" — resolve from root hints (no address needed)
# # "odoh" — Oblivious DoH (see ODoH block below)
# address = "9.9.9.9" # single upstream (plain UDP)
# address = ["192.168.1.1", "9.9.9.9:5353"] # multiple upstreams — SRTT picks fastest
# address = "https://dns.quad9.net/dns-query" # DNS-over-HTTPS (encrypted)
# address = "tls://9.9.9.9#dns.quad9.net" # DNS-over-TLS (encrypted, port 853)
# fallback = ["8.8.8.8", "1.1.1.1"] # tried only when all primaries fail
# port = 53 # default port for addresses without :port
# timeout_ms = 3000
# hedge_ms = 0 # request hedging delay (ms). Default: 0 (off).
# # Set to e.g. 10 to fire a parallel upstream
# # request after 10ms of silence — rescues packet
# # loss (UDP), dispatch spikes (DoH), TLS stalls
# # (DoT). Doubles the upstream query count, so
# # leave off for quota'd providers (NextDNS,
# # Control D).
# ODoH (Oblivious DNS-over-HTTPS, RFC 9230). The relay sees your IP but
# not the question; the target sees the question but not your IP. Numa
# refuses same-operator relay+target configs by default (eTLD+1 check).
# [upstream]
# mode = "odoh"
# relay = "https://odoh-relay.numa.rs/relay"
# target = "https://odoh.cloudflare-dns.com/dns-query"
# strict = true # default: refuse to downgrade to `fallback`
# # on relay failure. Set false to allow a
# # non-oblivious fallback path.
# relay_ip = "178.104.229.30" # optional: pin IPs so numa doesn't leak the
# target_ip = "104.16.249.249" # relay/target hostnames via the bootstrap
# # resolver on cold boot when numa is its
# # own system DNS. See
# # recipes/odoh-upstream.md.
# root_hints = [ # only used in recursive mode
# "198.41.0.4", # a.root-servers.net (Verisign)
# "199.9.14.201", # b.root-servers.net (USC-ISI)
# "192.33.4.12", # c.root-servers.net (Cogent)
# "199.7.91.13", # d.root-servers.net (UMD)
# "192.203.230.10", # e.root-servers.net (NASA)
# "192.5.5.241", # f.root-servers.net (ISC)
# "192.112.36.4", # g.root-servers.net (US DoD)
# "198.97.190.53", # h.root-servers.net (US Army)
# "192.36.148.17", # i.root-servers.net (Netnod)
# "192.58.128.30", # j.root-servers.net (Verisign)
# "193.0.14.129", # k.root-servers.net (RIPE NCC)
# "199.7.83.42", # l.root-servers.net (ICANN)
# "202.12.27.33", # m.root-servers.net (WIDE)
# ]
# prime_tlds = [ # TLDs to pre-warm on startup (recursive mode)
# "com", "net", "org", "info", # gTLDs
# "io", "dev", "app", "xyz", "me",
# "eu", "uk", "de", "fr", "nl", # EU + European ccTLDs
# "it", "es", "pl", "se", "no",
# "dk", "fi", "at", "be", "ie",
# "pt", "cz", "ro", "gr", "hu",
# "bg", "hr", "sk", "si", "lt",
# "lv", "ee", "ch", "is",
# "co", "br", "au", "ca", "jp", # other major ccTLDs
# ]
# [[forwarding]] # per-suffix conditional forwarding rules
# suffix = "168.192.in-addr.arpa" # single suffix → one upstream
# upstream = "100.90.1.63:5361"
#
# [[forwarding]]
# suffix = ["home.local", "home.arpa"] # multiple suffixes → same upstream
# upstream = "10.0.0.1" # port 53 default
#
# [[forwarding]] # DoT upstream: tls://IP[:port]#hostname
# suffix = ["google.com", "goog"] # hostname is the TLS SNI / cert name
# upstream = "tls://9.9.9.9#dns.quad9.net" # port 853 default
#
# [[forwarding]] # DoH upstream: full https:// URL
# suffix = "example.corp"
# upstream = "https://dns.quad9.net/dns-query"
#
# [[forwarding]] # array of upstreams → SRTT-aware failover
# suffix = ["google.com", "goog"] # fastest-healthy first, dead one skipped
# upstream = [
# "tls://9.9.9.9#dns.quad9.net",
# "tls://149.112.112.112#dns.quad9.net",
# ]
# [blocking]
# enabled = true # set to false to disable ad blocking
# refresh_hours = 24
# lists = [
# "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/hosts/pro.txt",
# "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/wildcard/nsfw-onlydomains.txt", # adult-content (opt-in; hagezi ships nsfw only as wildcard/adblock, not hosts/)
# "file:///etc/numa/local-blocklist.txt", # local hosts-style file
# "/etc/numa/extra-blocks.txt", # bare absolute path also works
# ]
# allowlist = ["example.com"] # domains to never block
# ── Per-client domain policies ─────────────────────────────────────
# Block or allow specific domains for specific clients, on top of the
# global blocklist above. `block`/`allow` use the same adblock syntax
# as global lists. Loopback always bypasses. Rules layer in order: the
# first rule matching the client that has an explicit block/allow for
# the name wins; within a rule, allow beats block.
#
# [[client_policy]]
# from = ["192.168.1.0/24"] # clients this rule applies to (CIDRs/IPs)
# exclude = ["192.168.1.254"] # carve hosts out of the range (e.g. your own device)
# block = ["youtube.com", "*.tiktok.com"]
# allow = ["safe.example.com"] # exempt a name the global list would block
#
# [[client_policy]]
# from = ["10.0.0.50"] # a single host: stricter rules just for it
# block = ["reddit.com"]
# filter_aaaa = true # override global [server].filter_aaaa for these clients (alone makes a rule valid)
[cache]
max_entries = 100000
min_ttl = 60
max_ttl = 86400
# warm = ["google.com", "github.com"] # resolve at startup, refresh before TTL expiry
[proxy]
enabled = true
port = 80
tls_port = 443
tld = "numa"
# bind_addr = "127.0.0.1" # default; set to "0.0.0.0" for LAN access to .numa services
# ── Bring-your-own TLS cert ────────────────────────────────────────
# Skip per-device CA install. `tld` must be a domain you own. Renew
# externally; restart to pick up.
#
# cert_path = "/etc/letsencrypt/live/example.com/fullchain.pem"
# key_path = "/etc/letsencrypt/live/example.com/privkey.pem"
# ── PROXY protocol v2 ──────────────────────────────────────────────
# Preserve the real client IP behind an L4 front-end (dnsdist,
# HAProxy, AWS NLB). Non-empty `from` is required-mode: connections
# outside the allowlist, or missing the header, are dropped.
#
# [proxy.proxy_protocol]
# from = ["10.0.0.0/8", "127.0.0.1"] # trusted L4 front-ends
# header_timeout_ms = 5000 # kill stalled-header connections
# Pre-configured services (numa.numa is always added automatically)
# [[services]]
# name = "frontend"
# target_port = 5173
#
# [[services]]
# name = "api"
# target_port = 8000
# target_host = "192.168.1.50" # optional, defaults to localhost
# Example zone records:
# [[zones]]
# domain = "dimescu.ro"
# record_type = "A"
# value = "3.120.139.105"
# ttl = 30
# [[zones]]
# domain = "test.local"
# record_type = "A"
# value = "127.0.0.1"
# ttl = 60
# Reverse-DNS (PTR) for LAN hosts — makes tcpdump/access logs readable
# [[zones]]
# domain = "1.0.168.192.in-addr.arpa" # 192.168.0.1 reversed + .in-addr.arpa
# record_type = "PTR"
# value = "router.lan"
# ttl = 300
# Wildcard zones — one rule covers an entire subtree. Leftmost label only
# (RFC 4592). Exact entries always win; the wildcard does NOT match its parent
# (e.g. `*.pool.ntp.org` matches `time2.pool.ntp.org` but not `pool.ntp.org`).
# [[zones]]
# domain = "*.pool.ntp.org"
# record_type = "CNAME"
# value = "time.onsite"
# ttl = 60
# DNSSEC signature validation (requires mode = "recursive")
# [dnssec]
# enabled = false # opt-in: verify chain of trust from root KSK
# strict = false # true = SERVFAIL on bogus signatures
# DNS-over-TLS listener (RFC 7858) — encrypted DNS on port 853
# [dot]
# enabled = true # on by default; set false to disable
# port = 853 # standard DoT port
# bind_addr = "0.0.0.0" # IPv4 or IPv6; unspecified binds all interfaces
# cert_path = "/etc/numa/dot.crt" # PEM cert; omit to use self-signed (proxy CA if available)
# key_path = "/etc/numa/dot.key" # PEM private key; must be set together with cert_path
# ── PROXY v2 on DoT ────────────────────────────────────────────────
# Same semantics as [proxy.proxy_protocol] above.
#
# [dot.proxy_protocol]
# from = ["10.0.0.0/8"]
# header_timeout_ms = 5000
# LAN service discovery via mDNS (disabled by default — no network traffic unless enabled)
# [lan]
# enabled = true # discover other Numa instances via mDNS (_numa._tcp.local)
# broadcast_interval_secs = 30
# peer_timeout_secs = 90
# ── Mobile API ─────────────────────────────────────────────────────
# Read-only HTTP for the companion apps (discovery, /ca.pem,
# /mobileconfig, QR onboarding via `numa setup-phone`). Binds to the
# LAN by default. Don't enable on untrusted LANs (office Wi-Fi,
# cafés) — an attacker on the same network can shadow you via mDNS
# and serve their profile instead.
[mobile]
enabled = true # opt-in to the mobile API listener
# port = 8765 # default; matches Discovery.swift defaultAPIPort
# bind_addr = "0.0.0.0" # default; set to "127.0.0.1" for localhost-only