Beszel: Lightweight Server Monitoring for Your Homelab with Docker Compose

Beszel is an MIT-licensed hub-and-agent monitoring tool that shows CPU, RAM, disks, Docker containers, S.M.A.R.T. and more for all your servers. Here is how to run version 0.21 with Docker Compose.

Share
Beszel dashboard listing several monitored systems with CPU, memory, disk and network usage
Screenshot: beszel.dev (MIT)

Once your homelab grows past one box, a simple question becomes surprisingly hard to answer: how are my servers actually doing? Is the NAS running hot? Which container is eating all the RAM? Is that old SSD about to die? You can build a Prometheus + Grafana stack for this, but for most homelabs that is a lot of moving parts. Beszel takes the opposite approach: one small hub, one tiny agent per machine, and a clean dashboard that works out of the box.

In this guide we look at what Beszel does, what is new in the current v0.21 release line, and how to run it with Docker Compose.

What is Beszel?

Beszel describes itself as a lightweight server monitoring platform that includes Docker statistics, historical data, and alert functions. It is written in Go, released under the MIT license and has passed 26,000 stars on GitHub. The latest release at the time of writing is v0.21.1 (22 October 2026).

Beszel dashboard table with several systems and their resource usage
The Beszel dashboard gives you one row per system with live CPU, memory, disk and network usage. Source: beszel.dev (MIT)

Hub and agent: how Beszel works

Beszel has exactly two components:

  • The hub is the web application. It is built on PocketBase, stores the history, sends alerts and serves the dashboard.
  • The agent runs on every system you want to monitor. It collects metrics and hands them to the hub.

Agents can connect to the hub over a WebSocket (using HUB_URL and a token), or the hub can connect to the agent over SSH on the agent's listen port (45876 by default). Each agent is tied to the hub's public key, so a random client cannot simply pull your stats. The agent is available as a Docker image, a single binary with a Linux install script, Homebrew, WinGet/Scoop and even a Home Assistant add-on.

What Beszel monitors

The list of supported metrics has grown a lot over the last releases:

  • CPU, memory, disk usage and disk I/O for the host, including swap and ZFS ARC
  • Docker and Podman containers: CPU, memory and network history per container, plus container status
  • Network usage, load average, temperatures and (on Linux) fan speeds
  • GPU usage and power draw for NVIDIA, AMD and Intel
  • S.M.A.R.T. disk health, including eMMC wear and Linux mdraid array health
  • ZFS pools and datasets: capacity, health, I/O and scrub status
  • Network monitors (ICMP, TCP, HTTP and DNS) probed directly from the agents
  • Battery charge for laptops and some peripherals
Beszel system detail page with charts for CPU, memory, disk, network, temperature and Docker containers
The system page shows the history for a single machine, from CPU and memory to disk I/O, temperatures and per-container usage. Source: beszel.dev (MIT)

On top of that you get multi-user support (users manage their own systems, admins can share systems), OAuth/OIDC login with the option to disable password login, and automatic backups to disk or S3-compatible storage.

What's new in v0.19 to v0.21

Beszel ships fast. The releases since September 2026 added a lot of homelab-friendly features:

  • v0.19.0 (September): ZFS pool and dataset monitoring, container health alerts with log excerpts, alerts for failed systemd services and for CPU I/O wait. Important: agents now verify HTTPS certificates. If your hub uses a self-signed certificate, set CA_CERT_FILE on the agent or the connection will be rejected.
  • v0.20.0 (September): network monitoring from agents, an "image update available" flag for containers and btrfs reporting.
  • v0.21.0 (October): a list of pending package updates on the system page, Wi-Fi signal strength, TLS certificate expiry checks for HTTPS monitors, systemd service logs and a DISABLE_SSH option for the hub.
  • v0.21.1 (October): mainly API changes. Memory values are now also reported as raw bytes, and the old GB fields are deprecated. Only relevant if you build integrations on the API.

Installing Beszel with Docker Compose

The official docs provide a Compose file that runs the hub and a local agent on the same machine. The two talk over a shared unix socket, which avoids network headaches between containers.

1. Create a folder and the Compose file

mkdir -p /opt/beszel && cd /opt/beszel
nano docker-compose.yml
services:
  beszel:
    image: henrygd/beszel:0.21.1
    container_name: beszel
    restart: unless-stopped
    environment:
      APP_URL: https://beszel.example.com
    ports:
      - 8090:8090
    volumes:
      - ./beszel_data:/beszel_data
      - ./beszel_socket:/beszel_socket

  beszel-agent:
    image: henrygd/beszel-agent:0.21.1
    container_name: beszel-agent
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./beszel_agent_data:/var/lib/beszel-agent
      - ./beszel_socket:/beszel_socket
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      LISTEN: /beszel_socket/beszel.sock
      HUB_URL: http://localhost:8090
      TOKEN: <token>
      KEY: "<key>"

The upstream example uses the latest tag. Pinning a version, as above, makes updates a deliberate step. Set APP_URL to the address you will use for the hub, because Beszel uses it for notification links and for the agent config it generates.

2. Start the hub and create your account

docker compose up -d beszel

Open port 8090 (or your domain) and create the first user. That account becomes the admin.

3. Add the local system

Click Add System. Use the socket path /beszel_socket/beszel.sock as Host/IP, copy the shown public key and token into the KEY and TOKEN variables of the agent, then start everything:

docker compose up -d

After a few seconds the new system should turn green in the table.

Why does the agent use host networking?

The agent runs with network_mode: host so it can read the host's real network interface statistics. If you do not care about host network stats, you can drop that line and map the port instead. Also note that rootless Docker or Podman cannot see most host-level data, so temperatures, GPU, S.M.A.R.T. and systemd monitoring may be missing in that setup.

Adding more servers

For every additional machine, click Add System in the hub and copy the ready-made docker-compose.yml or the binary install command from the dialog. A minimal remote agent looks like this:

services:
  beszel-agent:
    image: henrygd/beszel-agent:0.21.1
    container_name: beszel-agent
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./beszel_agent_data:/var/lib/beszel-agent
      - /var/run/docker.sock:/var/run/docker.sock:ro
      # extra disks: mount a folder into /extra-filesystems
      # - /mnt/disk1/.beszel:/extra-filesystems/disk1:ro
    environment:
      LISTEN: 45876
      KEY: "<public key>"
      HUB_URL: "https://beszel.example.com"
      TOKEN: "<token>"

If you have many machines, create a universal token under /settings/tokens. Agents started with that token register themselves with the hub, so you do not have to add each system by hand first.

Running the hub behind Traefik

If you already use Traefik (like in our Homepage dashboard guide), replace the ports: section of the hub with labels. The docs point out that the proxy must pass WebSocket connections, otherwise agents using a universal token cannot connect.

  beszel:
    image: henrygd/beszel:0.21.1
    container_name: beszel
    restart: unless-stopped
    environment:
      APP_URL: https://beszel.example.com
    volumes:
      - ./beszel_data:/beszel_data
      - ./beszel_socket:/beszel_socket
    networks:
      - traefik
    labels:
      - traefik.enable=true
      - traefik.http.routers.beszel.rule=Host(`beszel.example.com`)
      - traefik.http.routers.beszel.entrypoints=websecure
      - traefik.http.routers.beszel.tls.certresolver=letsencrypt
      - traefik.http.services.beszel.loadbalancer.server.port=8090

Traefik handles WebSockets without extra configuration. With Nginx you need the usual Upgrade and Connection headers and a longer proxy_read_timeout; the docs have full Caddy and Nginx examples.

Alerts: plug in ntfy or Gotify

Alerts are configured per system in the table, and the notification targets live under Settings > Notifications. Beszel uses Shoutrrr URLs, so you can send alerts to Discord, Telegram, Slack, Matrix, email and many more. If you followed our guides on ntfy or Gotify, you are one line away from push alerts on your phone:

ntfy://:accesstoken@ntfy.example.com/homelab-alerts
gotify://gotify.example.com/AppToken
Beszel notification settings page with webhook and push URLs
Notification settings in Beszel: add one or more Shoutrrr URLs and send a test notification. Source: beszel.dev (MIT)

Useful alerts to start with: system down, disk usage above 85 %, high temperature and the S.M.A.R.T. failure alert.

Tips from practice

  • Back up beszel_data. It contains the PocketBase database with users, systems and history. Beszel can also create backups to disk or S3 on its own.
  • Monitor extra disks by mounting a folder from each disk into /extra-filesystems in the agent container.
  • Show it on your dashboard. Homepage has a Beszel widget (type: beszel, version: 2) with an overview of all systems or details for one.
  • Pair it with uptime checks. Beszel tells you how a machine is doing; Healthchecks tells you when a cron job or backup silently stopped. Patch status is a different job again, which is where PatchMon comes in, although Beszel 0.21 now lists pending package updates too.

Beszel vs Uptime Kuma vs Netdata

Beszel Uptime Kuma Netdata
Main job Resource monitoring of your servers and containers Availability checks of services and websites Very detailed real-time metrics
Needs agent Yes, tiny agent per host No Yes, per host
History Yes Yes (uptime/response time) Yes
Status pages No Yes No
Resource use Very low Low Higher, very detailed
License MIT MIT GPL-3.0 (agent)

In short: Beszel and Uptime Kuma complement each other. Kuma checks whether a service answers; Beszel shows why a server is struggling. Netdata goes much deeper on metrics but is also heavier. If you want a simple "how are all my boxes doing" view, Beszel is hard to beat.

Conclusion

Beszel hits a sweet spot for homelabs: it installs in minutes, uses almost no resources and still covers containers, disks, GPUs, ZFS and alerts. The rapid release pace means new features arrive every few weeks. Just keep an eye on the release notes before updating, as v0.19 showed with its stricter certificate checks.

Sources