Zones get a DNSSEC setting: named signs them with BIND's default (or a custom) dnssec-policy and inline signing, with keys in a per-view key directory. Jarl shows the keys, the DS record and when it is safe to publish it, checks the parent's DS records (check-ds, which also tells named), and refuses steps that would break a signed domain: switching straight to unsigned, finishing a turn-off too early, deleting or moving a signed zone, TTLs above max-zone-ttl. Turning off goes through the insecure policy; wipe starts over once the parent has no DS. Backups store the DNSSEC keys and restore puts them back for named; the backup unit gets CAP_DAC_READ_SEARCH to read them. Jarl raises a zone's serial above named's whenever it writes an older one (after a restore). The serials check compares the signed serial. With a Porkbun API key in jarl.yaml, the registrar's name servers, glue records and DS records can be shown and changed, each change checked first (dry run, force to override). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
171 lines
9.3 KiB
Markdown
171 lines
9.3 KiB
Markdown
# jarld configuration (`/etc/jarl/jarl.yaml`)
|
|
|
|
jarld reads `/etc/jarl/jarl.yaml` (or the file given with `-c/--config`,
|
|
which every jarld subcommand accepts). Every setting is optional. The
|
|
defaults suit Debian/Ubuntu with BIND 9.20. Unknown keys are an error, so
|
|
typos don't go unnoticed.
|
|
|
|
```sh
|
|
jarld config --example # a commented example file with every setting
|
|
jarld config # the effective configuration (file + defaults)
|
|
```
|
|
|
|
The CLI has its own small configuration file, described in [cli.md](cli.md).
|
|
|
|
## Settings
|
|
|
|
### Web UI and API
|
|
|
|
| Key | Default | Meaning |
|
|
|-----|---------|---------|
|
|
| `listen` | `["127.0.0.1:8053"]` | Addresses to listen on (`host:port`, several allowed). Keep these on localhost and management networks. |
|
|
| `socket` | `/run/jarl/jarl.sock` | A local unix socket for the API. Requests on it from root or jarld's own user need no token and have administrator rights; anyone else must send a token ([permissions.md](permissions.md#the-local-socket)). The `jarl` CLI uses it when no server is configured. At most 107 bytes long; `""` turns it off. If it can't be created, jarld logs a warning and serves the network addresses only. |
|
|
| `tls.cert_file`, `tls.key_file` | (empty: plain HTTP) | PEM certificate chain and key. Both or neither. The files are rechecked every 10 minutes and on SIGHUP (`systemctl reload jarl`), so renewed certificates are used without a restart. |
|
|
| `trusted_proxies` | `[]` | Addresses or prefixes of reverse proxies whose `X-Forwarded-For` and `X-Forwarded-Proto` (or `Forwarded: proto=`) headers are believed. Needed for correct client IPs in the audit log and for rate limiting behind a proxy, and for knowing that a proxied request came over HTTPS (the session cookie's Secure flag, `acme.httpreq`). From other addresses these headers are ignored. |
|
|
| `session.lifetime` | `12h` | A web session ends this long after login... |
|
|
| `session.idle_timeout` | `2h` | ...or after this long without requests. |
|
|
| `session.cookie_secure` | `auto` | `auto` sets the cookie's Secure flag when the request came over HTTPS (directly or via a trusted proxy); `always` / `never` force it. |
|
|
|
|
Durations accept Go syntax (`90s`, `15m`, `12h`) and days (`30d`).
|
|
|
|
### Storage
|
|
|
|
| Key | Default | Meaning |
|
|
|-----|---------|---------|
|
|
| `database` | `/var/lib/jarl/jarl.db` | SQLite database: configuration, users, tokens, history, audit log. |
|
|
| `staging_dir` | `/var/lib/jarl/staging` | Scratch space where candidate configurations are rendered and checked with named-checkconf before they are installed. |
|
|
| `audit.retention_days` | `0` | Delete audit events older than this many days (0 keeps them forever). Changeset history is kept regardless. |
|
|
|
|
### Backups
|
|
|
|
`jarld backup` without a file name, which the `jarl-backup.timer` systemd
|
|
timer runs daily, writes `jarl-<UTC time>.db` into `backup.dir` (with the
|
|
DNSSEC keys of signed zones inside it) and then deletes old backups there. It reads these settings from this file each
|
|
time it runs; when it runs is the timer's (`systemctl edit
|
|
jarl-backup.timer`). See [operations.md](operations.md#backups), also for
|
|
restoring.
|
|
|
|
| Key | Default | Meaning |
|
|
|-----|---------|---------|
|
|
| `backup.dir` | `/var/backups/jarl` | Where backups go. The backup service's sandbox may only write here; to use another directory, allow it with `ReadWritePaths=` in `systemctl edit jarl-backup.service`. |
|
|
| `backup.retention` | `30d` | Delete backups older than this, by the time in their name. At least `1d`; `0` keeps every backup. |
|
|
| `backup.keep_at_least` | `7` | Always keep this many of the newest backups, however old, so a long gap in backups never deletes them all. At least 1. |
|
|
| `backup.stats` | `false` | Also back up the query statistics database (`stats-<UTC time>.db`). |
|
|
| `backup.warn_after` | `2d` | The dashboard and `jarl status` warn when the newest backup is older than this. Keep it above the timer's interval; `0` turns the warning off. |
|
|
|
|
Only files named `jarl-<time>.db` and `stats-<time>.db` are ever deleted.
|
|
|
|
### Logging
|
|
|
|
| Key | Default | Meaning |
|
|
|-----|---------|---------|
|
|
| `log.level` | `info` | `debug`, `info`, `warn` or `error`. |
|
|
| `log.format` | `text` | `text` or `json`. Under systemd both go to the journal (`journalctl -u jarl`). |
|
|
|
|
Audit events are logged as `msg=audit` lines as well as stored in the
|
|
database.
|
|
|
|
### Query statistics
|
|
|
|
The `stats:` section turns on query statistics (off by default). See
|
|
[stats.md](stats.md) for every setting and what it changes in named's
|
|
configuration. Changing it takes effect when jarld restarts.
|
|
|
|
### ACME (lego httpreq endpoint)
|
|
|
|
An endpoint for lego's `httpreq` DNS provider, so lego and Traefik can
|
|
publish DNS-01 challenges without the jarl CLI. See
|
|
[acme.md](acme.md#6-lego-and-traefik-over-http-httpreq-without-the-jarl-cli)
|
|
for how it works and how to set up HTTPS for it. Changes take effect when
|
|
jarld restarts.
|
|
|
|
| Key | Default | Meaning |
|
|
|-----|---------|---------|
|
|
| `acme.httpreq.enabled` | `false` | Answer `POST /api/v1/acme/httpreq/present` and `/cleanup`. Off, they answer `404 disabled`. |
|
|
| `acme.httpreq.require_https` | `true` | Refuse requests that didn't come over HTTPS: jarld's own `tls`, or a proxy in `trusted_proxies` that sends `X-Forwarded-Proto: https`. The rest of Jarl is unaffected by this setting. `false` accepts plain HTTP from anywhere (logged as a warning at startup). |
|
|
| `acme.httpreq.allow_loopback_http` | `false` | Also accept plain HTTP from `127.0.0.1` and `::1` (lego on the DNS server itself), unless that address is in `trusted_proxies`. |
|
|
|
|
### BIND
|
|
|
|
| Key | Default | Meaning |
|
|
|-----|---------|---------|
|
|
| `bind.main_config` | `/etc/bind/named.conf` | The file named loads. `jarld import` reads it, and `jarld adopt` replaces it with an include of Jarl's configuration. |
|
|
| `bind.config_dir` | `/etc/bind/jarl` | Where Jarl writes `named.conf` and `keys.conf`. Must be readable by named. |
|
|
| `bind.zone_dir` | `/var/lib/bind/jarl` | Primary zone files (`<view>/<zone>.zone`). named may write journals, signed copies of zones and, under `dnssec-keys/`, DNSSEC keys here. |
|
|
| `bind.cache_dir` | `/var/cache/bind/jarl` | Where named stores secondary, stub and mirror zones. |
|
|
| `bind.file_group` | `bind` | Group given to generated files and directories so named can read them. Empty leaves the group alone. |
|
|
| `bind.named_user` | `bind` | The user named runs as. `jarld restore` gives it the DNSSEC keys it puts back. |
|
|
| `bind.named_checkconf` | `/usr/bin/named-checkconf` | Used to check every candidate configuration (`-z` also loads the zones). |
|
|
| `bind.named_checkzone` | `/usr/bin/named-checkzone` | Used to check zone files. |
|
|
| `bind.rndc` | `/usr/sbin/rndc` | Used to reconfigure and reload named and to read zone serials. |
|
|
| `bind.rndc_args` | `[]` | Extra rndc arguments, e.g. `["-k", "/etc/bind/rndc.key", "-s", "127.0.0.1", "-p", "953"]`. Debian's rndc finds `/etc/bind/rndc.key` by itself. |
|
|
| `bind.reload_timeout` | `15s` | How long to wait for named to load changed zones (checked with `rndc zonestatus`) before the change is rolled back. |
|
|
| `bind.no_reload` | `false` | Write files but never run rndc. Use it when named runs on another host or for testing. Changes are then not verified against a running named. |
|
|
|
|
The three directories must exist and be writable by the `jarl` user. The
|
|
tmpfiles.d entry creates them, and the systemd unit only allows writes
|
|
there (`ReadWritePaths`). If you change them, update both
|
|
`/usr/lib/tmpfiles.d/jarl.conf` and the unit (`systemctl edit jarl`):
|
|
|
|
```ini
|
|
[Service]
|
|
ReadWritePaths=/srv/bind/jarl /srv/bind/zones
|
|
```
|
|
|
|
### Porkbun (registrar)
|
|
|
|
With an API key, Jarl can show and set a domain's name servers, glue
|
|
records and DNSSEC DS records at Porkbun, after checking that the change
|
|
won't break the domain ([dnssec.md](dnssec.md#porkbun)). Without a key
|
|
(the default) nothing about Porkbun shows up.
|
|
|
|
| Key | Default | Meaning |
|
|
|-----|---------|---------|
|
|
| `porkbun.api_key` | `""` | The API key (`pk1_...`). Set both or neither. |
|
|
| `porkbun.secret_api_key` | `""` | Its secret (`sk1_...`). |
|
|
| `porkbun.domains` | `[]` | Only these domains (default: every primary zone the key can reach). |
|
|
|
|
The key can move your domain anywhere, so it is only ever read from this
|
|
file: it isn't stored in the database or backups, and there is no API to
|
|
set it. Keep the file readable only by root and jarld (`chown root:jarl
|
|
jarl.yaml; chmod 640 jarl.yaml`, as the Debian package installs it); jarld
|
|
warns at start when everyone can read it. At porkbun.com, switch on "API
|
|
Access" for the domain, and limit the key to the domain if you can.
|
|
|
|
## Example: management network with TLS
|
|
|
|
```yaml
|
|
listen:
|
|
- "127.0.0.1:8053"
|
|
- "192.168.10.2:8053"
|
|
tls:
|
|
cert_file: /etc/jarl/tls/fullchain.pem
|
|
key_file: /etc/jarl/tls/privkey.pem
|
|
log:
|
|
level: info
|
|
audit:
|
|
retention_days: 730
|
|
```
|
|
|
|
## Example: behind nginx
|
|
|
|
```yaml
|
|
listen: ["127.0.0.1:8053"]
|
|
trusted_proxies: ["127.0.0.1"]
|
|
```
|
|
|
|
```nginx
|
|
location / {
|
|
proxy_pass http://127.0.0.1:8053;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_read_timeout 300s; # applying a large changeset can take a while
|
|
}
|
|
```
|
|
|
|
`X-Forwarded-Proto` tells jarld that the client used HTTPS. It sets the
|
|
session cookie's Secure flag, and the lego `httpreq` endpoint needs it
|
|
(Caddy and Traefik send it without being told). Check with
|
|
`curl https://YOUR-PROXY/api/v1/acme/httpreq`, whose `transport` field says
|
|
how jarld saw the request.
|