minsec.toml(5)
minsec daemon configuration and drop-in format
Synopsis
/etc/minsec/minsec.toml
/etc/minsec/conf.d/*.toml
Description
These TOML files configure the minsec(1) daemon and its per-filter policy. The main file is optional; an absent file produces the built-in defaults with no filters enabled.
After reading minsec.toml, minsec reads regular files ending in .toml from conf.d in lexical pathname order. Tables are merged recursively. A later scalar, array, or other non-table value replaces the earlier value. This makes a small drop-in sufficient to override one setting.
Unknown keys at every documented table level are errors. Run minsec check --all after editing and restart the daemon to apply changes. There is no live configuration reload.
Duration values
A duration may be a TOML string containing bare seconds or concatenated integer/unit pairs, or a TOML integer number of seconds. Supported units are s, m, h, d, and w. Examples include "30", "10m", "1h30m", and "2d".
Defaults table
The [defaults] table sets global policy.
- bantime = duration
Initial automatic and default manual ban lifetime. Default: 1h.
- findtime = duration
Window in which failures count toward maxretry. It must be greater than zero. Default: 10m.
- maxretry = integer
Failures from the same network in the same filter and findtime window that trigger a ban. The value must be from 1 through 32. Default: 5.
- escalate_enabled = boolean
Enable increasing lifetimes for repeat automatic bans. Default: true.
- escalate = { factor = integer, max = duration, memory = duration }
Repeat-offender policy. Each previous automatic ban still in history multiplies the base ban lifetime by factor, capped at max. History older than memory is forgotten; that retention applies even when escalate_enabled is false. Members omitted from this inline table receive defaults. Ban history is reconstructed at startup from the event log, so escalation survives restarts. Defaults are factor 2, maximum 1w, and memory 30d.
- allow = [network, ...]
IP addresses or CIDR networks that must never be banned. TOML values are strings, for example ["203.0.113.0/24"]. Loopback, unspecified, and addresses currently assigned to the local host are also protected. A candidate IPv6 aggregate is rejected if it overlaps an allowed network. Default: empty.
- backend = "nft" | "null" | "exec"
Firewall backend. nft maintains the project's nftables table, null makes no firewall changes, and exec invokes an operator-provided command. Default: nft.
- exec_command = string
Trusted shell command used by the exec backend. It is required when backend = "exec" and is invoked through /bin/sh -c with setup, ban network ttl-seconds, or unban network arguments. The arguments are appended as positional parameters, so the value may be a program path or a shell fragment reading $1, $2, and $3; see minsec(1). There is no default.
- ipv6_prefix = integer
Prefix length used to aggregate IPv6 addresses for tracking and banning. It must be from 1 through 128. For example, the default 64 tracks and bans one /64 rather than each /128. IPv4 addresses are tracked as /32.
- max_tracked = integer
Approximate upper bound for in-memory failure trackers and escalation-history entries. Idle or oldest tracking entries are discarded as needed; active firewall bans are not discarded merely to meet this bound. Default: 50000.
- journal = boolean
Prefer the systemd journal for filters that define journal selectors when journal support is available. If selected for a filter, journal input is used instead of that filter's file list to avoid double counting. If disabled or unavailable, the file list is used. Default: true.
Paths table
The [paths] table selects runtime and persistent locations.
- socket = path
Unix-domain control socket. Default: /run/minsec/minsec.sock.
- state_dir = path
Persistent state directory. The event log is stored as events.jsonl below it, with one rotated generation events.jsonl.1 created when the current file passes 8 MiB. Default: /var/lib/minsec.
Filter tables
Each [filters.name] table enables a built-in or custom filter and may override its policy or input definition. The table name is the filter lookup name.
- enabled = boolean
Load the filter into the running engine. Default: false.
- bantime = duration
Override defaults.bantime for this filter.
- findtime = duration
Override defaults.findtime for this filter.
- maxretry = integer
Override defaults.maxretry for this filter. The value must be from 1 through 32.
- files = [path-pattern, ...]
Replace the filter definition's complete file list. Shell-style glob patterns are supported.
- journal = { units = [...], identifiers = [...], comm = [...] }
Replace the filter definition's complete journal selector. All member arrays default to empty; selector entries are alternatives, not a conjunction.
- ports = [integer, ...]
Replace the service-port metadata from the filter definition. The value appears in effective inspection policy. The current nft backend bans source networks on all ports; this setting does not restrict its drop rules.
Source selection
When journal input is enabled, available, and the filter has a nonempty selector, only journal input is configured for that filter. Otherwise its files are followed. Journal units match _SYSTEMD_UNIT; identifiers match SYSLOG_IDENTIFIER; and comm matches _COMM. Unit matches are accepted directly because journald derives them from cgroup provenance. Identifier and command matches are accepted only for records from a system UID (0 through 999), because those fields can otherwise be forged by local users.
Drop-ins
A typical drop-in enables one filter and changes one policy value:
[filters.sshd]
enabled = true
maxretry = 3
minsec enable sshd and minsec disable sshd maintain conf.d/sshd.toml in this form. Because drop-ins are lexically ordered, use numeric prefixes when several administrator-managed files may override the same key.
Example
[defaults]
bantime = "1h"
findtime = "10m"
maxretry = 5
backend = "nft"
escalate = { factor = 2, max = "1w", memory = "30d" }
allow = ["203.0.113.0/24"]
ipv6_prefix = 64
journal = true
[paths]
socket = "/run/minsec/minsec.sock"
state_dir = "/var/lib/minsec"
[filters.sshd]
enabled = true
maxretry = 3
[filters.wordpress]
enabled = true
files = ["/var/log/httpd/*_access_log"]
Files
- /etc/minsec/minsec.toml
Main configuration.
- /etc/minsec/conf.d/*.toml
Lexically ordered drop-ins using this same format.
- /etc/minsec/filters/*.toml
Custom filter definitions, documented in minsec-filter.toml(5).
See also
minsec(1), minsec-filter.toml(5), minsec-sync.toml(5), nft(8)