nftables is the right tool for a Linux firewall and a genuinely nice piece of
engineering, but writing rulesets by hand is a niche pleasure. If you run a homelab
or a small cloud box and you want a firewall you can see and click, without pulling
in a whole appliance distribution or standing up something in the cloud, there is a
free, open-source option worth knowing about:
enforza-cockpit. It is a Cockpit plugin that gives you a browser GUI over
nftables. Install it, build a policy, and watch per-rule logs land in your syslog.
This article walks through what it is and how to use it. It asks nothing of you and
there is nothing to buy, so read it as a how-to. The one-line disclosure of who
makes it is at the bottom where it belongs.
What it actually is
enforza-cockpit turns a single Linux box into three things that usually come
separately, all on the one host and with nothing external to depend on:
- A firewall. Three rule sections compile to a live nftables ruleset that filters traffic to, through, and from the host.
- A router and NAT gateway. Turn on IP forwarding and the box routes between its interfaces; mark a rule SNAT and it masquerades outbound traffic, so it works as an edge gateway for whatever sits behind it.
- A management console. Cockpit's web UI is the console. You build, preview, apply and log every rule from the browser. There is no separate controller, no agent phoning home, and no cloud account.
Because it runs entirely on the one host and inside Cockpit's own authentication
and TLS, the result is a stand-alone appliance you happen to manage from a web
page. That is the whole idea: a clean GUI wrapper for a local nftables firewall,
nothing more clever than that.
Installing it
You need a Linux server with root or sudo, inbound access to TCP 9090 (Cockpit's
web port) from wherever you browse, and a browser. On a cloud instance, open 9090
in the security group to your own IP only, not the world.
There are two scripts. The first clones the repo and installs the prerequisites,
detecting your package manager along the way:
git clone https://github.com/enforza/enforza-cockpit.git
cd enforza-cockpit
sudo ./bootstrap.sh
That pulls in nftables, its JSON/Python bindings (so the GUI can read and write the
ruleset programmatically), ulogd2 for userspace netfilter logging, and Cockpit
itself. It enables Cockpit's socket immediately, and enables the nftables service
but deliberately does not start it with an empty ruleset, so it cannot lock you out
before you have written a policy.
The second script installs the plugin into Cockpit:
sudo ./deploy.sh
That copies the built files into Cockpit's system package directory
(/usr/share/cockpit/enforza). Browse to https://<your-host>:9090, accept the
self-signed certificate warning on a fresh install, and log in with a local system
account that can use sudo. The firewall plugin needs administrative privilege, so
if Cockpit shows a "Limited access" banner, click it and re-authenticate. The
plugin then appears as Firewall (enforza) in the left-hand menu.
The three chains, in plain terms
The reason a GUI over nftables is useful is that the mental model is simple once
someone lays it out. enforza-cockpit gives you three rule sections, and each maps
directly to one of nftables' filter hooks:
| Tab | nftables hook | What it controls |
|---|---|---|
| Management | input |
Traffic to the box itself: SSH, the Cockpit port, health checks. |
| Network | forward |
Traffic passing through the box between other hosts and the internet. |
| Local | output |
Traffic originating from the box: updates, DNS, outbound calls. |
Each section has a default action (accept or drop). First match wins; anything a
rule does not catch falls through to the default. There is also an Objects tab
for reusable named network (CIDR) and port sets: define home-lan, mgmt, web
once and reference them as @home-lan, @web and so on across any rule. Edit the
object and every rule using it updates, which is the same reason you use named sets
in a hand-written ruleset, minus the typing.
If you have ever stared at input, forward and output in the docs and not
been quite sure which one your rule belonged in, seeing them as three labelled
tabs is most of the value on its own.
Building a first policy
The safe first policy is a locked-down Management section: allow SSH and the
Cockpit port from your own address, drop everything else. In the Management tab,
set the default action to drop, then add a rule:
-
Action
accept, Protocoltcp, Destination port22 -
Source your admin IP or CIDR (or
anyto start with) - Tick Log matches, which is what puts the rule in your syslog
-
Comment
SSH from admin, which is included in the log line, so make it mean something
Add a second rule the same way for TCP 9090 so you keep the Cockpit UI. And heed
the obvious warning: allow SSH and Cockpit from your own IP before you apply a
default-drop policy, or you will be relying on the auto-revert to get back in.
Then the apply flow, which is the part that makes this safe to do on a box you care
about:
- Preview renders the policy to nftables JSON and dry-runs it against the kernel. A green "Valid" means the kernel accepts it.
- Apply puts it live and starts a confirm-or-revert banner with a 60-second countdown.
- Verify you still have access. Open a fresh SSH session, or just check the Cockpit page still responds.
- Confirm to keep the ruleset. Do nothing and it auto-reverts to the previous one; there is also a Revert now button.
-
Save persists the policy document to
/etc/enforza/policy.jsonso it reloads next time.
Your rules are now live in the inet enforza nftables table, and you can always
check what actually landed from a shell with sudo nft list table inet enforza.
The GUI is a front end; the kernel state is the truth, and nothing stops you
reading it directly.
Turning it into a router and NAT gateway
The Network tab (the forward path) is where the box stops being just a host
firewall and becomes a gateway. Turn on Enable routing to switch on IP
forwarding, then add a Network rule and mark it SNAT. That masquerades outbound
traffic from the hosts behind the box out through its public interface, so a single
Linux instance becomes the edge gateway for a whole segment: a lab network, a set
of VMs, or the machines on a home LAN. Network rules can carry both a LOG flag
and the SNAT flag, so you can log and source-NAT the same traffic, and
reference @objects for source, destination and ports to keep the rules readable.
That is the same job a small cloud NAT instance does, on hardware you already have.
Watching the logs
Any rule with Log matches ticked emits a kernel log line each time it matches,
and enforza-cockpit tags every line with three useful things: the section
(to-firewall, through-firewall or from-firewall), a plain verdict word
(ALLOW, DENY or REJECT), and your rule's comment. So a matched SSH accept
reads like:
kernel: enforza to-firewall ALLOW: SSH from admin IN=eth0 ... SRC=203.0.113.10 DPT=22 ...
Because the verdict is a plain word, grep does the rest:
sudo tail -f /var/log/syslog | grep 'enforza.*DENY' # only denials
sudo tail -f /var/log/syslog | grep 'SSH from admin' # one rule, by its comment
On distributions without /var/log/syslog (many dnf-based ones), read the kernel
log through the journal instead with sudo journalctl -kf | grep enforza.
One gotcha worth internalising, because it catches everyone once: a section's
default drop is not logged. If you want to see what is being denied, add an
explicit last rule with Action drop (or reject), Source any and
Log matches ticked, and make sure it sits at the bottom of the list. First
match wins, so a logging catch-all only works as the final rule.
What it isn't
Since being honest about limits is more useful than a feature list, here is what
enforza-cockpit does not do:
-
No application-layer filtering. It is plain nftables: L3/L4 rules plus SNAT.
There is no FQDN or hostname filtering, no SNI inspection, no L7 anything. If you
need to allow
github.combut not the rest of the internet, this is not the tool. - One host, not a fleet. It manages the box it runs on. There is no central console, no pushing one policy to many machines, and no policy-as-code pipeline. For a homelab that is exactly right; for fifty boxes it is fifty logins.
- A static ruleset. The kernel enforces the rules you compiled. It does not learn, score, or adapt, and it does not pretend to.
None of that is a criticism. It is a small, sharp tool that does one job well, and
knowing the edges is what lets you use it confidently.
Who makes it
enforza-cockpit is a free, MIT-licensed community tool from the people behind
enforza, a managed cloud-firewall platform. It needs no
account and no cloud connection, the code is open so you can read exactly what it
does to your box, and contributions and bug reports are welcome. That is the whole
disclosure. Go build a firewall.
FAQ
Frequently asked questions
Is enforza-cockpit really free?
Yes. It is MIT-licensed and open source, needs no account, no cloud connection and no subscription, and all firewall state stays on your machine. The repo is github.com/enforza/enforza-cockpit.
What is it built on?
It is a plugin for Cockpit, the web console that ships with most Linux distributions. The GUI renders your policy to a live nftables ruleset (in a table called inet enforza) and lets the kernel do the enforcing. A bootstrap script installs nftables, its JSON/Python bindings, ulogd2 for logging, and Cockpit itself.
Which Linux distributions does it support?
Debian and Ubuntu, Fedora, RHEL/Rocky/Alma, and openSUSE. The bootstrap script detects your package manager (apt, dnf, yum or zypper) so the same steps work across the common homelab and small-cloud distributions.
Can a bad rule lock me out of the box?
It is designed so it cannot, permanently. Every apply uses a confirm-or-revert model: after you click Apply you have 60 seconds to click Confirm, and if you do not, the previous ruleset is automatically restored. Keep a second way onto the box handy the first few times anyway. If you ever do get stuck, get on out-of-band and run nft flush ruleset or nft delete table inet enforza.
Does it do FQDN or application-layer filtering?
No, and it is worth being clear about that. It is a GUI over plain nftables: L3/L4 rules on the three chains (traffic to, through and from the host) plus SNAT. There is no FQDN, SNI or other L7 filtering, and it manages one host, not a fleet. If that is what you need, this is not the tool.
Can it act as a router and NAT gateway?
Yes. Turn on Enable routing (IP forwarding) and the box routes between its interfaces; mark a Network rule SNAT and it masquerades outbound traffic, so it works as an edge gateway for the machines behind it. That is the homelab use case it is happiest in.

Top comments (0)