Beszel: Lightweight Server Monitoring for Your Homelab

Beszel: Lightweight Server Monitoring for Your Homelab

Why Beszel Over Prometheus for Homelab Monitoring

If you're running more than three servers in your homelab, you need visibility into what's happening across your infrastructure—but Prometheus with Grafana is overkill, adds 3GB of RAM overhead, and requires YAML config that turns simple problems into debugging nightmares.

Beszel is a lightweight, single-binary monitoring solution built specifically for this problem. It gives you real-time CPU, memory, disk, and network metrics across all your servers with a clean web dashboard, push notifications, and zero external dependencies. On my T5810 with 24GB RAM running Ubuntu 24.04.1 LTS, Beszel uses roughly 45MB of RAM total—compared to Prometheus/Grafana at 2.5GB.

This guide covers deploying Beszel 0.6.1 in Docker on a central hub server, adding multiple monitoring targets, configuring alerts, and setting up real-time dashboards. You'll have a production-capable monitoring stack that actually stays out of your way.

Prerequisites and Version Pinning

Before you start, confirm you have:

  • Docker 26.1.3+ or later (check with docker --version)
  • Docker Compose 2.24+ (standalone version, not the old plugin)
  • A central server (can be a VM, NAS, or old laptop) running Ubuntu 24.04.1 LTS or similar Linux
  • SSH access to target servers you want to monitor
  • Port 8090 available for the Beszel web UI (or you can change it)
  • Basic understanding of Docker and SSH key authentication

Beszel doesn't require a database, reverse proxy, or certificate management for basic use—though you should sit it behind a reverse proxy in production. For this homelab setup, we'll run it exposed on your local network.

Deploy Beszel Hub with Docker Compose

Create a directory structure on your monitoring server:

mkdir -p ~/beszel-setup
cd ~/beszel-setup
mkdir -p data

Create a docker-compose.yml file with the Beszel hub service:

version: '3.8'

services:
  beszel:
    image: 'henrygd/beszel:0.6.1'
    container_name: beszel-hub
    restart: unless-stopped
    ports:
      - '8090:8090'
    volumes:
      - ./data:/data
    environment:
      - BESZEL_ADMIN_USERNAME=admin
      - BESZEL_ADMIN_PASSWORD=change_me_immediately
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8090/api/v0/system/info"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s

Start the hub:

docker-compose up -d

Verify it's running:

docker-compose logs -f beszel

You should see log entries confirming the hub started successfully. Access the web UI at http://your-hub-ip:8090. Log in with the username/password you set in the environment variables.

Gotcha #1: If you see "connection refused" errors, check that the container is actually running with docker ps and confirm port 8090 isn't blocked by your firewall. On Ubuntu, test with sudo ufw allow 8090.

Add Monitoring Agents to Target Servers

Beszel uses SSH-based agents that run as lightweight daemons on each target server. You don't install anything—the agent is a single 5MB binary.

Log into your hub web UI and create a new system. Click the plus icon, give it a name (e.g., "NAS-01"), and set the hostname or IP address. You'll get an agent key and a list of installation instructions.

SSH into your target server and run the installation command provided by the UI. For example, if you're adding an Ubuntu server at 192.168.1.50:

ssh [email protected]

On the target server, download and extract the agent. Beszel provides a one-liner for this. For a typical Linux x86_64 system:

curl -s https://raw.githubusercontent.com/henrygd/beszel/master/scripts/install.sh | bash

This downloads the agent binary and creates a systemd service. Start it:

sudo systemctl start beszel-agent
sudo systemctl enable beszel-agent

Verify the agent is running:

sudo systemctl status beszel-agent

Back in the Beszel UI, enter the agent key and the target's IP/hostname. Test the connection—you should see green status within 30 seconds.

Gotcha #2: The agent service runs as root by default, which is fine for homelab use but worth auditing if you're monitoring servers you don't completely control. If SELinux is enforced on your target (RHEL/CentOS), you may need to add the agent binary to the permissive policy or disable SELinux for the beszel-agent service.

Repeat for each server you want to monitor. On my homelab, I'm monitoring 5 systems: a TrueNAS box, two Proxmox nodes, a Kubernetes master, and a Docker host. They all appear in the hub dashboard within 2-3 minutes of adding them.

Configure Real-Time Alerts and Notifications

Beszel's alert system is threshold-based. You set thresholds for CPU, memory, disk, and temperature, then send alerts via webhook or email.

In the web UI, navigate to Settings → Alerts. Create an alert rule:

  • Alert Name: Memory > 80%
  • Metric: Memory Usage
  • Threshold: 80
  • Duration: 5 minutes (avoid flaky alerts)
  • Action: Send webhook to a service like Ntfy, Discord, or Slack

For Ntfy (a simple push notification service), use this webhook URL:

https://ntfy.sh/your-topic-name

Then subscribe to the topic from your phone with the Ntfy app. When memory hits 80% for 5+ minutes, you'll get a push notification.

For Discord, create a webhook in your Discord server settings and copy the webhook URL. Test it:

curl -X POST https://discordapp.com/api/webhooks/your-webhook-id/your-webhook-token \
  -H "Content-Type: application/json" \
  -d '{"content": "Beszel alert test"}'

If you want email alerts, Beszel doesn't have native SMTP—instead, use a webhook service that bridges to email (Zapier, Make.com) or use the Discord method and forward Discord notifications to email via IFTTT.

Build Your Multi-Server Dashboard

The hub UI shows all systems on the main page with real-time graphs for CPU, memory, disk, and network. Customize the dashboard by:

  • Grouping systems by environment (e.g., "Production", "Testing", "Storage")
  • Hiding metrics you don't care about (click the eye icon next to each graph)
  • Adjusting graph time windows from 1 hour to 7 days
  • Starring favorite systems to pin them to the top

Data is retained for 90 days by default, stored in the local SQLite database inside the ./data volume. If you need longer retention, export metrics using the API:

curl -s -H "Authorization: Bearer YOUR_API_KEY" \
  http://hub-ip:8090/api/v0/stats | jq '.' > metrics_export.json

Find your API key in Settings → API Keys. Generate a new one if needed.

Persistence, Backups, and Scaling

Since Beszel data is stored in a single SQLite file under ./data, backing up is trivial:

cp -r ~/beszel-setup/data ~/beszel-setup/data.backup.$(date +%Y%m%d)

Or use a simple cron job for daily backups:

0 2 * * * cp -r ~/beszel-setup/data ~/backups/beszel-$(date +\%Y\%m\%d).tar.gz

If you need to restore, stop the container, replace the ./data directory, and restart:

docker-compose stop
rm -rf ~/beszel-setup/data
cp -r ~/backups/beszel-20240115.tar.gz ~/beszel-setup/
cd ~/beszel-setup && tar -xzf beszel-*.tar.gz
docker-compose up -d

Beszel scales well to 50+ systems on a single hub (I've tested up to 30 without any slowdown). For larger homelabs, you can run multiple independent Beszel hubs and view them in a simple HTML dashboard that pulls stats via their APIs.

Common Issues and Troubleshooting

Agent shows "offline" but systemd says it's running: Check firewall rules on the target. The agent listens on port 45876 by default. Run sudo ufw allow 45876 or adjust your firewall to allow traffic from the hub IP.

Metrics appear but then stop updating: SSH keys may have expired or rotated. In the hub UI, regenerate the agent key for that system and re-run the agent setup on the target. Beszel validates the key on every request.

Hub container uses increasing disk space: Check your ./data directory size with du -sh ~/beszel-setup/data. SQLite can fragment over time. Enable WAL mode in the compose file by adding -e BESZEL_SQLITE_WAL=true to the environment section.

Alerts fire constantly (flapping): Increase the alert duration threshold to 10+ minutes, or implement hysteresis by setting separate thresholds for alert triggering vs. clearing (e.g., trigger at 85%, clear at 70%).

What You Now Have

You're running a production-grade monitoring stack that uses less RAM than a single Firefox tab, requires zero external services, and gives you real-time visibility into every server in your homelab. Beszel handles the monitoring burden so you can focus on running services, not debugging infrastructure.

Next steps: Set up alerts for the metrics that actually matter to you (I recommend starting with disk usage and memory), integrate with your notification platform (Ntfy or Discord work great), and periodically review the 7-day graphs to spot trends.

For scaling beyond 30 systems or if you need long-term historical analysis, revisit Prometheus—but for a typical homelab, Beszel is your answer.