- jarl zone list showed only primary zones. zone create binds its --type flag (default "primary") to the same variable as list's --type, so the default leaked into the list filter and hid hint, secondary and forward zones. list now has its own variable. TestListQueries runs list commands against a fake server and checks the filters they send. - named-checkconf/named-checkzone messages are classified by the tool's exit code: on success, everything printed is a warning. Warnings such as 'both "recursion no;" and "allow-recursion" active' were shown as errors. The CLI, jarld check and the web UI now label them as warnings and skip the routine "loaded serial" lines. - The zone_outside_view error points at --adopt-zones. - docs/views.md: step-by-step split DNS for a server that has no views yet, tested on a copy of a stock Ubuntu 26.04 setup. Linked from the README, concepts and validation docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
128 lines
5.9 KiB
Markdown
128 lines
5.9 KiB
Markdown
# 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.
|
|
* **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](docs/install.md) has the
|
|
details):
|
|
|
|
```sh
|
|
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](docs/concepts.md) | How Jarl works: source of truth, changesets, the apply pipeline, authentication. Read this first |
|
|
| [docs/install.md](docs/install.md) | Installing, importing and adopting an existing server, TLS, upgrading |
|
|
| [docs/configuration.md](docs/configuration.md) | `/etc/jarl/jarl.yaml` reference |
|
|
| [docs/cli.md](docs/cli.md) | The `jarl` command line client |
|
|
| [docs/api.md](docs/api.md) | REST API reference |
|
|
| [docs/permissions.md](docs/permissions.md) | Users, tokens, grants and roles |
|
|
| [docs/views.md](docs/views.md) | Split DNS: adding views to a server that has none |
|
|
| [docs/acme.md](docs/acme.md) | Let's Encrypt DNS-01 with certbot and acme.sh |
|
|
| [docs/validation.md](docs/validation.md) | Every check Jarl makes |
|
|
| [docs/operations.md](docs/operations.md) | Backups, drift, failures, recovery, monitoring |
|
|
| [docs/development.md](docs/development.md) | Code layout, tests against real BIND, conventions |
|
|
| [CHANGELOG.md](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.
|
|
* **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](docs/concepts.md#what-jarl-deliberately-doesnt-do-yet)).
|