release / release (push) Successful in 1m6s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
143 lines
7.3 KiB
Markdown
143 lines
7.3 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
|
|
([docs/flowtable.md](docs/flowtable.md)).
|
|
* **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)).
|
|
* **Try it first, in shadow mode.** Housecarl's ruleset runs beside the
|
|
firewall you have, blocking nothing: its hits, log and tracer show what
|
|
it would drop, so you see what switching over would break before you do
|
|
([docs/shadow.md](docs/shadow.md)).
|
|
* **Ban lists for Guard and fail2ban.** A program on any machine bans an
|
|
address it caught misbehaving in its logs, and the ban list says what
|
|
that address is kept from: the firewall, some hosts, or everything
|
|
([docs/bans.md](docs/bans.md)).
|
|
* **Easy to watch.** A zone matrix of what is allowed between zones,
|
|
statistics over time (traffic per zone and device, drops, the sources
|
|
blocked most, connections; [docs/stats.md](docs/stats.md)), hits per rule, a live log of what was dropped and
|
|
why, the connections the firewall tracks (and closing them), a packet
|
|
tracer that names the rule that dropped something, in any table, 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; should it fail to load, a fallback keeps
|
|
anything new from the internet out until housecarld puts it back.
|
|
* **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
|
|
* [bans.md](docs/bans.md): ban lists, where Guard and fail2ban ban addresses
|
|
* [import.md](docs/import.md): moving from an existing nftables ruleset
|
|
* [shadow.md](docs/shadow.md): shadow mode, Housecarl beside your firewall, changing nothing
|
|
* [operations.md](docs/operations.md): probation, the boot and its fallback, hits and the log, monitoring, backups, troubleshooting
|
|
* [flowtable.md](docs/flowtable.md): the fast path for forwarded traffic, and when (not) to use it
|
|
* [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.2.0 is in testing (0.2.0-rc.3+git62-0d16358): 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 (confirmed by the client that made them), the ruleset
|
|
at boot with a fail-closed fallback, hits and the drop log, nftables
|
|
import, changesets reviewed with the ruleset's diff (as in Jarl),
|
|
bandwidth limits and quotas, shadow mode beside another firewall, ban
|
|
lists for Guard and fail2ban, a web UI, REST API and CLI.
|
|
|
|
## Licence
|
|
|
|
MIT, see [LICENSE](LICENSE).
|