On this page
Configuration reference
Native TOML settings, durations, sources, storage, enforcement and reload boundaries for fail2zig 0.4.0.
The default file is /etc/fail2zig/config.toml. Use the
worked example as a starting point and validate
before starting or reloading. This reference describes 0.4.0 native operation.
File format and permissions
The parser accepts a strict TOML subset: [global], [defaults] and
[jails.<name>]. Unknown keys/sections, duplicate keys, mixed array types and
invalid values are rejected. Use section headers, not dotted keys on the left.
Comments begin with #; strings must be quoted. Jail names use ASCII letters,
digits, hyphens or underscores.
Keep configuration administrator-owned and readable by the service. World-writable or non-root-group-writable configuration is refused. A non-root owner warns. The installer preserves existing operator configuration; check its permissions when changing the service group.
Duration strings
bantime, findtime, bantime_increment_max_bantime and
bantime_increment_jitter accept integer seconds or quoted durations in both
defaults and jail overrides.
[defaults]
bantime = "1h30m"
findtime = "10m"
bantime_increment_max_bantime = "1w"
bantime_increment_jitter = "30s"| Unit | Seconds |
|---|---|
s | 1 |
m, mm, min | 60 |
h | 3,600 |
d | 86,400 |
w | 604,800 |
mo | 2,629,800 |
y | 31,557,600 |
Months and years are fixed intervals, not calendar arithmetic. Each term is a
nonnegative integer followed by a unit; terms can touch or have intervening
whitespace ("1h 30m"). Fractions, signed terms, arithmetic, unknown units and
overflow are rejected. Bare 24h is not valid TOML.
Finite bantime, findtime and the escalation cap must be positive. Jitter permits
zero and must not exceed the cap. Only bantime accepts "permanent". CLI
--duration, --timeout and migration window arguments remain numeric.
[global]
Logging and administration
| Key | Type / default | Meaning |
|---|---|---|
log_level | String, "info" | debug, info, warn or err. Live reload supported. |
log_target | String, "stderr" | Stderr or an absolute log-file path. Changing the target requires restart; SIGUSR1 reopens it after rotation. |
socket_path | String, "/run/fail2zig/fail2zig.sock" | Local administration and monitoring socket. |
pid_file | String, "/run/fail2zig/fail2zig.pid" | Deprecated compatibility key; warns when explicitly set and is not written. Use systemd MainPID. |
The socket is mode 0660. The configured service/monitor group has read-only
access. Mutations require root or the daemon UID, verified with peer credentials.
Use fail2zig --socket <path> status when overriding the default socket.
State and resource limits
| Key | Type / default | Meaning |
|---|---|---|
state_file | Absolute path, "/var/lib/fail2zig/state.bin" | Native SQLite store for receipts, checkpoints, policy, retries, owners, effect intent and confirmed history. |
memory_ceiling_mb | Integer, 64, minimum 16 | Configured memory budget; do not interpret it as a whole-process RSS cap. |
native_memory_ceiling_mb | Positive integer, 256 | Native reservation/admission budget in MiB. Plans that exceed the admitted bounds are refused. |
native_fd_ceiling | Positive integer, 2048 | Native descriptor admission budget. |
history_retention | Nonnegative integer seconds, 86400 | Age policy for confirmed-history cleanup; required recovery anchors stay pinned. |
history_max_matches | Integer 0–1024, 10 | Confirmed-history match-retention policy. |
The database and its parent must belong to the daemon UID. The historical
.bin extension does not make it the legacy binary format. Native startup
refuses corrupt, incompatible or inaccessible required state instead of starting
empty. Storage failure pauses affected ingestion and reports degraded health
while retaining protection. Preserve the database and WAL/SHM coherently; do not
delete them to clear an error. See upgrades
and the memory model.
HTTP and WebSocket
| Key | Type / default | Meaning |
|---|---|---|
metrics_enabled | Boolean, true | false disables both HTTP and WebSocket; IPC and protection remain available. |
metrics_bind | IP string, "127.0.0.1" | Listen address. Loopback is not authentication. |
metrics_port | Integer 1–65535, 9100 | Port remains validated even when disabled. Zero does not disable HTTP. |
websocket_max_clients | Integer 1–1024, 16 | Maximum simultaneous WebSocket clients. |
Endpoints are /metrics, /api/status, /api/bans, /api/health and /events.
Health reports readiness with HTTP 200/503. HTTP shares the privileged daemon
process. Keep external access controlled or disable it if unused.
Firewall
firewall is a global string, default "auto".
| Value | Selection behavior |
|---|---|
"auto" | Probe nftables, then ipset/iptables for unsupported or transient nftables failure. Permission denial stops detection. |
"nftables" | Probe only nftables; direct netlink. |
"ipset" | Probe only ipset; needs both ipset and iptables tools. |
"iptables" | Probe only iptables. |
An explicit backend never silently switches to another. Scaffold failure also
does not trigger fallback. Jail banaction selects enforcement policy, not a
backend. If every enabled jail is log-only, enforcement backend detection is skipped.
on_no_backend is "fail-closed" by default: unusable required enforcement causes
startup refusal. "log-only" explicitly permits degraded observe-only operation;
status reports the cause. It does not install protection.
firewall_namespace is an ownership anchor, not a request to enter another
namespace. Effects remain in the daemon’s current network namespace. Custom
selectors and unit overrides that move the daemon between namespaces are
unsupported in 0.4.0; leave this setting at its built-in default.
DNS and timezone data
dns_server is an optional resolver IP; dns_port defaults to 53 and accepts
1–65535. Native hostname rules use bounded resolution and retain retry state;
a hostname is not an arbitrary command. timezone_root defaults to
"/usr/share/zoneinfo" for named timezone data. Leave these defaults unless the
chosen input contract requires an explicit deployment setting.
[defaults]
| Key | Type / default | Meaning |
|---|---|---|
bantime | Seconds/duration, 600, or "permanent" | Initial ban duration. |
findtime | Positive seconds/duration, 600 | Window for repeated failures. |
maxretry | Integer 1–128, 5 | Failures required within findtime. |
source | String, "auto" | auto, file, journald or internal. |
banaction | String, "nftables" | nftables, iptables, ipset all mean enforce through the selected global backend; log-only means observe. |
ignoreip | String array, [] | Exact IPs/CIDRs excluded from ban policy. The shipped example includes loopback ignores. |
enforce = true/false is also accepted as a policy spelling. Do not combine it
with banaction in the same section. Prefer banaction for consistency with the
shipped configuration. No value here enables arbitrary shell actions.
Escalation
| Key | Default | Meaning |
|---|---|---|
bantime_increment_enabled | false | Enable escalating durations. |
bantime_increment_multiplier | 1.0 | Positive base multiplier. |
bantime_increment_factor | 1.0 | Nonnegative growth factor; integer or decimal. |
bantime_increment_formula | "linear" | linear or exponential, not an arbitrary expression. |
bantime_increment_scope | "per-jail" | per-jail or overall recurrence scope. |
bantime_increment_max_bantime | 604800 | Positive seconds/duration cap. |
bantime_increment_jitter | 0 | Seconds/duration jitter bound, at most the cap. |
Linear uses bantime × multiplier × (1 + factor × n); exponential uses
bantime × multiplier × factor^n, where n is the prior ban count used by the
policy. For doubling with no jitter, set multiplier 1, factor 2 and formula
"exponential". A multiplier of 2 alone does not select doubling growth.
0.4.0 inherits escalation settings field by field. A jail overrides only the
keys it explicitly sets; omitted keys retain [defaults] values. This differs
from the old grouped-inheritance documentation.
[jails.<name>]
A jail declares a source, matcher and policy. Enabled jails must have admitted protection; unknown built-in filters without native rule files fail validation.
| Key | Default / contract |
|---|---|
enabled | true; disabled jails are not started. |
filter | Built-in service name, or the service name for a custom rule-file jail. Built-ins accept hyphen/underscore forms. |
logpath | Array of absolute file paths, default empty. Use file-source paths that the service can read. |
source | Inherits defaults. Prefer explicit source selection for reviewed configurations. |
maxretry, findtime, bantime, banaction | Override the corresponding default. |
ignoreip | Replaces, rather than appends to, the defaults list. Repeat loopback entries when overriding. |
bantime_increment_* | Field-by-field overrides as described above. |
Source and time contracts
| Key | Contract |
|---|---|
timestamp | File inputs require an explicit format: iso8601, syslog, epoch_seconds, common_log or undated. Choose for the actual log format. |
timezone_offset_minutes | Fixed offset from UTC, -1439–1439, for the selected timestamp contract. |
timezone | Named timezone; cannot be combined with the fixed offset. |
timezone_ambiguity | reject, earlier or later; requires a named timezone. |
journal_executables | Root-owned executable paths admitting journal origins. For Debian 13 SSH, include both paths below. |
rule_files | Up to eight distinct absolute paths to bounded native JSON rules. |
ignore_file | Optional ignore-policy file for custom rule jails; its contents can be reloaded. |
[jails.sshd]
filter = "sshd"
source = "journald"
journal_executables = ["/usr/sbin/sshd", "/usr/lib/openssh/sshd-session"]auto resolves the configured source at startup. file reads declared paths;
journald requires journalctl and admitted origins; internal is the confirmed-ban
feed for recidive. Internal recidive does not use log paths or custom rule files.
A source is healthy only after its runtime checks pass; configuration validation
alone is not that check. See log watching.
Deprecated and migration-managed settings
backend is a deprecated source alias accepted in defaults/jails: systemd
maps to journald; auto, polling, pyinotify and gamin map to auto.
Using both source and backend in one section is an error. It never chooses
the firewall backend.
native_ingestion defaults to true; disabling native operation is not a supported
0.4.0 deployment route. compatibility_manifest and compatibility_pending are
migration-managed admission metadata. Do not clear blockers by hand to force an
unsupported imported jail into service.
Validation and reload
sudo fail2zig --validate-config --config /etc/fail2zig/config.tomlDiagnostics identify file, line, column, section and key when available. Unreadable
files and permission failures can be positionless. Validation summarizes configured
sources; an auto source is resolved when the daemon starts. Inspect the actual
source and readiness through fail2zig jails and fail2zig status.
Some settings apply through fail2zig reload; others return restart_required.
See the reload table. Neither successful
syntax validation nor a reload request establishes installed firewall protection.
The tagged parser and shipped example define the release’s accepted configuration.