Skip to content
Go back

Beszel: Server Monitoring Without the Prometheus Tax

By SumGuy 9 min read
Beszel: Server Monitoring Without the Prometheus Tax

You Don’t Need a Monitoring Stack. You Need a Monitoring Tool.

Somewhere between “I should probably watch my servers” and “I now maintain six containers just to see CPU graphs,” you lost the plot.

Here’s how it usually goes: you stand up a VPS or three. You figure you should know if one of them is on fire. Someone on Reddit says “just use Prometheus + Grafana.” You spend a weekend setting up node_exporter, writing scrape configs, importing dashboards from a JSON blob you don’t understand, and configuring Alertmanager with a YAML file that has six levels of nesting. You get graphs. Beautiful, glorious graphs. You also now have seven running containers, two config files to maintain, and a Grafana dashboard that crashes your browser tab on mobile.

There’s a better way for the rest of us.

Beszel is a lightweight multi-server monitoring tool built on PocketBase with tiny Go agents on each host. One hub container. One binary per server. Real-time CPU, RAM, disk, network, and container stats—plus alerts, without a six-service Compose stack. Your 2 AM self will appreciate it.


What Beszel Actually Is

Beszel has two pieces:

That SSH-tunnel approach is clever. Your agents don’t need to be publicly accessible. No firewall rules to punch. No reverse proxy needed on each host. The hub pulls the data; agents don’t push to an exposed endpoint.

Out of the box you get:

No PromQL. No Loki. No dashboards to import. Just works.


Standing Up the Hub

One Compose file. That’s it.

docker-compose.yml
services:
beszel:
image: henrygd/beszel:latest
container_name: beszel
restart: unless-stopped
ports:
- "8090:8090"
volumes:
- ./beszel-data:/beszel_data
environment:
- TZ=America/New_York

Bring it up:

Terminal window
docker compose up -d

Hit http://your-server:8090 and create your admin account. You’re done with the hub setup. Seriously, that’s the whole thing.

If you’re running this behind Caddy or Nginx, proxy port 8090. Beszel’s UI is a single-page app—no special headers needed, just a standard reverse proxy config.


Adding Your First Host

In the Beszel UI, click Add System. You’ll get:

Beszel generates an SSH key pair internally. You’ll see a public key to authorize on the agent side—but if you’re running the agent as a Docker container, it handles this automatically.

Option 1: Docker Agent (Easiest)

On the host you want to monitor, drop this Compose file:

docker-compose.yml
services:
beszel-agent:
image: henrygd/beszel-agent:latest
container_name: beszel-agent
restart: unless-stopped
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- PORT=45876
- KEY=<paste-public-key-from-hub>

network_mode: host is required—the agent needs to see the host’s actual network interfaces for accurate stats. The Docker socket mount is optional but gives you per-container metrics.

Terminal window
docker compose up -d

Back in the hub, click Test Connection for your new system. Green check? You’re monitoring.

Option 2: Binary Agent (Systemd Hosts, LXC, VMs Without Docker)

Terminal window
curl -sL https://raw.githubusercontent.com/henrygd/beszel/main/supplemental/scripts/install-agent.sh | bash -s -- -p 45876 -k "<your-public-key>"

The script installs the agent as a systemd service. Works on any modern Linux host.


What the Dashboard Actually Shows You

The hub UI is clean without being sparse. Per-host view gives you:

The multi-host overview page shows all your systems in a grid with live stats. At a glance you know which boxes are sweating and which are napping. It renders fine on a phone, which matters when you’re at dinner and your pager goes off.


Alert Rules That Don’t Require a PhD

In the Beszel UI, alerts live under each system’s settings. You pick a metric, a threshold, and a severity. Current supported alert types:

Example: alert when disk on your NAS hits 85%:

Metric: Disk Usage
Threshold: 85
Duration: 5 minutes
Severity: Warning

Connecting Notifications

Beszel supports multiple channels via its notification settings page. Discord is the easiest for homelabbers:

Type: Discord
Webhook URL: https://discord.com/api/webhooks/your-webhook-url

That’s it. When your disk fills up or a container dies, you get a Discord message. No Alertmanager YAML. No inhibit_rules. No route.receiver nesting.

You can also configure ntfy for push notifications on your phone, or webhook to hit any HTTP endpoint—handy if you run something like Apprise or your own alert aggregator.


How Beszel Stacks Up

Let’s be honest about the alternatives:

Uptime Kuma — amazing for HTTP/TCP/DNS uptime checks. If you want “is my website up and does it respond in under 2 seconds,” Uptime Kuma is the right tool. It’s not a system metrics tool. It doesn’t know your CPU is at 98%—it just knows your HTTP endpoint answered. Different job.

Netdata — incredibly powerful, genuinely impressive technology, and also installs 40MB of stuff on your host, phones home by default, and assumes you want to think about it. The per-host UI is great; the multi-host story involves their cloud or running Netdata Parent, which is more infrastructure. If you’re already all-in on Netdata, great. For a homelab with 3-5 hosts, it’s heavy.

Glances — solid single-host monitoring with a decent web UI. No centralized multi-host view. You’d be opening a browser tab per server. Fine for occasional checks, not for “show me all my hosts at once.”

Zabbix — overkill doesn’t begin to cover it. Zabbix is for enterprises with 500 hosts and a dedicated monitoring team. It has its own database schema, its own agent protocol, its own templating system. It’s excellent at scale. For a homelab it’s like hiring a forklift to move a couch.

Prometheus + Grafana — and here’s the honest take: the Prometheus stack is the right answer if you need it. Long-term metric retention with custom retention policies? Prometheus. Complex multi-dimensional queries with PromQL? Prometheus. Alerting rules based on rate-of-change, prediction, or cross-metric math? Alertmanager. Multi-team RBAC with fine-grained dashboard permissions? Grafana Enterprise or Grafana with an LDAP backend.

For three home servers? You’re paying a steep complexity tax for features you’ll never touch. Beszel covers 90% of what homelabbers actually need at about 5% of the operational overhead.


Where Beszel Breaks Down

No tool is perfect. Know the limits before you commit:

Long-term retention. Beszel’s default retention is 15 days (configurable up to whatever your disk can handle). If you need 2 years of metrics for capacity planning, Beszel isn’t your primary store—you’d still want Prometheus with a long-retention TSDB or VictoriaMetrics behind it.

Query flexibility. There’s no query language. You get the graphs Beszel gives you. You can’t write “show me p95 latency for requests that hit container X during high-CPU periods.” If you need that, you need a real TSDB.

Multi-team RBAC. Beszel has basic user roles (admin, viewer) but nothing granular. If you have a team where Alice should only see the prod servers and Bob only the dev cluster, Beszel can’t enforce that today.

No log aggregation. Beszel is metrics-only. No log shipping, no log search. If you need “show me the Docker logs from the last hour when memory spiked,” you still need something like Loki or a simple ELK setup.

Alerting complexity. Threshold-based alerts cover most homelab needs. But if you want “alert if CPU is above 80% for 5 minutes AND disk IO is above 50MB/s AND it’s not Saturday,” you’re writing that logic elsewhere.

For homelab and small team self-hosting? These gaps rarely matter. For production infrastructure with SLAs and an on-call rotation? Layer Beszel for quick dashboards on top of a proper observability stack.


Full Example: Hub + Agent on Two Hosts

hub/docker-compose.yml
services:
beszel:
image: henrygd/beszel:latest
container_name: beszel
restart: unless-stopped
ports:
- "8090:8090"
volumes:
- ./data:/beszel_data
environment:
- TZ=America/New_York
agent/docker-compose.yml
services:
beszel-agent:
image: henrygd/beszel-agent:latest
container_name: beszel-agent
restart: unless-stopped
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- PORT=45876
- KEY=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... (your hub's generated key)

Deploy the hub first. Create your admin account. Add a system in the UI—it’ll show you the public key. Paste that key into the agent’s KEY env var. Deploy the agent. Hit Test Connection in the hub. Done.

Repeat the agent deploy for every host you want to monitor. The hub handles them all from one UI.


The Bottom Line

If you’ve been avoiding monitoring because “setting up Prometheus” sounds like a weekend project and you already have a full one, Beszel is the answer.

Hub up in five minutes. Agent on a new host in two. Alerts to Discord in ten. No Grafana dashboards to import, no scrape configs to write, no exporters to babysit.

It’s not trying to replace your observability stack. It’s trying to replace the thing you were procrastinating on. That’s a different job, and Beszel does it well.

Check the project: github.com/henrygd/beszel


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Next Post
iperf3 + nload: Network Diagnosis

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts