···1+# Configuration
2+3+## Location
4+5+The config file is loaded from one of two places:
6+7+1. The path set in the `ONIS_CONFIG` environment variable
8+2. `onis.toml` in the current working directory (default)
9+10+If the file does not exist, all options fall back to their defaults. Every field is optional. A default config is provided here, with the default values that are used.
11+12+## Options
13+14+### `[appview]`
15+16+| Key | Type | Default | Description |
17+|-----|------|---------|-------------|
18+| `bind` | string | `"0.0.0.0:3000"` | Address and port for the appview HTTP server |
19+| `tap_url` | string | `"ws://localhost:2480/channel"` | WebSocket URL for [TAP](https://github.com/bluesky-social/indigo/tree/main/cmd/tap) |
20+| `tap_acks` | bool | `true` | Whether to acknowledge TAP messages |
21+| `tap_reconnect_delay` | u64 | `5` | Seconds to wait before reconnecting after a TAP connection error |
22+| `index_path` | string | `"./data/index.db"` | Path to the shared zone index SQLite database |
23+| `db_dir` | string | `"./data/dbs"` | Directory for per-DID SQLite databases |
24+25+### `[appview.database]`
26+27+| Key | Type | Default | Description |
28+|-----|------|---------|-------------|
29+| `busy_timeout` | u64 | `5` | Seconds to wait when the database is locked |
30+| `user_max_connections` | u32 | `5` | Max connections for per-user database pools |
31+| `index_max_connections` | u32 | `10` | Max connections for the shared index database pool |
32+33+### `[dns]`
34+35+| Key | Type | Default | Description |
36+|-----|------|---------|-------------|
37+| `appview_url` | string | `"http://localhost:3000"` | URL of the appview API |
38+| `bind` | string | `"0.0.0.0"` | Address for the DNS server to listen on |
39+| `port` | u16 | `5353` | Port for the DNS server |
40+| `tcp_timeout` | u64 | `30` | Seconds before a TCP connection times out |
41+| `ttl_floor` | u32 | `60` | Minimum TTL enforced on all DNS responses |
42+| `slow_query_threshold_ms` | u64 | `50` | Log a warning for queries slower than this (milliseconds) |
43+| `ns` | list\[string\] | `["ns1.example.com.", "ns2.example.com."]` | NS records served for all zones (fully qualified, trailing dot) |
44+| `metrics_bind` | string | `"0.0.0.0:9100"` | Bind address for the metrics HTTP server |
45+46+### `[dns.soa]`
47+48+Default SOA record values for zones without a user-published SOA. These fields are defined in RFC 1035 Section 3.3.13 and are primarily relevant for nameserver maintenance operations between primary and secondary servers.
49+50+| Key | Type | Default | Description |
51+|-----|------|---------|-------------|
52+| `ttl` | u32 | `3600` | SOA record TTL in seconds |
53+| `refresh` | i32 | `3600` | SOA refresh interval in seconds |
54+| `retry` | i32 | `900` | SOA retry interval in seconds |
55+| `expire` | i32 | `604800` | SOA expire interval in seconds |
56+| `minimum` | u32 | `300` | SOA minimum (negative cache) TTL in seconds |
57+| `mname` | string | `"ns1.example.com."` | Primary nameserver (fully qualified) |
58+| `rname` | string | `"admin.example.com."` | Admin email in DNS format (fully qualified) |
59+60+**Field details:**
61+62+- **`refresh`** -- The interval at which secondary nameservers should poll the primary to check if the zone's serial number has incremented.
63+64+- **`retry`** -- If a secondary fails to reach the primary during a refresh attempt, it retries after this many seconds.
65+66+- **`expire`** -- If a secondary cannot reach the primary for this long, it stops serving the zone entirely and returns SERVFAIL. This is the upper bound on how long stale data can be served.
67+68+- **`minimum`** -- Originally defined in RFC 1035 as a lower bound on TTL for all RRs in the zone (resolvers would set TTL to the maximum of the record's own TTL and this value). RFC 2308 redefined this field to mean the **negative caching TTL** -- how long resolvers should cache NXDOMAIN and NODATA responses.
69+70+- **`mname`** -- The FQDN of the primary nameserver for the zone. Must include the trailing dot.
71+72+- **`rname`** -- The email address of the zone administrator, encoded in DNS format: the `@` is replaced with a `.`, so `admin@example.com` becomes `admin.example.com.`. Must include the trailing dot. This is informational and not used by resolvers programmatically, but it is exposed in SOA query responses.
73+74+### `[verify]`
75+76+| Key | Type | Default | Description |
77+|-----|------|---------|-------------|
78+| `appview_url` | string | `"http://localhost:3000"` | URL of the appview API |
79+| `bind` | string | `"0.0.0.0"` | Address for the verify API server |
80+| `port` | u16 | `3001` | Port for the verify API server |
81+| `check_interval` | u64 | `60` | Seconds between scheduled verification runs |
82+| `recheck_interval` | i64 | `3600` | Seconds a zone must be stale before reverification |
83+| `expected_ns` | list\[string\] | `["ns1.example.com", "ns2.example.com"]` | Expected NS records that indicate correct delegation (should match `dns.ns`) |
84+| `nameservers` | list\[string\] | `[]` | Custom resolver IP addresses (optional, uses system resolvers if empty) |
85+| `dns_port` | u16 | `53` | Port used when resolving against custom nameservers |
86+87+## Example config
88+89+A full `onis.toml` with all defaults:
90+91+```toml
92+[appview]
93+bind = "0.0.0.0:3000"
94+tap_url = "ws://localhost:2480/channel"
95+tap_acks = true
96+tap_reconnect_delay = 5
97+index_path = "./data/index.db"
98+db_dir = "./data/dbs"
99+100+[appview.database]
101+busy_timeout = 5
102+user_max_connections = 5
103+index_max_connections = 10
104+105+[dns]
106+appview_url = "http://localhost:3000"
107+bind = "0.0.0.0"
108+port = 5353
109+tcp_timeout = 30
110+ttl_floor = 60
111+slow_query_threshold_ms = 50
112+ns = ["ns1.example.com.", "ns2.example.com."]
113+metrics_bind = "0.0.0.0:9100"
114+115+[dns.soa]
116+ttl = 3600
117+refresh = 3600
118+retry = 900
119+expire = 604800
120+minimum = 300
121+mname = "ns1.example.com."
122+rname = "admin.example.com."
123+124+[verify]
125+appview_url = "http://localhost:3000"
126+bind = "0.0.0.0"
127+port = 3001
128+check_interval = 60
129+recheck_interval = 3600
130+expected_ns = ["ns1.example.com", "ns2.example.com"]
131+nameservers = []
132+dns_port = 53
133+```