-
Notifications
You must be signed in to change notification settings - Fork 0
FHS Compliance
Last verified against code: v1.218.7 (2026-07-08). All tables on this page are cross-checked against
build/fhs-spec.yaml,install/systemd/tmpfiles.d/nftban.conf,install/systemd/sysusers.d/nftban.conf,install/packaging/deb/nftban-dir-attrs.list,install/packaging/rpm/nftban-files.inc, andpackaging/build_nftban.shat that HEAD. If you make a packaging change, please update this page in the same review.
NFTBan follows the Linux Filesystem Hierarchy Standard (FHS 3.0) for all file placement, ownership, and permissions.
- Purpose
- Source of Truth
- System Users and Groups
- Identity authority model: sysusers.d format vs identity creation mechanism
- Directory Layout
- Systemd Integration
- Permission Model
- Polkit Authorization
- Configuration Variables
- Validation Commands
- Common Errors
- References
Ensure all NFTBan files are placed according to Linux FHS 3.0 conventions for security, maintainability, and distribution compatibility. All paths, permissions, and ownership are defined in a single canonical specification and enforced at install time, runtime, and via periodic health checks.
All filesystem paths are defined in build/fhs-spec.yaml. Packaging artifacts (tmpfiles.d, sysusers.d, RPM %files, DEB postinst) are generated from this file. Do not manually edit generated files.
The runtime implementation is in cli/lib/nftban/core/nftban_fhs_spec.sh, which provides programmatic access to paths, permissions, and validation functions.
The intended identity set is declared in /usr/lib/sysusers.d/nftban.conf (generated from fhs-spec.yaml).
| Type | Name | Purpose |
|---|---|---|
| Group | nftban |
Admin/Operator group (full CLI access + Polkit) |
| Group | nftban-auditor |
Auditor group (read-only report and log access) |
| Group |
nftban-panel (retired v1.137)
|
Historical panel-integration group — not created by current packages (only nftban + nftban-auditor are) |
| User | nftban |
Service account (home: /var/lib/nftban, shell: /usr/sbin/nologin) |
The nftban user is also a member of the nftban-auditor group.
The sysusers.d file is the declarative identity recipe — it states what identities the package expects to exist. The execution mechanism that actually creates these identities at install time is the package scriptlet (DEB postinst / RPM %pre), not systemd-sysusers. See Identity authority model below.
NFTBan adopts the sysusers.d declarative format as the source of identity intent, but does not yet adopt systemd-sysusers as the runtime execution mechanism. These are two separate decisions; the project has made the first one and deliberately deferred the second.
A package can ship a sysusers.d file as a recipe for system identities without that recipe being executed by systemd-sysusers. The recipe records the contract — names, group memberships, descriptions — and the mechanism that materialises that contract is a separate concern. Many distributions allow either:
-
Declarative +
systemd-sysusersexecution — the file is consumed bysystemd-sysusersat package-install time. -
Declarative + scriptlet execution — the file is shipped as the recipe of record, but
getent/groupadd/useraddin DEB postinst / RPM%preactually create the identities.
NFTBan currently uses the second model. The sysusers.d file is the recipe; the lifecycle scriptlets are the mechanism.
Production package install (both DEB and RPM) creates identities through getent / groupadd / useradd in lifecycle scriptlets — see the postinst heredoc constructed in packaging/build_nftban.sh. systemd-sysusers is not invoked during install.
# Conceptual shape of the postinst (DEB) / %pre (RPM) — actual production mechanism:
getent group nftban >/dev/null || groupadd -r nftban
getent group nftban-auditor >/dev/null || groupadd -r nftban-auditor
# nftban-panel group retired v1.137 — current packages create only nftban + nftban-auditor
getent passwd nftban >/dev/null || useradd -r -g nftban \
-d /var/lib/nftban -s /usr/sbin/nologin -c "NFTBan system user" nftbanThe basename nftban.conf appears in three different locations with three different authorities. The directory determines the meaning; the basename alone is ambiguous.
| Path | Role | Operator-editable? |
|---|---|---|
/etc/nftban/nftban.conf |
NFTBan application/operator config (runtime behaviour, feeds, thresholds) | yes |
install/systemd/sysusers.d/nftban.conf → /usr/lib/sysusers.d/nftban.conf
|
systemd identity recipe (declares groups + user) | no — generated |
install/systemd/tmpfiles.d/nftban.conf → /usr/lib/tmpfiles.d/nftban.conf
|
systemd directory/runtime path recipe (declares mode + owner of /var/lib/nftban/*, /run/nftban, etc.) |
no — generated |
When referring to any of these in code review, audit notes, or operator docs, always include the full path or the qualifier (sysusers.d/nftban.conf, tmpfiles.d/nftban.conf). The bare basename without directory context is not enough.
This format-first, mechanism-second adoption is consistent with packaging direction in major distributions, without overclaiming alignment:
-
Fedora has discussed adopting the
sysusers.dformat as the canonical identity declaration while keeping macros/scriptlets that calluseradd/groupaddas the execution mechanism — the format declaration migrates first, the execution path migrates later. -
OpenSUSE uses
user(<name>)/group(<name>)virtualProvides:to express identity dependencies in package metadata, with similar separation between declaration and creation mechanism. -
Arch ships
sysusers.dfiles and runssystemd-sysusersfrom install hooks, illustrating the fully-migrated end-state. -
Debian has historically created identities via
adduser/addgroupin maintainer scripts (postinst). Debhelper now providesdh_installsysusers, which lets a Debian package ship asysusers.dfile as the recipe and have it processed at install time — but maintainer-scriptadduser/addgroupremain the canonical mechanism in most existing packages. The format-vs-mechanism separation is the same idea expressed in Debian's own packaging vocabulary. -
Ubuntu inherits the Debian model directly. The same
sysusers.d-as-recipe / scriptlet-as-mechanism split applies on Ubuntu releases that ship NFTBan (22.04, 24.04). NFTBan's CI Runtime Truth matrix exercises Ubuntu 24.04 explicitly to confirm the recipe + scriptlet combination produces the documented on-disk state.
NFTBan is at the same starting point as modern Linux distros adopting this model: declarative recipe shipped, scriptlet execution preserved. Migration to systemd-sysusers execution is a future step, not a current one.
-
Do not edit
/usr/lib/sysusers.d/nftban.conforinstall/systemd/sysusers.d/nftban.confmanually. Both are generated frombuild/fhs-spec.yaml; manual edits are overwritten on the next regeneration. -
Do not confuse the sysusers recipe with the application config.
/etc/nftban/nftban.confis for operators; the systemd recipes are for the package builder. -
Do not switch production from
groupadd/useraddtosystemd-sysuserswithout a separate gated redesign. A migration tosystemd-sysusersexecution requires:- Resolving the SYSUSERS-GECOS-G-LINES format-strictness gap (a known dormant gap in the current
g-line declarations thatsystemd-sysusersrejects butgroupaddaccepts); - Confirming the broader Self-Healing Authority redesign scope before changing the production identity-creation mechanism.
Until both are resolved, the recipe-only adoption is the contract. The CI Runtime Truth Gate verifies that the
tmpfiles.ddirectory authority — which depends on the identities being present — produces the expected on-disk state regardless of whether the mechanism that materialised them was scriptlet orsystemd-sysusers. - Resolving the SYSUSERS-GECOS-G-LINES format-strictness gap (a known dormant gap in the current
| Path | Mode | Owner | Purpose |
|---|---|---|---|
/usr/sbin/nftban |
0750 | root:nftban | Main CLI entry point (RPM %attr(0750,root,nftban); DEB equivalent — group-readable so the nftban group can run it without sudo) |
/usr/lib/nftban/ |
0755 | root:root | Application libraries and modules |
/usr/lib/nftban/bin/ |
0755 | root:root | Go binaries (nftban-core, nftband, nftban validate, nftban-installer, bundled yq) |
/usr/lib/nftban/core/ |
0755 | root:root | Core modules |
/usr/lib/nftban/cli/ |
0755 | root:root | CLI command modules |
/usr/lib/nftban/lib/ |
0755 | root:root | Library modules |
/usr/lib/nftban/exporters/ |
0755 | root:root | Metrics exporters |
/usr/lib/nftban/helpers/ |
0755 | root:root | Helper scripts (trace, autoheal) |
/usr/lib/nftban/modules/ |
0755 | root:root | Protection modules (portscan, ddos, login) |
/usr/lib/nftban/sbin/ |
0755 | root:root | System helper binaries |
/usr/lib/nftban/health/ |
0755 | root:root | Health check modules |
/usr/lib/nftban/setup/ |
0755 | root:root | Setup and installation scripts |
/usr/lib/nftban/cron/ |
0755 | root:root | Cron/timer job scripts |
/usr/lib/nftban/tests/ |
0755 | root:root | Test scripts (selftest suite, validation) |
/usr/lib/nftban/data/ |
0755 | root:root | Static data files (registries, schemas) |
/usr/lib/nftban/tools/ |
0755 | root:root | Utility tools and scripts |
/usr/lib/nftban/scripts/ |
0755 | root:root | Generator + post-install helper scripts |
/usr/lib/nftban/templates/ |
0755 | root:root | Library-side templates (e.g. nftables.conf.tpl) |
All configuration is under /etc/nftban/. Owned by root:nftban with mode 0750 so the daemon can read via group membership but cannot modify.
| Path | Mode | Owner | Purpose |
|---|---|---|---|
/etc/nftban/ |
0750 | root:nftban | Configuration root |
/etc/nftban/nftban.conf |
0640 | root:nftban | Primary config (immutable, chattr +i) |
/etc/nftban/conf.d/ |
0750 | root:nftban | Module configurations |
/etc/nftban/conf.d/ddos/ |
0750 | root:nftban | DDoS protection configuration |
/etc/nftban/conf.d/portscan/ |
0750 | root:nftban | Port scan detection configuration |
/etc/nftban/conf.d/login/ |
0750 | root:nftban | Login monitoring configuration |
/etc/nftban/conf.d/panels/ |
0750 | root:nftban | Control panel configurations |
/etc/nftban/conf.d/botscan/ |
0750 | root:nftban | Bot scanner configuration |
/etc/nftban/whitelist.d/ |
0750 | root:nftban | Whitelist entries |
/etc/nftban/blacklist.d/ |
0750 | root:nftban | Blacklist entries |
/etc/nftban/ports.d/ |
0750 | root:nftban | Port whitelist entries |
/etc/nftban/rules.d/ |
0750 | root:nftban | Custom nftables rules |
/etc/nftban/patterns.d/ |
0750 | root:nftban | Detection pattern files |
/etc/nftban/patterns.d/botscan/ |
0750 | root:nftban | Bot scanner patterns |
/etc/nftban/connectors/ |
0750 | root:nftban | Connector configs (Zabbix, Elasticsearch, Kafka) |
/etc/nftban/distros/ |
0750 | root:nftban | Distribution-specific configuration |
/etc/nftban/access.d/ |
0750 | root:nftban | Access-control entries |
/etc/nftban/templates/ |
0750 | root:nftban | Operator-facing templates (logrotate, etc.) |
/etc/nftban/nftables.d/ |
0750 | root:nftban | Operator nftables overrides |
/etc/nftban/ssl/ |
0750 | root:nftban | TLS material for outbound connectors |
/etc/nftban/conf.d/rbl/ |
0750 | root:nftban | RBL (DNSBL) configuration |
/etc/nftban/conf.d/geoban/ |
0750 | root:nftban | GeoBan configuration |
/etc/nftban/conf.d/geoip/ |
0750 | root:nftban | GeoIP module configuration |
/etc/nftban/conf.d/botguard/ |
0750 | root:nftban | BotGuard configuration |
/etc/nftban/conf.d/botguard/profiles/ |
0750 | root:nftban | BotGuard profile presets |
/etc/nftban/conf.d/suricata/ |
0750 | root:nftban | Suricata-integration configuration |
/etc/nftban/conf.d/tunnel/ |
0750 | root:nftban | DNS-tunnel detector configuration |
/etc/nftban/suricata/ (+ profiles/, config/, rules/, cache/, state/, state/last-good/) |
0750 | root:nftban | Suricata profile/rule/state tree |
Distro configs in /etc/nftban/distros/: almalinux.conf, centos.conf, debian.conf, fedora.conf, rhel.conf, rocky.conf, ubuntu.conf.
Top-level /var/lib/nftban/ is owned by root:nftban as a security boundary to prevent privilege escalation. Most subdirectories where the daemon writes are nftban:nftban. A small number of directories deliberately keep root:nftban ownership (backup territory) or open one specific channel to a different group (the auditor write-channel).
The table below is sourced from install/systemd/tmpfiles.d/nftban.conf and install/packaging/rpm/nftban-files.inc — the two generated authority files. /var/lib/nftban/ and /var/lib/nftban/community/ are package-shipped (RPM %dir %attr + DEB nftban.dirs); the remaining subdirectories are tmpfiles-managed (created at boot or after a systemd-tmpfiles --create run).
| Path | Mode | Owner | Authority | Purpose |
|---|---|---|---|---|
/var/lib/nftban/ |
0750 | root:nftban | package | Application state (security boundary) |
/var/lib/nftban/community/ |
0750 | nftban:nftban | package | Community (shared) data |
/var/lib/nftban/banned/ |
0750 | nftban:nftban | tmpfiles | Banned IP state files |
/var/lib/nftban/whitelist/ |
0750 | nftban:nftban | tmpfiles | Whitelist state files |
/var/lib/nftban/feeds/ |
0750 | nftban:nftban | tmpfiles | Threat feed data |
/var/lib/nftban/geoip/ |
0750 | nftban:nftban | tmpfiles | GeoIP databases (.mmdb files) |
/var/lib/nftban/reports/ |
0750 | nftban:nftban | tmpfiles | Generated reports |
/var/lib/nftban/reports/baseline/ |
0750 | nftban:nftban | tmpfiles | Baseline reports |
/var/lib/nftban/reports/watchdog/ |
0750 | nftban:nftban | tmpfiles | Watchdog system reports |
/var/lib/nftban/reports/auditors/ |
0770 | root:nftban-auditor | tmpfiles | Auditor write-channel (compliance access) |
/var/lib/nftban/reports/archive/ |
0750 | nftban:nftban | tmpfiles | Archived reports |
/var/lib/nftban/metrics/ |
0750 | nftban:nftban | tmpfiles | Metrics database |
/var/lib/nftban/stats/ |
0750 | nftban:nftban | tmpfiles | Runtime statistics |
/var/lib/nftban/stats/history/ |
0750 | nftban:nftban | tmpfiles | Stats history |
/var/lib/nftban/stats/profiles/ |
0750 | nftban:nftban | tmpfiles | Stats profiles |
/var/lib/nftban/snapshots/ |
0750 | nftban:nftban | tmpfiles | Hourly stats snapshots |
/var/lib/nftban/exports/ |
0750 | nftban:nftban | tmpfiles | User data exports (JSON, CSV) |
/var/lib/nftban/queue/ |
0750 | nftban:nftban | tmpfiles | Task queue root |
/var/lib/nftban/queue/pending/ |
0750 | nftban:nftban | tmpfiles | Pending tasks |
/var/lib/nftban/queue/work/ |
0750 | nftban:nftban | tmpfiles | In-progress tasks |
/var/lib/nftban/queue/dlq/ |
0750 | nftban:nftban | tmpfiles | Dead letter queue |
/var/lib/nftban/mailspool/ |
0750 | nftban:nftban | tmpfiles | Failed mail retry queue |
/var/lib/nftban/state/ |
0750 | nftban:nftban | tmpfiles | Runtime state |
/var/lib/nftban/staging/ |
0750 | nftban:nftban | tmpfiles | Staging area |
/var/lib/nftban/config/ |
0750 | nftban:nftban | tmpfiles | Runtime-derived config cache |
/var/lib/nftban/login/ |
0750 | nftban:nftban | tmpfiles | Login monitoring state |
/var/lib/nftban/portscan/ |
0750 | nftban:nftban | tmpfiles | Port scan detector state |
/var/lib/nftban/panels/ |
0750 | nftban:nftban | tmpfiles | Panel adapter state |
/var/lib/nftban/botguard/ |
0750 | nftban:nftban | tmpfiles | BotGuard state |
/var/lib/nftban/tunnel/ |
0750 | nftban:nftban | tmpfiles | DNS-tunnel detector state |
/var/lib/nftban/analytics/ |
0750 | nftban:nftban | tmpfiles | Analytics state |
/var/lib/nftban/recorder/ |
0750 | nftban:nftban | tmpfiles | Event recorder state |
/var/lib/nftban/suricata/ |
0750 | nftban:nftban | tmpfiles | Suricata integration state |
/var/lib/nftban/watchdog/ |
0750 | nftban:nftban | tmpfiles | Watchdog state |
/var/lib/nftban/backup/ |
0750 | root:nftban | tmpfiles | Backup territory (root-owned by intent) |
/var/lib/nftban/update-backups/ |
0750 | root:nftban | tmpfiles | Update-rollback backups (root-owned by intent) |
/var/lib/nftban/pro/ |
0750 | root:nftban | tmpfiles | Pro subscription data (root-owned by intent) |
The directory layer is the only part of the log tree the package authority covers. Per-file ownership and mode for individual log files (bans.log, nftban-actions.log, portscan.log, etc.) are not declared in tmpfiles.d, nftban-files.inc, or nftban-dir-attrs.list; those files are created at runtime by the daemon and the project does not currently ship a per-file authority assertion for them. If you need an exact statement of per-file mode/owner, read it from the running system rather than from this page.
The directory rows below are sourced from install/systemd/tmpfiles.d/nftban.conf:
| Path | Mode | Owner | Purpose |
|---|---|---|---|
/var/log/nftban/ |
0750 | nftban:nftban | Log root |
/var/log/nftban/watchdog/ |
0750 | nftban:nftban | Watchdog logs |
/var/log/nftban/reports/ |
0750 | nftban:nftban | Report logs |
/var/log/nftban/rbl/ |
0750 | nftban:nftban | RBL check cache |
/var/log/nftban/botguard/ |
0750 | nftban:nftban | BotGuard logs |
/var/log/nftban/metrics/ |
0750 | nftban:nftban | Metrics logs |
/var/log/nftban/soak/ |
0750 | nftban:nftban | Soak-test logs |
Log rotation is configured in /etc/logrotate.d/nftban, installed by the package from install/config/nftban.logrotate (mode 0644, %config(noreplace)). The Suricata-integration logs use a separate drop-in: /etc/logrotate.d/nftban-suricata. Both files use copytruncate so processes that hold open file handles do not need to be reloaded after rotation.
| Path | Mode | Owner | Purpose |
|---|---|---|---|
/var/cache/nftban/ |
0755 | nftban:nftban | Cache files |
/var/cache/nftban/health/ |
0750 | nftban:nftban | Health check status cache |
/run/nftban/ |
0755 | nftban:nftban | Runtime data (PID files, sockets, locks) |
/run/nftban/ is managed by tmpfiles.d only. Do not use RuntimeDirectory= in unit files to avoid ownership conflicts.
Read-only application data, installed by the package.
| Path | Mode | Owner | Purpose |
|---|---|---|---|
/usr/share/nftban/ |
0755 | root:root | Shared application data |
/usr/share/nftban/templates/ |
0755 | root:root | Templates root |
/usr/share/nftban/templates/mail/ |
0755 | root:root | Mail templates |
/usr/share/nftban/templates/reports/ |
0755 | root:root | Report templates |
/usr/share/nftban/templates/zabbix/ |
0755 | root:root | Zabbix import templates |
/usr/share/nftban/dashboards/grafana/ |
0755 | root:root | Grafana dashboard JSON files |
/usr/share/nftban/specs/ |
0755 | root:root | Specification files |
/usr/share/bash-completion/completions/nftban |
0644 | root:root | Bash tab completion |
Note: the package does not ship a man page. CLI documentation is registry-driven (
commands.registry.ymlconsumed bynftban help/scripts/generate-help.sh). The hand-maintainedinstall/man/man8/nftban.8was retired because it competed with the registry source-of-truth and caused symmetric DEB+RPM Phase-6 verify failures. If you see a/usr/share/man/man8/nftban.8on a host, it is a leftover from an older install — newer packages do not place it.
/usr/lib/tmpfiles.d/nftban.conf creates the runtime directory tree under /var/lib/nftban/, /var/log/nftban/, /var/cache/nftban/, and /run/nftban/. Generated from fhs-spec.yaml.
systemd-tmpfiles --create /usr/lib/tmpfiles.d/nftban.confThe current generated file uses only d (create) directives — there are no z/Z (enforce-ownership) directives in the current authority. If a directory already exists at the time tmpfiles runs, systemd-tmpfiles will not silently re-chown it. Ownership convergence on an existing tree is the responsibility of the install scriptlet (postinst chown loop reading nftban-dir-attrs.list) and the nftban permissions enforce command.
nftband.socket does not create /run/nftban/ — its previous RuntimeDirectory= directive was removed; the socket unit now relies on tmpfiles.d having created the directory.
/usr/lib/sysusers.d/nftban.conf is the declarative identity recipe, generated from fhs-spec.yaml. It records the intended groups and user.
In current packages, systemd-sysusers is not the identity-creation mechanism. The DEB postinst / RPM %pre scriptlets create identities directly with getent / groupadd / useradd. The sysusers.d file documents the contract; the scriptlet enforces it.
The form below is the upstream invocation that would materialise the recipe via systemd-sysusers, shown for reference only — it is not part of the install-time path:
# Reference only — not executed by NFTBan's package install path today:
systemd-sysusers /usr/lib/sysusers.d/nftban.confSee Identity authority model for the full format-vs-mechanism explanation and the cautions that apply before any migration to systemd-sysusers execution.
All installed to /usr/lib/systemd/system/ (or /lib/systemd/system/ on Debian). The canonical list (and per-unit description) lives in Systemd Units Overview; the table below is a curated subset of the most operator-relevant units. For the complete unit inventory, see install/systemd/ in the repo.
| Unit | Purpose |
|---|---|
nftband.service |
Main daemon (single nftables writer; socket-activated by nftband.socket) |
nftban-core-feeds.service |
Threat feed updater |
nftban-core-geoip.service |
GeoIP database updater |
nftban-health.service |
Periodic health check with auto-heal |
nftban-health-fix.service |
On-demand privileged health fix (root, manual) |
nftban-maintenance.service |
Maintenance tasks |
nftban-watchdog.service |
Runtime monitoring |
nftban-queue.service |
Queue processor |
nftban-unified-exporter.service |
Unified metrics exporter |
nftban-snapshot.service |
Stats snapshot |
nftban-rollback.service |
Rollback service |
nftban-suricata.service |
Suricata integration wrapper |
nftban-suricata-update.service |
Suricata rule updater |
nftban-firewall-init.service |
Firewall initialization |
nftban-rebuild-recovery.service |
Rebuild recovery (post-failure) |
nftban-soak.service |
Post-install soak validation |
nftban-report-daily.service |
Daily report generator |
nftban-community-stats.service |
Community-stats opt-in submitter |
nftban-rbl-check.service |
RBL check |
nftban-botscan.service |
Bot scanner |
nftban-tunnel.service |
DNS-tunnel detector |
nftban-update-check.service |
Update-availability check |
nftban-update-apply.service |
Update apply |
nftban-pro-inventory.service |
Pro-tier inventory (where applicable) |
nftban-pro-license.service |
Pro-tier license validator |
nftban-suricata-stats.service |
Suricata stats |
nftban-alert@.service |
Alert dispatch (templated) |
| Timer | Purpose |
|---|---|
nftban-health.timer |
Periodic health check |
nftban-maintenance.timer |
Periodic maintenance |
nftban-watchdog.timer |
Periodic runtime monitoring |
nftban-queue.timer |
Queue processing |
nftban-unified-exporter.timer |
Metrics export |
nftban-snapshot.timer |
Stats snapshot |
nftban-rollback.timer |
Rollback cleanup |
nftban-core-feeds.timer |
Threat feed update |
nftban-core-geoip.timer |
GeoIP update |
nftban-suricata-update.timer |
Suricata rule update |
nftban-rebuild-recovery.timer |
Rebuild recovery |
nftban-soak.timer |
Soak validation |
nftban-report-daily.timer |
Daily report |
nftban-community-stats.timer |
Community stats |
nftban-rbl-check.timer |
RBL check |
nftban-botscan.timer |
Bot scanner |
nftban-tunnel.timer |
Tunnel detector |
nftban-update-check.timer |
Update check |
nftban-update-apply.timer |
Update apply |
nftban-pro-inventory.timer |
Pro inventory |
nftban-pro-license.timer |
Pro license |
(Specific schedules, calendars, and deltas live in Systemd Units Overview and the unit files themselves; this page does not duplicate them to avoid drift.)
| Path | Owner | Reason |
|---|---|---|
/etc/nftban/ |
root:nftban (0750) | Config readable by daemon via group, not writable |
/var/lib/nftban/ |
root:nftban (0750) | Security boundary: root-owned top-level prevents privilege escalation |
/var/lib/nftban/*/ |
nftban:nftban (0750) | Subdirectories are daemon-writable |
/var/lib/nftban/reports/auditors/ |
root:nftban-auditor (0770) | Auditor group has access for compliance |
/var/log/nftban/ |
nftban:nftban (0750) | Daemon-written logs |
/var/log/nftban/*.log |
runtime-created; no package-level per-file authority | Directory layer (/var/log/nftban 0750 nftban:nftban) is authoritative. Individual log file owner/mode is not declared by any generated package authority. After first logrotate rotation, install/config/nftban.logrotate's create 0640 nftban nftban directive applies to listed files. |
/usr/lib/nftban/ |
root:root (0755) | Read-only libraries, executable by all |
Immutable files (chattr +i):
-
/etc/nftban/nftban.conf— prevent config tampering -
/usr/lib/nftban/lib/nft_schema.sh— prevent nftables command injection
The immutable attribute is set by the package %post script and removed by %preun before upgrades.
Linux capabilities (setcap cap_net_admin+ep):
/usr/lib/nftban/bin/nftban-core/usr/lib/nftban/bin/nftband
Both binaries receive CAP_NET_ADMIN so they can perform nftables operations without running as root. The capabilities are applied by the Go installer (internal/installer/fhs/permissions.go::SetCapabilities) when the system has setcap available; if setcap is missing the step is skipped with a debug log. The health check verifies the resulting state and reports drift.
Permissions are enforced through three layers:
-
tmpfiles.d (runtime) — Creates missing directories at boot or on explicit
systemd-tmpfiles --create; it does not re-chown already-existing trees because the current generated file uses onlyddirectives. -
Package scripts (installation) — RPM
%post/ DEBpostinstset initial ownership and permissions. -
Health auto-heal (ongoing) —
nftban-health.serviceperiodically checks and fixes permissions. Runs asnftbanuser withCAP_NET_ADMIN; root-only operations (chown) are skipped gracefully.
For manual enforcement as root:
nftban health fix allPolkit rules control which systemd units the nftban group can manage without root. The install path differs by packager:
-
RPM (Fedora/RHEL/AlmaLinux/Rocky/CentOS Stream) ships rules at
/etc/polkit-1/rules.d/. -
DEB (Debian/Ubuntu) ships rules at
/usr/share/polkit-1/rules.d/(per the upstream Debian polkit packaging convention).
Both locations are picked up by polkitd at runtime; the difference is purely packaging convention.
| Rule File | Group | Access Level |
|---|---|---|
10-nftban-systemd.rules |
nftban |
Start/stop/restart/reload whitelisted units |
20-nftban-auditor.rules |
nftban-auditor |
Read-only status queries |
30-nftban-panel.rules (retired v1.137)
|
— |
Not shipped. Only 10-nftban-systemd.rules + 20-nftban-auditor.rules are installed |
The operator rule (10-nftban-systemd.rules) uses explicit unit whitelisting only. No wildcards or prefix matching. See Polkit for the full allowlist.
/etc/nftban/nftban.conf defines canonical path variables. Scripts must source this file and reference variables rather than hardcoding paths.
NFTBAN_BIN="/usr/sbin/nftban"
NFTBAN_CORE_BIN="/usr/lib/nftban/bin/nftban-core"
NFTBAN_LIB_DIR="/usr/lib/nftban"
NFTBAN_CONFIG_DIR="/etc/nftban"
NFTBAN_DATA_DIR="/var/lib/nftban"
NFTBAN_LOG_DIR="/var/log/nftban"
NFTBAN_CACHE_DIR="/var/cache/nftban"
NFTBAN_RUN_DIR="/run/nftban"
NFTBAN_DISTRO_CONF_DIR="/etc/nftban/distros"# Check FHS compliance status
nftban fhs status
# Fix permissions (requires elevated privileges; members of the nftban group are authorized via PolicyKit/polkit)
nftban health fix permissions
# Fix all detected issues (requires elevated privileges; members of the nftban group are authorized via PolicyKit/polkit)
nftban health fix all
# Run health check with auto-heal (as nftban user or root)
nftban health check --auto-healPermission denied when running CLI commands
Cause: User is not in the nftban group.
sudo usermod -aG nftban $USER
# Log out and back in for group membership to take effect/run/nftban/ owned by root:root after reboot
Cause: tmpfiles.d did not run, or it ran before the nftban system group existed (so the chown step silently fell through to root:root defaults).
# Re-run tmpfiles.d explicitly. Requires the nftban group to exist (it is
# created by the package postinst); on a freshly-imaged system you may
# need to run the postinst-equivalent identity creation first.
sudo systemd-tmpfiles --create /usr/lib/tmpfiles.d/nftban.conf/run/nftban/ is created exclusively by tmpfiles.d — nftband.socket does not declare a RuntimeDirectory= directive (this was removed to prevent a previously-observed ownership race). The current tmpfiles.d/nftban.conf uses only d (create) directives, so a directory that already exists with the wrong owner will not be silently re-chowned by tmpfiles; ownership convergence on an existing tree is the responsibility of the install scriptlet's chown loop or nftban permissions enforce.
run as root during health fix
Cause: Operations like chown require elevated privileges (members of the nftban group are authorized via PolicyKit/polkit rules).
nftban health fix allAuto-heal (nftban-health.service) handles non-root operations automatically. Root-only operations are skipped with a warning.
- build/fhs-spec.yaml — Canonical FHS specification (single source of truth)
- cli/lib/nftban/core/nftban_fhs_spec.sh — Runtime FHS implementation
- install/systemd/tmpfiles.d/nftban.conf — Directory creation (generated)
- install/systemd/sysusers.d/nftban.conf — User/group creation (generated)
- Linux FHS 3.0 Specification
- Configuration
- Security Architecture
- Polkit
- Health Checks
See also: Logging, Rotation & Retention and Audit Reports & Compliance for path-specific operational detail.
NFTBan Wiki
Getting Started
Architecture
- Architecture Overview
- Firewall Anchor Architecture
- NFT Schema & Validator Model
- Health & Validation
- Startup Lifecycle & Readiness
- Metrics & Evidence Model
- Watchdog & Resource Profiles
- Security Architecture
Protection & Monitoring
- Protection & Monitoring Modules
- BotGuard — HTTP Guard
- BotScan — HTTP Exploit Scanner
- DDoS Protection
- Portscan Detection
- Login Monitoring
- Blacklist & Threat Feeds
- Suricata IDS Integration
- RBL Monitoring
- DNS Tunnel Detection
Operator Reference
- CLI Commands Reference
- Configuration Reference
- Systemd Units & Timers
- Optimization & Tuning
- Security Operations Guide
- GeoIP Database Guide
- FHS Compliance
- Troubleshooting & Selftest
- Support Bundle & Incident Diagnostics
Operations, Communications & Reporting
- Maintenance & Scheduled Operations
- Logging, Rotation & Retention
- Communications & Notifications
- Notification & Report Templates
- Audit Reports & Compliance
Verification & Trust
Reference
Legal