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

8.6 KiB

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.

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.

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). 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: 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, 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 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 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):

[Service]
ReadWritePaths=/srv/bind/jarl /srv/bind/zones

Example: management network with TLS

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

listen: ["127.0.0.1:8053"]
trusted_proxies: ["127.0.0.1"]
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.