### [Beszel](https://github.com/henrygd/beszel)

> Handle: `beszel`<br/>
> URL: [http://localhost:34841](http://localhost:34841)

![Beszel dashboard with the local Harbor host monitored — live CPU, memory, disk, load, and temperature](./harbor-beszel.png)

Beszel is a lightweight server monitoring platform with historical data, Docker container stats, and alerts. It is built on PocketBase and ships as two components:

- **Hub** (`beszel`) — the web dashboard and PocketBase backend that stores systems, alerts, and historical metrics.
- **Agent** (`beszel-agent`) — a per-host collector that gathers CPU, memory, disk, network, container, temperature, GPU, and S.M.A.R.T. metrics and pushes them to the hub.

Harbor pre-provisions the hub so that the local Docker host appears in the dashboard automatically — no admin signup, no Add-System click, no key paste.

#### Starting

```bash
harbor pull beszel
harbor up beszel --open
```

The browser opens the hub already signed in (via beszel's [`AUTO_LOGIN`](https://beszel.dev/guide/environment-variables)) and `harbor-host` shows up in the dashboard within a few seconds.

##### How the auto-provisioning works

Three pieces, each documented upstream:

1. **Hub user creation** — the hub container is started with `USER_EMAIL=${HARBOR_BESZEL_USER_EMAIL}` and `USER_PASSWORD=${HARBOR_BESZEL_USER_PASSWORD}`. On first boot beszel's initial-settings migration creates that admin user. `AUTO_LOGIN=${HARBOR_BESZEL_USER_EMAIL}` then signs visitors in automatically.
2. **Universal token row** — once the hub is healthy, the `beszel-agent-register` sidecar (`services/beszel/agent-register.sh`) extracts the hub's freshly generated SSH public key into `services/beszel/agent/key.pub` and inserts a row into the `universal_tokens` PocketBase collection. The token is persisted to `services/beszel/agent/token`.
3. **Agent self-registration** — the agent reads `KEY_FILE`, `TOKEN_FILE`, `HUB_URL`, and `SYSTEM_NAME` and dials the hub's WebSocket endpoint with the token. The hub looks up the row, creates the matching system, and accepts the agent's metric stream. See beszel's [Agent Installation guide](https://beszel.dev/guide/agent-installation) for the protocol.

The sidecar is idempotent — the `universal_tokens` collection has a `UNIQUE(user)` constraint, so it reuses any existing row instead of inserting a duplicate. Wiping `services/beszel/agent/` is safe: the sidecar restores the token from the DB on the next `harbor up`.

`HARBOR_BESZEL_USER_PASSWORD` is generated on first run by `harbor.sh` and persisted in `.env`. Read it back with:

```bash
harbor config get beszel.user.password
```

#### Configuration

##### Environment Variables

Set via [`harbor config`](./3.-Harbor-CLI-Reference.md#harbor-config):

```bash
# Hub web port (PocketBase + dashboard)
HARBOR_BESZEL_HOST_PORT          34841

# Hub image and version
HARBOR_BESZEL_IMAGE              henrygd/beszel
HARBOR_BESZEL_VERSION            latest

# Hub data directory (PocketBase database, history, settings)
HARBOR_BESZEL_WORKSPACE          ./services/beszel

# Agent (per-host collector) image and version
HARBOR_BESZEL_AGENT_IMAGE        henrygd/beszel-agent
HARBOR_BESZEL_AGENT_VERSION      latest

# Internal port the agent listens on inside the harbor network
HARBOR_BESZEL_AGENT_PORT         45876

# Hub URL the agent dials for self-registration
HARBOR_BESZEL_AGENT_HUB_URL      http://beszel:8090

# System name shown in the hub for the local Harbor host
HARBOR_BESZEL_SYSTEM_NAME        harbor-host

# Pre-provisioned admin credentials (USER_EMAIL/USER_PASSWORD on the hub).
# Password auto-generated on first run; read with `harbor config get beszel.user.password`.
HARBOR_BESZEL_USER_EMAIL         admin@harbor.local
HARBOR_BESZEL_USER_PASSWORD      (auto-generated)
```

##### Volumes

The hub persists state in `services/beszel/data/` (mounted to `/beszel_data` inside the container). This includes the PocketBase SQLite database, the hub's SSH key pair, uploaded assets, and historical metric snapshots.

The agent's `KEY_FILE` and `TOKEN_FILE` live in `services/beszel/agent/` (mounted read-only into the agent at `/agent_data/`). Both are written by the `beszel-agent-register` sidecar after the hub finishes its first boot.

The hub and the register sidecar run as the host user (`HARBOR_USER_ID:HARBOR_GROUP_ID`), so files under `services/beszel/data/` and `services/beszel/agent/` are owned by the host user and can be inspected, backed up, or removed without `sudo`.

The agent also mounts `/var/run/docker.sock:/var/run/docker.sock:ro` to read container stats. This is read-only — the agent cannot start, stop, or otherwise modify containers. If you do not want the agent to access the Docker socket at all, comment out the volume in `services/compose.beszel.yml`; container metrics will then be unavailable but host metrics still work.

#### Monitoring Additional Hosts

The bundled `beszel-agent` only monitors the host running Harbor. To monitor other machines, follow the upstream agent install guide:

- [Beszel agent install (binary)](https://beszel.dev/guide/agent-installation)
- [Beszel agent (Docker)](https://github.com/henrygd/beszel#docker-agent)

Use the same universal token that's stored at `services/beszel/agent/token`, or create a fresh one in the hub at **Settings → Tokens**. The remote agent needs network reach to the hub on `${HARBOR_BESZEL_HOST_PORT}` (default 34841).

#### Troubleshooting

```bash
harbor logs beszel
harbor logs beszel-agent
harbor logs beszel-agent-register
```

(All of `harbor logs` tail by default — Ctrl-C to break out.)

Common issues:

- **`harbor-host` is missing or shows offline** — check `harbor logs beszel-agent-register` for the universal_tokens insert, and `harbor logs beszel-agent` for `WebSocket connected host=beszel:8090`. If the agent reconnects but the system never appears, the hub may have a stale system row pointing at a different token; delete it from the dashboard and the agent will re-register on next reconnect.
- **Forgot the admin password** — `harbor config get beszel.user.password` shows the value harbor.sh generated. To rotate, set a new value with `harbor config set beszel.user.password <new>` and remove `services/beszel/data/data.db` so beszel re-runs the user-creation migration on next start (this destroys metric history).
- **Container stats missing** — the docker.sock mount is required. Verify with `docker inspect harbor.beszel-agent | grep docker.sock`.

#### Links

- [Beszel website](https://beszel.dev)
- [GitHub Repository](https://github.com/henrygd/beszel)
- [Agent installation guide](https://beszel.dev/guide/agent-installation)
- [Environment variables](https://beszel.dev/guide/environment-variables)
