Compare commits

...
Author SHA1 Message Date
beatzaplenty c9458ac8a6 Merge pull request 'docs: add beszel agent setup guide' (#96) from worktree-docs-beszel-guide into main
Check NixOS configurations / eval-hosts (push) Successful in 10m24s
Reviewed-on: #96
2026-07-29 00:41:22 +00:00
beatzaplentyandClaude Sonnet 4.6 99ba0ed52b docs: add beszel agent setup guide
Check NixOS configurations / eval-hosts (pull_request) Successful in 10m37s
Documents how to wire beszel-agent into any flake build: the two-module
split (enable-agent.nix in build types, host-token.nix in host files),
sops secret creation, hub pairing flow, and optional EXTRA_FILESYSTEMS /
Docker monitoring knobs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-29 10:41:03 +10:00
beatzaplenty 1e4072029e update rmote-builder keys
Check NixOS configurations / eval-hosts (push) Successful in 10m38s
2026-07-29 10:39:53 +10:00
beatzaplenty 46649fc7e0 update remote-builder client keys
Check NixOS configurations / eval-hosts (push) Successful in 10m32s
2026-07-29 10:29:40 +10:00
beatzaplenty 4cbcc3beb9 updated .gitignore and change default editor in home.nix
Check NixOS configurations / eval-hosts (push) Failing after 13m5s
2026-07-29 10:17:37 +10:00
beatzaplenty 35f696ccd5 Merge pull request 'feat(ha): add resize-data-disk.sh for online data disk expansion' (#95) from worktree-ha-resize-disk into main
Check NixOS configurations / eval-hosts (push) Successful in 10m27s
Reviewed-on: #95
2026-07-29 00:01:49 +00:00
4 changed files with 203 additions and 7 deletions

No files matched your search

+2
View File
@@ -23,3 +23,5 @@ host-keys/
# Temporary Milestone 1 audit checklist (remove-sensetive-info-refactor.md)
# - working notes only, never committed, deleted once every row is rotated.
secrets-inventory.md
.claude/worktrees/
.claude/settings.local.json
+192
View File
@@ -0,0 +1,192 @@
# Beszel agent
[Beszel](https://github.com/henrygd/beszel) is the monitoring dashboard used
in this LAN. The hub runs as a Docker container on `docker.sweet.home` (port
`vars.ports.beszelHub`, 8090). Each monitored NixOS host runs a
`beszel-agent` that connects back to the hub.
This document explains how to wire beszel-agent into any build in the flake.
---
## How it is split across modules
There are two modules and they have separate jobs:
| Module | What it does | Where it goes |
|---|---|---|
| `modules/beszel/enable-agent.nix` | Enables the systemd service, sets `HUB_URL`, fixes upstream StateDirectory bug | **Build type** (`modules/build-types/*.nix`) |
| `modules/beszel/host-token.nix` | Declares the sops secret + env-file template that holds `TOKEN` | **Host file** (`hosts/<name>/host.nix`) |
`KEY` (the hub's public key for this agent slot) is a plain string set
directly on the host under `services.beszel.agent.environment.KEY` — it comes
from the hub UI, not from sops, so it belongs in the host file rather than a
secret.
---
## Adding beszel to a new build type
Open `modules/build-types/<type>.nix` and add `../beszel/enable-agent.nix` to
the `imports` list:
```nix
imports = [
../beszel/enable-agent.nix
# ... other imports
];
```
That is the only change needed at the build-type level. The module sets:
- `services.beszel.agent.enable = true`
- `HUB_URL` pointing at `docker.sweet.home:8090`
- a persistent `StateDirectory` for the hub-pairing fingerprint
---
## Wiring the host file
Every host whose build type includes `enable-agent.nix` needs two things in
its `hosts/<name>/host.nix`:
### 1 — Import `host-token.nix`
```nix
imports = [
(import ../../modules/beszel/host-token.nix {
name = "<hostname>"; # must match the sops secret file name below
sopsFile = ../../secrets/<hostname>.yaml;
})
];
```
This creates a sops-managed env file at runtime containing `TOKEN=<value>` and
passes it to the agent via `environmentFile`. The `name` argument also becomes
the sops template name (`<name>-beszel.env`), so it must be unique per host.
### 2 — Set `KEY` once the hub has paired the agent
```nix
services.beszel.agent.environment = {
KEY = "ssh-ed25519 AAAA...";
};
```
`KEY` is the hub's SSH public key for this agent slot — copy it from the hub
UI after the agent first connects (see "Pairing with the hub" below).
Until the hub has been paired, leave `KEY` commented out or omit it. The agent
will still start and appear in the hub as an unpaired entry; fill in the key
after that first connection.
---
## Adding the sops secret
The `beszel-token` value in `secrets/<hostname>.yaml` is the token the agent
uses to authenticate to the hub. To add it for a new host:
1. Decrypt and edit the host's secrets file:
```sh
sops secrets/<hostname>.yaml
```
2. Add the token:
```yaml
beszel-token: <token from the beszel hub UI>
```
3. Save and close — sops re-encrypts the file on exit.
If the host does not yet have a `secrets/<hostname>.yaml`, create one using
the same sops recipients as the other secrets files (check `.sops.yaml`), or
run `scripts/secrets/sync-host-keys.sh <target>` first so the host's own
SSH key is already a valid recipient.
The token is found in the beszel hub under **Settings → Keys** or when you
add a new system via the hub UI.
---
## Optional: monitoring extra filesystems
To have the agent report disk usage for a mount point that is not the root
filesystem, add `EXTRA_FILESYSTEMS` in the host file alongside `KEY`:
```nix
services.beszel.agent.environment = {
KEY = "ssh-ed25519 AAAA...";
EXTRA_FILESYSTEMS = "/mnt/data"; # colon-separated if more than one
};
```
The `server` host uses this to expose the ZFS data pool:
```nix
EXTRA_FILESYSTEMS = "${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath}";
```
---
## Optional: monitoring Docker containers
The `enable-agent.nix` module has a commented-out line for Docker monitoring:
```nix
#DOCKER_HOST = "tcp://docker-socket-proxy:2375";
```
Uncomment it if the host runs docker-socket-proxy and you want per-container
stats in the hub. Hosts that do not run Docker should leave this commented out.
---
## Pairing with the hub
1. Deploy the host with `host-token.nix` imported and `enable-agent.nix`
present in the build type. Leave `KEY` unset for now.
2. Open the beszel hub (`http://docker.sweet.home:8090`).
3. Go to **Systems → Add system**. The new host should appear as an
unpaired entry — copy the `KEY` value shown there.
4. In `hosts/<name>/host.nix`, set:
```nix
services.beszel.agent.environment.KEY = "<copied key>";
```
5. Rebuild and deploy the host. The agent will now pair permanently with the
hub.
---
## Example: complete host file
For reference, `hosts/tor-relay/host.nix` is the minimal case — one
filesystem, no Docker, LXC platform:
```nix
{ vars, ... }:
{
imports = [
(import ../../modules/beszel/host-token.nix {
name = "tor-relay";
sopsFile = ../../secrets/tor-relay.yaml;
})
];
networking = { ... };
services.beszel.agent.environment = {
KEY = "ssh-ed25519 AAAA...";
};
system.stateVersion = "26.05";
}
```
`hosts/server/host.nix` is the fuller case — extra filesystem path, debug
logging:
```nix
services.beszel.agent.environment = {
KEY = "ssh-ed25519 AAAA...";
EXTRA_FILESYSTEMS = "${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath}";
LOG_LEVEL = "debug";
};
```
+1 -1
View File
@@ -26,7 +26,7 @@
# Optional: set environment vars
sessionVariables = {
EDITOR = "vim";
EDITOR = "nano";
SOPS_AGE_KEY_FILE = "${config.home.homeDirectory}/.config/sops/age/keys.txt";
};
+8 -6
View File
@@ -44,13 +44,15 @@
# host (modules/nix-cache/server.nix) — one per client host that's allowed
# to use it as a distributed builder.
remoteBuilderAuthorizedKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFDEA1S2ikpObREgbP5uVBWMxIOGbY8B+Wx7VTZK1m6t root@server"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPAYIT9ormlmxZ0SziyDQaUntnKI8HK9/s3Qac1ZKjP2 root@docker"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKKKzoEPl/ZW9KBRHBcp6/ThOngGpwMv5EhkTlgC4aDf root@nixos"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIGtOWOCS+ImHc7NehguoyD7PbonGosKMZqc9+QR3v/h root@nixos"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxXTQxFnArK5HXG7czeoybZebCGfxpUdusJkPn+BCSp root@server"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK+ioWPhHixlgCB9KIQ0QTHTz6A+Oo2F3uKiINLip5rO root@docker"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICMJhrfFayLBG+gWtO6oAvgambw5nWWgztiTFEaaaVRH debian@surface"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJEj26SL/emsVjW2YhRucJVp2kTz8WgcEQgjBEBLRikk root@claude"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII/rLceRhnDobVXQYiPceuhDHHvVjFQ1pc9A6un/eUlA root@server"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHj11bLPpRzH2oslnwFzEvY9cSgfEFtSZbLQaDm4nZMK root@pxe-boot"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4/Sesm8NYpj73R0cbGhI0Ubvz73vIVWAnbEDTlBTdh root@tor-relay"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIBCFUUtePndW7pqtlawft1QCdHmBVs3O/c8EJO+RcXV root@tailscale-router"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBZ9WKKAlP9Z7GQdgaZ1Xgw9C+vja2lqEZO5rJFpVqYN root@ha-server-1"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEGNKlaaMckd8nLWNGz4B2QokXjnnIvM+rEUv+R6h0sp root@ha-server-2"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK+XeMco7OxUpjrjZm54HogMs9QB5xlcKmElASRvrmlW root@nixos"
];
# Admin SSH public key, authorized on the primary user of every host and