Files
jarl/docs/configuration.md
T
abrown38andClaude Opus 5.5 8f9cdd0a17 Add two-factor login (TOTP) with recovery codes
Users can set up an authenticator app from their account page; login
then asks for a code after the password, with one-time recovery codes
as a fallback. Sensitive actions (tokens, user changes, 2FA resets)
need a code from the last 5 minutes. totp.require (none/admins/all)
forces setup, and admins can reset a user's 2FA from the UI, the jarl
CLI or jarld on the server. The dashboard and jarl status flag users
missing 2FA and a shared "admin" account still in use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:12:24 +00:00

152 lines
8.6 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. |
| `totp.require` | `none` | Who must use [two-factor login](permissions.md#two-factor-login): `none` (each user decides), `admins`, or `all` (every user with a password). Someone who must and hasn't set it up can only set it up after logging in. API tokens and the local socket are not affected. |
| `totp.issuer` | `""` | The name authenticator apps show for the account. Empty means `Jarl <short hostname>`, so several servers are told apart. At most 64 characters, no `:`. Changing it doesn't affect apps already set up. |
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` 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 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_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
```
## 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.