# Changelog All notable changes to nxdns are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Sections are written by hand. Nothing here is generated from commit messages: the point of the file is to say what changed for an operator, which a commit subject rarely does. ## [Unreleased] ### Fixed - **The DNS cache's memory is bounded in bytes, not only in entries.** Each cached answer is copied at whatever size the upstream sent, so 10000 entries could in principle hold 10000 large answers. The answers now share a budget of 256 bytes per `cache.size` entry, about 2.4 MiB at the default, and when a new answer does not fit, answers nobody has asked for lately make room for it. An answer larger than the whole budget is not cached. `/metrics` reports `nxdns_cache_response_bytes` against `nxdns_cache_max_bytes`, and counts `nxdns_cache_oversized_total` and `nxdns_cache_copy_failures_total`. - **The DNS cache no longer evicts an answer while it has free room.** A new answer replaced an older one whenever the eviction scan met it first, even with most of the cache empty. A copy of an answer that failed for lack of memory was also dropped without a trace; it is now counted, and a failed replacement keeps the answer already cached. - **A refused query history says what to do.** When nxdns refuses to open `querylog.db`, because a newer release wrote it or it cannot be converted, the message now gives the remedy: run the newer release again, put back the `querylog.db.pre-migrate-*` copy, or move the file and its `-wal` and `-shm` files aside to start an empty history. It used to point at a documentation page. - **A refused start no longer gives advice that does not apply.** After a query history refusal, `nxdns run` also printed "run `nxdns check`" and "load one with `nxdns import `", though the configuration was fine. The import hint now appears only when the database has no usable upstream, and neither hint follows a database refusal. ### Changed - **Blocklists take less memory, and a refresh peaks lower.** A list that names a domain both on its own and with its subdomains, as Adblock-style lists do for every entry, now stores that name once instead of twice. A reload reads one list's compiled files at a time instead of all of them at once, and the startup pass no longer rebuilds the blocklists when no list was due for a refresh. - **The query-history buffer defaults to 1024 queries** instead of 10000, under 2 MiB instead of about 17. It only holds queries that arrive while a write is in progress. - **A live query stream takes memory only while someone watches it.** Each of the 32 possible streams reserved its buffer at startup, about 3.6 MiB in all. A stream that cannot get its buffer is refused with its own message and counted in `nxdns_live_stream_allocation_failures_total`. - **Each database connection keeps a page cache sized for its job** instead of SQLite's 2 MiB default on all seven: 256 KiB for the configuration database and for retention, 1 MiB for the query-history writer and reader. - **The documentation is written for people running nxdns.** It starts from Get started, which downloads a release instead of building from source, and drops the API reference, the troubleshooting page and the performance pages. It is published at , and `INSTALL.md` in the tarball links there. ## [0.0.24] - 2026-10-21 ### Fixed - **The admin pages fit a phone.** At 390 px, Activity, Clients, Diagnostics and every configuration table scrolled sideways, and Diagnostics and Clients made the whole page 826 px and 660 px wide, so the phone zoomed out. A table now shows all its columns only where they fit without wrapping. In a narrower table, the first cell carries the other columns' facts on short lines ("Priority 20 · TLS name dns.quad9.net", "Created 19 Oct 2026, 16:15:44"), and long names, URLs, IPv6 addresses and patterns wrap instead of widening the page. In the narrow Sources and Upstreams tables, Edit and Delete stack, which gives the first cell the width. Protection > Sources needs a 1440 px wide table for all its columns, so a 1440 px window now shows its narrow form; in 0.0.23 it made the page 1557 px wide there. - **Overview is no longer taller than the window.** The charts' screen-reader tables extended the document below the app, so the page had a second scroll bar under the main one at desktop widths. - **The Diagnostics count line no longer spreads its words across the page.** - **The Diagnostics health cards no longer spread a short card's lines down its height.** ## [0.0.23] - 2026-10-20 ### Fixed - **A blackhole route to an upstream no longer stops failover.** On a route like that, `connect()` fails with an errno the runtime has no name for, and nxdns took it for a fault of its own: the query got SERVFAIL at once, the next upstream was never tried, and nothing was charged to the unreachable one. A connect failure of that kind now counts against that upstream as `ConnectFailed (cause Unexpected)`, and the query fails over. - **The Overview charts no longer draw the current bucket as a fall in traffic.** Every Overview window ends at the end of the bucket that holds the present moment, so its last bucket is still counting. Queries over time draws the curve into it dashed over a fainter fill, and Client activity draws its column faint inside a dashed outline. Both legends name "Still counting", and the tooltip and the chart's data table give that bucket's time as "