
Web interface for the nftables firewall on Linux, written in Go. The apply undoes itself after 120 seconds unless you confirm it — you cannot lock yourself out. Debian & Docker install.
nftables through a web interface that cannot lock you out: every apply reverts itself unless you confirm it.
Editing a rule changes nothing. Applying it changes everything — for 120 seconds. If the new rules cut your connection you cannot click Confirm, and not confirming is what brings the old rules back.
Two processes. The one exposed to the network holds no privilege worth stealing.
A complete rewrite of the original easywall — Python, Flask, iptables via
subprocess — which was archived in 2022 after a CVE. Both root causes are gone:
the privileges live in a different process, and the apply path builds Go structs
instead of a command line. How it works →
# Debian / Ubuntu — amd64 and arm64
ARCH=$(dpkg --print-architecture)
wget https://github.com/jp1337/easywall/releases/latest/download/easywall_$ARCH.deb
sudo dpkg -i easywall_$ARCH.deb && sudo apt-get install -f
# Docker
git clone https://github.com/jp1337/easywall.git && cd easywall && docker compose up -d
# From source — Go 1.26+, nftables
git clone https://github.com/jp1337/easywall.git && cd easywall
make build && sudo make install
sudo systemctl enable --now easywall-core easywall-web
Then open https://localhost:12227. The first visit
sets up the account and stages the first rules.
| Ports | TCP and UDP, single or range, with per-rule SSH brute-force routing |
| Blacklist & whitelist | IPv4, IPv6 and CIDR, evaluated before any port rule |
| Protection modules | Twelve, five on by default — floods, scans, bogons, fragments, broadcast/multicast/anycast |
| Port forwarding | NAT redirects with protocol selection |
| Custom rules | Raw nftables, syntax-checked before it is applied |
| Export / import | The whole rule set as JSON |
| Audit log | What changed and when, one JSON object per line |
| Docker coexistence | Owns table inet easywall, touches nothing else |
| English & German | Switchable in the interface, including before sign-in |
| Light & dark | Follows the OS, with a manual toggle; both contrast-checked |
| Go 1.26, single binary | go-chi/chi · html/template |
nftables via google/nftables | direct netlink, no nft subprocess |
| Argon2id | golang.org/x/crypto, 16-byte salt per password |
| CSRF | net/http.CrossOriginProtection, Go 1.25 native |
| Design system | DESIGN.md + Tailwind v4 — no third-party UI library |
| Fonts | Inter + JetBrains Mono, self-hosted, ~145 KB — works air-gapped |
| CI | govulncheck, gosec, CodeQL, -race, and an integration suite against a real kernel |
Correctness first: a firewall that quietly does less than it says is worse than one that does less and says so. Ordered by exposure — the holes first, then comprehension, then reach:
| 2.7 | The firewall survives a reboot — no more accidental way back in through a restart |
| 2.8 | A second factor — TOTP, recovery codes, and login events in the audit log |
| 2.9 | What changes is on the screen before you apply it — and whether it cuts you off |
| 2.10 | A rule names a service and who may reach it, from a curated catalogue |
Twelve releases in total, why each comes when it does, and what is deliberately excluded: Roadmap →
| A question, or something not behaving | Discord |
| A bug, or a feature you want | GitHub issues |
| A security vulnerability | Security advisory — not Discord, and not a public issue |
Setup, commit conventions and the review checklist: CONTRIBUTING.md.
Anything visual goes through DESIGN.md first.
Security issues: not as a public issue — use GitHub Security Advisories.
GPL-3.0 — see LICENSE.