Changesets, as in Jarl: configuration changes are operations that can be staged in a changeset, checked as they are added (validation and nft -c), reviewed with the diff of the ruleset, and applied together as one history entry, then on probation like any change made over the network. The web UI collects edits for review by default (pending rows, a bar with Review and Apply now, a Changes page, a switch for live edits); hc stages with -C ID or HOUSECARL_CHANGESET (checked like JARL_CHANGESET) and has hc changeset create/list/show/diff/apply/discard/remove. Undo, import and takeover refuse a changeset. --dry-run shows the ruleset's diff. Bandwidth and quotas: rate limits in bytes, per source or destination; quotas per rule or per address that reset daily, weekly, monthly on a day, or by hand, with their usage carried across reloads, saved for reboots, shown by hc quotas and on the rules page, and reset with hc rule reset-quota. Rules that count traffic are checked before established connections are accepted (so they see every packet) and can't accept. Per-address limits group IPv6 by /64 by default (--group-v4/-v6). Per-source rate meters use update. The importer turns meters, byte rates and quotas into these fields. The examples in the web UI, hc's help and the docs use documentation addresses and generic names instead of the maintainer's network. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
123 lines
5.8 KiB
Markdown
123 lines
5.8 KiB
Markdown
<p align="center"><img src="artwork/banner.svg" width="340" alt="Housecarl: a carved Nordic doorway, above the HOUSECARL wordmark"></p>
|
|
|
|
# Housecarl
|
|
|
|
*Every Jarl has a housecarl at his side; this one keeps the door.*
|
|
|
|
Housecarl is a firewall for Linux that you manage through a web UI, a
|
|
REST API and a command line client (`hc`), all three backed by the same
|
|
API. It is the third of a set with [Jarl](https://gitea.adbraun.lol/adam/jarl),
|
|
the BIND manager, and [Steward](https://gitea.adbraun.lol/adam/steward), the
|
|
DHCP server, and works the same way: every change is checked as a whole
|
|
before it is used, is recorded in a history where it can be undone, and is
|
|
audited.
|
|
|
|
In Skyrim, a housecarl is the Jarl's sworn bodyguard: it stands at the
|
|
door and decides who comes in. Housecarl does that for your network. It
|
|
keeps the machine's nftables ruleset, built from its own database, in one
|
|
table of its own.
|
|
|
|
## What it does
|
|
|
|
* **Zones, sets and services, then rules.** Name your interfaces (`wan`,
|
|
`lan`, `wg`), your addresses (`trusted`, IPv4 and IPv6 in one set) and
|
|
your ports (`web`, or the built-in `ssh`, `dns`, `https`…), and
|
|
write ordered rules with them: in, out or through the firewall, by
|
|
zone, address, service, connection state, time of day, rate per
|
|
source, or connection count. Anything else can be written as an
|
|
nftables rule by hand.
|
|
* **Bandwidth and quotas.** Byte-rate limits per device, and traffic
|
|
allowances that reset daily, weekly or monthly (or by hand), counted
|
|
across changes and reboots.
|
|
* **IPv4 and IPv6 together.** One rule covers both; Housecarl writes the
|
|
nftables rules each family needs.
|
|
* **NAT in one object.** A port forward is the DNAT, the forward accept
|
|
and the hairpin NAT together, and can open the same port to an IPv6
|
|
host. Masquerading, SNAT and redirects too.
|
|
* **The rules every firewall needs**, built in and each one switchable:
|
|
loopback, established connections, invalid packets, the ICMPv6 that
|
|
IPv6 needs, antispoofing for your prefixes, MSS clamping for PPPoE, the
|
|
DHCPv6 client, and a flowtable fast path.
|
|
* **Changes you can trust.** Each change is validated as a whole, checked
|
|
by nftables itself, and applied in one transaction. As in Jarl, edits
|
|
can be collected in a changeset, reviewed with the diff of the ruleset,
|
|
and applied (or discarded) together. A change made over
|
|
the network is on probation: unless you confirm it within two minutes,
|
|
it rolls itself back, so a rule that cuts you off undoes itself.
|
|
* **Your existing ruleset, imported.** `hc import` turns an nftables
|
|
ruleset into zones, sets, services, rules and port forwards, keeping the
|
|
rules' order, and keeps what it can't translate as raw rules
|
|
([docs/import.md](docs/import.md)).
|
|
* **Easy to watch.** Hits per rule, a live log of what was dropped and
|
|
why, and the history of every change, field by field, with undo.
|
|
* **Its own table only.** Docker, Incus and libvirt keep theirs. The
|
|
confirmed ruleset is loaded at boot, before the network comes up, even
|
|
if housecarld doesn't start.
|
|
* **Sets other programs can fill.** A dynamic set's entries expire by
|
|
themselves, and a token can be limited to one set: that is how
|
|
Steward's captive portal will let a guest in.
|
|
* **Users, tokens and HTTPS** as in Jarl and Steward, with the web UI's
|
|
certificate from Let's Encrypt through Jarl
|
|
([docs/certificates.md](docs/certificates.md)).
|
|
|
|
Not yet: rules by MAC address or DNS name, and iptables import
|
|
([docs/design.md](docs/design.md)).
|
|
|
|
## Quick start
|
|
|
|
On Debian 13, from the package registry (see
|
|
[docs/install.md](docs/install.md) for other ways):
|
|
|
|
```sh
|
|
sudo apt install housecarl
|
|
sudo -u housecarl housecarld init # asks for the admin password
|
|
sudo systemctl enable --now housecarl # applies nothing until configured
|
|
|
|
# Import the ruleset you have...
|
|
sudo hc import --defines /etc/nftables.conf -n # look first
|
|
sudo hc import --defines /etc/nftables.conf
|
|
sudo hc takeover "inet main"
|
|
sudo systemctl disable nftables.service
|
|
|
|
# ...or start from scratch: let yourself in first
|
|
sudo hc set add admins 192.168.1.0/24
|
|
sudo hc rule add input --from admins --service ssh
|
|
sudo hc zone add wan --interface ppp0 --external
|
|
sudo hc zone add lan --interface eth1
|
|
sudo hc rule add forward --in lan --out wan
|
|
sudo hc snat add --out wan
|
|
sudo hc status
|
|
```
|
|
|
|
The web UI is on `http://127.0.0.1:8070/` (see `listen` in
|
|
`/etc/housecarl/housecarl.yaml`); write a rule that lets you reach it.
|
|
|
|
## Documentation
|
|
|
|
* [install.md](docs/install.md): packages, building from source, first steps
|
|
* [rules.md](docs/rules.md): zones, address sets, services, rules and the built-ins
|
|
* [nat.md](docs/nat.md): port forwards, hairpin NAT, IPv6 pinholes, source NAT, redirects
|
|
* [import.md](docs/import.md): moving from an existing nftables ruleset
|
|
* [operations.md](docs/operations.md): probation, the boot, hits and the log, backups, troubleshooting
|
|
* [certificates.md](docs/certificates.md): HTTPS with a certificate from Let's Encrypt, through Jarl
|
|
* [jarl.md](docs/jarl.md): connecting Housecarl to Jarl, and what its token may do
|
|
* [cli.md](docs/cli.md): the `hc` command line client
|
|
* [api.md](docs/api.md): the REST API
|
|
* [configuration.md](docs/configuration.md): `/etc/housecarl/housecarl.yaml`
|
|
* [permissions.md](docs/permissions.md): users, roles, grants and API tokens
|
|
* [validation.md](docs/validation.md): every check and what it means
|
|
* [design.md](docs/design.md): how Housecarl is built, and what 0.1 leaves out
|
|
* [development.md](docs/development.md): building, testing, releasing
|
|
|
|
## Status
|
|
|
|
Housecarl 0.1.0 is in testing (0.1.0-rc.1): zones, address sets and
|
|
services with ordered rules, IPv4 and IPv6, port forwards with hairpin NAT
|
|
and IPv6 pinholes, source NAT and redirects, built-ins, probation for
|
|
network changes, the ruleset at boot, hits and the drop log, nftables
|
|
import, a web UI, REST API and CLI.
|
|
|
|
## Licence
|
|
|
|
MIT, see [LICENSE](LICENSE).
|