Skip to content

Releases: heyvaldemar/beszel-traefik-letsencrypt-docker-compose

v1.0.3

Choose a tag to compare

@heyvaldemar heyvaldemar released this 23 Sep 19:13

Fixed

  • CI had never run the restore script. The test restored with its own
    copy of the commands. The script read DATA_PATH and DATA_BACKUPS_PATH
    from the shell that ran it rather than from .env or the stack, so a path
    set in .env was not the one it listed or cleared, and it cleared with
    rm -rf dir/*, which leaves every dotfile of the newer state in place. It
    now takes every path and name from the running backups container, accepts
    the backup file name as an argument, starts the application again whatever
    happens, and CI runs it: a file written before a backup and deleted after it
    must be back once that backup is restored.

Changed

  • The freshness check has its own workflow, Pin Freshness. It ran inside Deployment Verification, whose badge is the one at the top of this README. Across the fleet, nine red runs in ten were a pin one version behind - which the fleet's triage moves within the day - and a reader cannot tell that from a stack that does not boot. The badge now says whether the stack boots. The job itself is unchanged.

v1.0.2

Choose a tag to compare

@heyvaldemar heyvaldemar released this 21 Sep 18:27

Security

  • traefik:3.7 was rebuilt upstream; the pin moved from sha256:1c32e7c36820… to sha256:24841fe2de73…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.

Upgrading

git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.

Full history in CHANGELOG.md.

v1.0.1

Choose a tag to compare

@heyvaldemar heyvaldemar released this 20 Sep 16:40

Changed

  • henrygd/beszel:0.19.0 moved to henrygd/beszel:0.20.0. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.
  • henrygd/beszel-agent:0.19.0-alpine moved to henrygd/beszel-agent:0.20.0-alpine. The freshness check reported the lag; the deploy job booted the stack on the new image before this landed.

Security

  • traefik:3.7 was rebuilt upstream; the pin moved from sha256:f86a2cab1b5c… to sha256:1c32e7c36820…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.
  • alpine:3.22 was rebuilt upstream; the pin moved from sha256:14358309a308… to sha256:5291449c3df7…. Same version, same tag, a rebuilt base image — the usual shape of a security fix in a base layer.

Upgrading

git pull (or ./update.sh), then docker compose up -d. Containers on a refreshed image are recreated; data volumes and .env are untouched. This release was cut by fleet triage after the deploy job booted the stack on the refreshed images.

Full history in CHANGELOG.md.

What upstream changed

Read by fleet triage from the upstream release notes (or the commits between the tags) against this compose file, before the bump was applied.

Upstream changes 0.19.0 -> 0.20.0

Verdict: NEEDS ATTENTION — the upstream release notes could not be retrieved, so this upgrade cannot be verified against them; also note the companion beszel hub image is pinned separately at 0.19.0 and must move in lockstep with the agent.

Breaking changes

  • Unknown. The release notes for henrygd/beszel-agent 0.20.0 were not available (404), so no breaking changes can be confirmed or ruled out.

Variables

  • none confirmed from notes (notes unavailable). No variable renames can be verified either way.

Data and dependencies

  • The compose file pins henrygd/beszel-agent and henrygd/beszel (the hub) as two separate version defaults (BESZEL_AGENT_IMAGE_VERSION:-0.19.0-alpine, BESZEL_IMAGE_VERSION:-0.19.0). Beszel's agent and hub are a matched pair (protocol/handshake between them); bumping only the agent to 0.20.0 while leaving the hub pinned at 0.19.0 is exactly the mismatch this review flags — the hub's own notes are what would confirm agent/hub compatibility, and they were not read here either.
  • No database engine is involved (SQLite via PocketBase, embedded — not a separately pinned companion service), so the "companion service unpinned" trigger does not apply on that axis. It does apply to the hub/agent version pairing above.

Before applying

  • Fetch the actual release notes (and the hub's release notes for 0.20.0, if the hub is also being bumped) before changing BESZEL_AGENT_IMAGE_VERSION. Check https://github.com/henrygd/beszel/releases (the agent ships from the main beszel repo's release tags, not a separate beszel-agent repo — the 404 suggests the wrong repo/tag was queried) for the 0.20.0 entry and any UPGRADING/BREAKING_CHANGES notes.
  • If bumping the agent, bump the hub to a compatible version in the same change, and read that hub's release notes too — the pair should move together.
  • Take a backup of beszel-data (the backups service already does this on a schedule; confirm a recent successful archive exists) before applying, since the hub holds an embedded SQLite database.
  • After applying, verify the agent reconnects to the hub (check hub UI system status) rather than trusting a clean container start alone.

Notes read

  • None. GitHub releases for henrygd/beszel-agent returned HTTP 404 Not Found. No UPGRADING, BREAKING_CHANGES, or CHANGELOG section was supplied for this range. Check by hand: the correct upstream repo/tag for agent 0.20.0 release notes, and the hub's own release notes for the same range.

Upstream changes 0.19.0 -> 0.20.0

Verdict: NEEDS ATTENTION — the hub image pin (henrygd/beszel:0.19.0) is being bumped to 0.20.0, but the compose file's agent pin is already at 0.20.0-alpine while .env.example still documents BESZEL_AGENT_IMAGE_VERSION=0.19.0-alpine; confirm which is actually deployed and align hub/agent versions before applying.

Breaking changes

  • none found in the notes. No entry in the changelog is marked as breaking, and no removed feature or config format change is mentioned.

Variables

  • New optional variable introduced upstream: TRUSTED_PROXY_IPS, from "Add TRUSTED_PROXY_IPS allowlist for TRUSTED_AUTH_HEADER" (#2327). Not present in this template's .env.example or compose file. Only relevant if you use TRUSTED_AUTH_HEADER-based auth (not referenced anywhere in this template); if you do, add it, otherwise no action needed.
  • No renamed or removed variables found in the notes.

Data and dependencies

  • none found in the notes — no database version requirement, no migration, no changed port or path is mentioned for the hub (PocketBase/SQLite is unaffected per the changelog).
  • Compose/.env.example mismatch worth flagging on its own: the compose file's x-images block pins agent: ... 0.20.0-alpine, i.e. the agent has already been bumped ahead of the hub in this file, while .env.example still lists BESZEL_AGENT_IMAGE_VERSION=0.19.0-alpine as the override example. This is an inconsistency in the template itself, not something from the release notes — verify both hub and agent are intentionally going to 0.20.0 together, since the note "Fix agent disconnects during slow collections by extending WebSocket deadline" (#2294) and other agent-side fixes only apply once the agent is actually upgraded.

Before applying

  • Update BESZEL_AGENT_IMAGE_VERSION documentation/default in .env.example to 0.20.0-alpine to match the compose file, or explicitly confirm the agent is meant to already be at 0.20.0-alpine ahead of this hub bump.
  • No database backup is strictly required by anything in the notes, but the template's own backup service is already in place — a normal pre-upgrade backup of beszel-data is good practice regardless.
  • No manual migration command is called for in the notes.
  • After upgrade, verify agents reconnect cleanly (given the WebSocket deadline fix) and that alert rules/view preferences persist as expected (given "Add persistence of view preferences and language to user settings").

Notes read

  • v0.20.0 release notes (henrygd/beszel, 2026-09-19), covering the 0.19.0...0.20.0 range in full.
  • No UPGRADING, BREAKING_CHANGES, or CHANGELOG document was supplied beyond the release notes above; none to reconcile against.

v1.0.0

Choose a tag to compare

@heyvaldemar heyvaldemar released this 11 Sep 01:11

First release. A production deployment of Beszel behind Traefik with automatic Let's Encrypt TLS, built to the fleet standard.

Beszel answers one question: is the host healthy? CPU, memory, disk usage and I/O, network, temperature, S.M.A.R.T. disk health, per-container statistics, with weeks of history and threshold alerts.

CI asserts that the expected crash-loop is the expected one

The agent's key and token are issued by the hub, so they cannot exist before the hub has run once. A fresh deployment therefore starts an agent that restarts every few seconds saying no key provided, and the README tells you to ignore it until you have finished registration.

That instruction is exactly the problem. An unchecked claim about an expected failure is how a genuinely broken agent goes unnoticed for a week: a restarting container is precisely what the reader has just been told not to worry about. So the deploy job asserts that no key provided is the message, and any other reason fails the build.

The rest of the registration path is checked as far as it honestly can be — an account created from the CLI signs in to the API, and /api/beszel/getkey hands back the ssh key that goes in BESZEL_AGENT_KEY. The per-system token is minted by the interface when you add a system and cannot be fabricated from outside, so the README sends you there for it rather than pretending otherwise.

The agent must be the -alpine image, and CI proves it

The default agent image is built FROM scratch: no shell, no smartctl, and therefore no S.M.A.R.T. at all. It runs perfectly happily and silently monitors nothing about disk health — the failure where everything is green and the question is simply not being asked.

CI checks both halves: that the pinned reference carries -alpine, and that smartctl is actually in the image.

Devices are override files

A device node belongs to your host. Naming /dev/nvme0 in the base compose file means the stack refuses to start anywhere that node does not exist — not on a VPS, not on the CI runner that proves this template works.

disk-smart.override.yml adds exactly two capabilities — SYS_RAWIO for SATA passthrough, SYS_ADMIN for NVMe — rather than privileged: true, which grants every capability on the host. It also spells out what people get wrong: pass the controller, not the block device or a partition, and address USB disks by /dev/disk/by-id because USB enumeration reshuffles sd? letters between boots.

extra-filesystems.override.yml carries the trap worth knowing before you use it. Beszel charts a filesystem by watching a marker directory on it — and if that directory does not exist when the container starts, Docker creates it, as root, on whatever the path resolves to. For an unmounted disk that is your root filesystem, and you get a chart that looks entirely plausible while measuring / a second time. Create the markers first and an unmounted disk gives you an empty graph, which is a question rather than a quiet lie.

Neither the hub nor the agent holds the Docker socket

A proxy does, with POST denied — published on 127.0.0.1 rather than reached by service name, because a host-networked container has no Docker DNS to resolve one with. CI asserts the proxy's answers (200 to a GET, 403 to a POST) and both containers' mount lists.

Two things that are forced rather than chosen

The hub reaches the agent over a unix socket in a shared volume, which is why Host in the Add System dialog is /beszel_socket/beszel.sock and not an address: the agent runs with host networking and the hub does not, so neither can see the other's loopback and no Docker DNS name resolves for both.

Host networking on the agent is required. Without it the agent measures the container's network interface rather than the machine's, and reports a busy server as idle — a number that is wrong rather than missing, which is worse.

Also included

Five images pinned by tag@sha256:<digest>, a backup loop that reads its own archive back before naming it a backup, an end-to-end suite requiring data.db in the archive by name, a restore script, update.sh, resource limits and reservations, and OpenSSF Scorecard.

The archive holds the systems, the alert rules, the users and the history. The history rides along and nobody restores a CPU graph from March; the alert rules are the part that is genuinely irreplaceable, and they are the reason the loop exists.

Full documentation: README · CHANGELOG