abrown38andClaude Opus 5.5 3b7bee67f8 Add optional query statistics
Off by default (stats in jarl.yaml). When enabled, Jarl adds a loopback
statistics channel and a response log to named's configuration (merged
into existing logging/statistics-channels statements) and switches
response logging with rndc responselog, because the responselog option
only counts when named starts. jarld polls named's counters every minute
and tails the response log (resuming after restarts and across
rotation). It stores aggregates, never individual queries, in a separate
SQLite database: per-minute, hourly and daily counters (queries, result
codes, record types, views, zones, cache hits, upstream latency, DNSSEC)
and hourly/daily top lists (names, clients, NXDOMAIN and SERVFAIL names,
refused clients), each with its own retention. Clients can be anonymized
or excluded.

- Web UI: Statistics page with KPI tiles, queries and failed answers over
  time, a weekday x hour heatmap, top lists and breakdowns; SVG charts
  with hover/keyboard readouts, a table view and light/dark palettes
  validated for colour-vision deficiency.
- CLI: jarl stats status|summary|top|timeline|heatmap|breakdown.
- API: /api/v1/stats/*, behind a new "stats" permission resource.
- jarld brings named's configuration up to date with jarl.yaml at
  startup (engine.SyncConfig), never overwriting hand-edited files.
- resync now refuses to overwrite drifted files without force, as
  documented.
- tmpfiles.d creates /var/log/named (allowed by named's AppArmor profile
  on Debian 13 and Ubuntu).
- The e2e harness runs named with -f like the Debian unit.
- docs/stats.md, plus API, CLI, configuration, permissions and README
  updates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:21:34 +00:00
2026-10-07 20:21:34 +00:00
2026-10-07 20:21:34 +00:00
2026-10-07 20:21:34 +00:00
2026-10-07 20:21:34 +00:00
2026-10-07 20:21:34 +00:00
2026-10-07 20:21:34 +00:00
2026-10-07 20:21:34 +00:00

Jarl

A Jarl rules a Hold; this one rules your zones.

Jarl manages a BIND 9 (named) server: zones, records of every type, views, ACLs, TSIG keys and any named.conf option. It has a web UI, a REST API and a command line client. All three go through the same validated, audited, all-or-nothing change pipeline, and nothing reaches named before BIND's own checkers have accepted it.

$ jarl record add adbraun.lol nas A 192.168.1.20 --ptr
add nas.adbraun.lol. IN A 192.168.1.20
add 20.1.168.192.in-addr.arpa. IN PTR nas.adbraun.lol.
zone 1.168.192.in-addr.arpa serial 2026100700 -> 2026100701
zone adbraun.lol serial 2026100701 -> 2026100702
applied (changeset 12)

$ jarl record add adbraun.lol www A 192.168.1.99
error: www.adbraun.lol has a CNAME, so it can't have any other records (found A); a CNAME must be the only record at its name (RFC 1034) [zone adbraun.lol]

Features

  • Everything in one place: primary, secondary, forward, stub, mirror, hint, redirect and in-view zones, reverse zones from a CIDR, split DNS with views, ACLs, TSIG keys, and every BIND 9.20 option at server, view, zone and top level, with the ARM's description and grammar built in.
  • Safe changes. Every change is validated as a whole (CNAME rules, glue, delegations, RRset TTLs, references, option syntax, open-resolver and open-transfer lints), checked with named-checkconf -z, installed atomically, reloaded, and verified with rndc zonestatus. If named doesn't load it, the previous files are put back.
  • Changesets: apply edits one at a time, or bundle them, review the diff, and apply them together. Every applied changeset can be reverted. Serials are bumped automatically.
  • Users and API tokens with granular permissions, e.g. a token that may only write _acme-challenge TXT records in one zone. Passwords use argon2id, sessions have CSRF protection, logins are rate limited.
  • Audit log of every login, change and token, with user, token, IP and outcome.
  • Query statistics (optional, off by default): queries over time, busiest hours of the week, top names and clients, NXDOMAIN and refused queries, record types, cache hit rate. Shown in the web UI and the CLI, and exportable as JSON. Stored as aggregates in a separate database with retention you set.
  • Let's Encrypt DNS-01 built in: jarl acme plus certbot and acme.sh hooks, including CNAME delegation to a dedicated ACME zone.
  • Adopts an existing server: imports named.conf and zone files (comments included), then switches named over with an automatic fallback.
  • One static Go binary for the daemon (web UI embedded, SQLite built in) and one for the CLI, run by a sandboxed systemd service as an unprivileged user.

Quick start

On a Debian/Ubuntu BIND 9.20 server (install.md has the details):

make && sudo make install
sudo systemd-sysusers jarl.conf && sudo systemd-tmpfiles --create jarl.conf
sudo chgrp jarl /etc/jarl/jarl.yaml
sudo -u jarl jarld init --token            # first admin + a CLI token
sudo -u jarl jarld import                  # read the current named.conf and zones
sudo jarld adopt                           # switch named over (keeps a backup, rolls back on failure)
sudo systemctl enable --now jarl

jarl config set server http://127.0.0.1:8053
jarl config set token                      # paste the token from 'jarld init'
jarl status

Then open the web UI at http://127.0.0.1:8053/, or set listen and tls in /etc/jarl/jarl.yaml to reach it from your management network.

Documentation

docs/concepts.md How Jarl works: source of truth, changesets, the apply pipeline, authentication. Read this first
docs/install.md Installing, importing and adopting an existing server, TLS, upgrading
docs/configuration.md /etc/jarl/jarl.yaml reference
docs/cli.md The jarl command line client
docs/api.md REST API reference
docs/permissions.md Users, tokens, grants and roles
docs/views.md Split DNS: adding views to a server that has none
docs/acme.md Let's Encrypt DNS-01 with certbot and acme.sh
docs/stats.md Query statistics: enabling, what is collected, retention
docs/validation.md Every check Jarl makes
docs/operations.md Backups, drift, failures, recovery, monitoring
docs/development.md Code layout, tests against real BIND, conventions
CHANGELOG.md Changes per release

The web UI

The UI is built for getting things done rather than for looks. It has these pages:

  • Dashboard: named status, adoption, drift, recent changes, open problems.
  • Statistics (when enabled): queries over time, failed answers, a weekday x hour heatmap, top names and clients, and breakdowns. Every chart has a table view.
  • Zones: list, create (fields adapt to the zone type), per-zone records with inline editing and type-specific hints, settings (SOA, TTL, serial policy, view), options, the generated zone file, and pasting a zone file to merge or replace records.
  • Views, ACLs, TSIG keys, Server options: the options editor knows every BIND 9.20 statement for the scope and shows its description, grammar and a value field that fits it.
  • Changes: pending edits with the diff, named-checkconf output and problems, applied as one changeset. History lists applied changesets with their diffs and a revert button.
  • Audit, Users, Account (password, API tokens) and Search.

By default, edits are collected as pending changes. Pending rows are shown inline (green = new, yellow = changed, struck out = deleted) until you review and apply them. Switch on "Apply edits immediately" to skip the review step.

Requirements

  • BIND 9.20, with named-checkconf, named-checkzone and rndc. The option catalog follows 9.20. 9.18 will probably work, because named-checkconf still checks every change, but it is untested.
  • Linux with systemd for the packaged service. Defaults match Debian/Ubuntu, and other layouts are configurable.
  • Go 1.27+ to build.

Status

Version 0.1.0, the first release. It is feature-complete for one server's configuration. DNSSEC signing and managing several servers are not handled yet (concepts.md).

S
Description
No description provided
Readme MIT
11 MiB
0 Stars 1 Watchers 0 Forks
Jarl v0.6.2
Latest
2026-10-21 21:21:23 +00:00
Languages
Go 80.6%
JavaScript 14.2%
Shell 3.3%
CSS 1.3%
Makefile 0.3%
Other 0.3%