Reverse lookups (internal/names, POST /names) put a name beside each inside address in connections, the log, quota usage, the dashboard's quotas and the statistics' devices and blocked sources, in the web UI and hc (--no-names to leave them out). Only inside addresses are looked up: an inside zone's networks, and private ones outside the external zones'. Names are cached (names.cache, 10m) and never stored; names.resolver picks the DNS server. Also: hc stats top devices listed each device twice; the dashboard's quotas named the rule's ID twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
85 lines
5.5 KiB
Markdown
85 lines
5.5 KiB
Markdown
# Configuration file
|
|
|
|
`/etc/housecarl/housecarl.yaml` says how housecarld runs. The firewall's
|
|
configuration (zones, sets, rules, NAT, settings) isn't here; it is in
|
|
the database, changed with the CLI, the API or the web UI.
|
|
|
|
`housecarld config --example` prints a commented file with the defaults.
|
|
Every setting is optional; unknown settings are an error. housecarld
|
|
reads the file when it starts.
|
|
|
|
| Setting | Default | |
|
|
|---|---|---|
|
|
| `listen` | `["127.0.0.1:8070"]` | addresses of the web UI and API (`host:port`). Keep them on localhost or a management network, and write an input rule that lets you reach them |
|
|
| `tls.cert_file`, `tls.key_file` | none | serve HTTPS with this certificate; housecarld rereads it when the file changes, or on `systemctl reload housecarl` |
|
|
| `tls.acme.*` | off | get the certificate from Let's Encrypt, with Jarl publishing the challenge ([certificates.md](certificates.md#settings)) |
|
|
| `jarl.server`, `jarl.token_file` (or `jarl.token`), `jarl.ca_cert`, `jarl.insecure` | none | the Jarl server for the certificate's challenge, and its token ([jarl.md](jarl.md)) |
|
|
| `ruleset` | `/var/lib/housecarl/ruleset.nft` | the confirmed ruleset, which `housecarl-ruleset.service` loads at boot; its fallback is saved beside it as `ruleset-fallback.nft` ([operations.md](operations.md#if-the-ruleset-fails-to-load-at-boot)). Change both paths in the unit too |
|
|
| `trusted_proxies` | `[]` | addresses or prefixes of reverse proxies whose `X-Forwarded-For` and `X-Forwarded-Proto` are believed |
|
|
| `socket` | `/run/housecarl/housecarl.sock` | the local API socket; `""` turns it off |
|
|
| `database` | `/var/lib/housecarl/housecarl.db` | the SQLite database: configuration, history, users, audit log |
|
|
| `log.level` | `info` | `debug` (every HTTP request), `info`, `warn` or `error` |
|
|
| `log.format` | `text` | `text` or `json` |
|
|
| `session.lifetime` | `12h` | how long a web UI login lasts |
|
|
| `session.idle_timeout` | `2h` | logged out after this long without use |
|
|
| `session.cookie_secure` | `auto` | `auto` (secure over HTTPS), `always` or `never` |
|
|
| `backup.dir` | `/var/backups/housecarl` | where `housecarld backup` writes |
|
|
| `backup.retention` | `30d` | backups older than this are deleted… |
|
|
| `backup.keep_at_least` | `7` | …keeping at least this many |
|
|
| `stats.enabled` | `true` | keep traffic, drops, hits, blocked sources, connections and quotas over time ([stats.md](stats.md)) |
|
|
| `stats.database` | `/var/lib/housecarl/stats.db` | the statistics' own database; deleting it is safe |
|
|
| `stats.retention.minute`, `.hour`, `.day` | `7d`, `90d`, `730d` | how long per-minute, hourly and daily figures are kept |
|
|
| `stats.top_n` | `100` | entries kept per top list, per hour and per day |
|
|
| `shadow.enabled` | `false` | shadow mode: Housecarl's ruleset is loaded beside the firewall you have, but blocks, rejects and translates nothing; its counters, log and tracer show what it would do. No change is on probation, and takeovers and closing connections are refused ([shadow.md](shadow.md)) |
|
|
| `shadow.position` | `after` | where Housecarl's filter chains run in shadow mode: `after` the other firewall's (`filter + 10`: it sees only what that one lets through, so what it would drop is what switching would break) or `before` them (`filter - 10`: it sees every packet) |
|
|
| `names.enabled` | `true` | show inside addresses' names beside them, found by reverse lookups (below) |
|
|
| `names.resolver` | `""` | the DNS server to ask, such as `10.10.0.1:53`; empty: the system's (`/etc/hosts`, then `/etc/resolv.conf`) |
|
|
| `names.cache` | `10m` | how long a name, or the lack of one, is kept |
|
|
|
|
Durations are written `15s`, `12h` or `30d`.
|
|
|
|
Shadow mode is here, and not a firewall setting, so that no user or API
|
|
token can switch enforcement off; restart housecarld to switch.
|
|
|
|
### Names
|
|
|
|
The web UI and `hc` show a name beside each **inside** address in
|
|
connections, the log, quotas and traffic per device: `laptop
|
|
192.168.1.20`. Housecarl finds it with a reverse (PTR) lookup, so the
|
|
names are your reverse zones' (and `/etc/hosts`'). An address counts as
|
|
inside when it is in a network connected to an inside zone's interface,
|
|
or private (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7`)
|
|
and not in an external zone's network. Outside addresses get no name:
|
|
their reverse zones belong to whoever holds the addresses, who would
|
|
choose the names, and looking up every scanner is slow.
|
|
|
|
Names are looked up when a page or `hc` asks, cached (a failed lookup is
|
|
tried again after a minute), and never stored: statistics stay by
|
|
address. With a split DNS (views), the server asked must answer the
|
|
firewall as an inside client; set `names.resolver` if the system's
|
|
resolver doesn't. IPv6 traffic per device is counted per /64, which has
|
|
no name. `hc --no-names` leaves them out.
|
|
|
|
The probation's length is a firewall setting, not here: `hc settings set
|
|
--probation 5m`. So is counting traffic per device for the statistics:
|
|
`hc settings set --stats-per-device on`.
|
|
|
|
## HTTPS
|
|
|
|
Over plain HTTP, passwords and tokens cross the network in the clear;
|
|
housecarld warns when it listens on a non-loopback address without TLS.
|
|
Let it get its own certificate through Jarl ([certificates.md](certificates.md)),
|
|
or give it one:
|
|
|
|
```yaml
|
|
listen: ["192.168.1.1:8070"]
|
|
tls:
|
|
cert_file: /etc/housecarl/tls/fullchain.pem
|
|
key_file: /etc/housecarl/tls/privkey.pem
|
|
```
|
|
|
|
Or keep it on `127.0.0.1` behind a reverse proxy that terminates TLS, and
|
|
list the proxy in `trusted_proxies`. With a certificate, the same port
|
|
answers HTTPS and redirects plain HTTP to it, except from the firewall
|
|
itself.
|