What does Beszel monitor?
A website can still return a successful response while its server is running out of disk space. Equally, a CPU spike does not necessarily mean customers have lost access. Useful monitoring separates resource pressure from availability, then gives you enough history to connect the two.
Beszel provides a hub dashboard and per-system agents, with historical resource data, Docker statistics and configurable alerts. Its supported metrics include CPU, memory, disk and network activity. Hardware-specific information depends on what the monitored machine exposes; a virtual server will not necessarily expose the physical host's temperature or drive health. See the official Beszel overview.
| Question | Useful check | What to do with it |
|---|---|---|
| Is the machine under pressure? | CPU, memory and disk history | Compare busy periods with deployments, scheduled jobs and normal traffic. |
| Which workload is growing? | Per-container resource metrics | Identify a service worth investigating before increasing every VM's allocation. |
| Can visitors use the site? | An independent HTTP or application check | Test the public path separately from the operating system. |
| Has the monitoring server failed? | A check outside that server | Avoid depending on the failed hub to deliver its own outage notification. |
If you already use Uptime Kuma, keep it for external checks and use Beszel for a closer look at the machine. A green resource dashboard is not proof that checkout, login or a background worker is functioning. Add an application-specific check for the user journey that matters.
1. Prepare a Linux VPS and a monitoring domain
Use a Linux VPS with administrator access, Docker Engine and the Compose plugin. A dedicated monitoring VM keeps experiments and application restarts separate from the hub. For a small deployment, allocating 1 vCPU and 1 GB RAM is a practical starting budget rather than an official minimum or a capacity guarantee. Measure actual consumption as you add systems and retain more history.
- Choose a hostname such as
monitor.example.com, replacing it everywhere below with your real domain. - Have SSH access and a non-default, strong administrator password ready.
- Confirm the machine has enough free disk space for Docker images, metrics and backups.
- Use a current supported Linux installation and complete the VPS setup checklist first.
- Install Docker from its official installation instructions if it is not present.
docker --version
docker compose version
df -h
free -h
The commands below assume your account can run Docker. Docker access is privileged: only give it to trusted administrators. Keep an existing SSH session open while adjusting firewall rules, and confirm a second login works before closing it.
2. Install the Beszel hub with Docker Compose
Create a private working directory on the VPS:
mkdir -p ~/beszel
chmod 700 ~/beszel
cd ~/beszel
nano compose.yaml
Save this hub configuration. Port 8090 is deliberately published only on the server's loopback address, not every network interface:
services:
beszel:
image: henrygd/beszel:latest
restart: unless-stopped
environment:
APP_URL: https://monitor.example.com
ports:
- "127.0.0.1:8090:8090"
volumes:
- ./beszel_data:/beszel_data
docker compose config --quiet
docker compose up -d
docker compose ps
docker compose logs --tail=50 beszel
The data directory is persistent; recreating the container must not mean starting with an empty dashboard. This adapts the official getting-started configuration. The example uses the upstream latest tag for a first install. For repeatable production deployments, record and pin a reviewed release tag or image digest after checking compatibility. Do not update it unattended without a backup.
Before publishing the site, create its first account through an SSH tunnel. On your own computer, open a second terminal and substitute your SSH username and server address:
ssh -N -L 18090:127.0.0.1:8090 your-user@your-server
While that session is open, visit http://127.0.0.1:18090 on your computer and create the initial administrator account. This avoids leaving an unclaimed setup screen on the internet. Close the tunnel when finished. The hub itself remains bound to the VPS loopback interface.
3. Put the dashboard behind HTTPS
Point the hostname's A record at the VPS IPv4 address. Add an AAAA record only if the IPv6 address, routing and firewall work too. An incorrect AAAA record can cause seemingly intermittent failures because different clients take different paths.
This example assumes Caddy runs as a service on the same host, not inside a separate container. Install it using Caddy's official instructions, then add the following site to its existing Caddyfile without removing other sites:
monitor.example.com {
request_body {
max_size 10MB
}
reverse_proxy 127.0.0.1:8090 {
transport http {
read_timeout 360s
}
}
}
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
Allow HTTP/HTTPS to Caddy as needed for certificate issuance and dashboard access, while keeping SSH restricted appropriately. Do not add a public firewall allowance for 8090. If you already run another reverse proxy on ports 80 and 443, configure that proxy instead of starting a competing listener.
Beszel requires WebSocket forwarding for agent-initiated connections. Keep APP_URL set to the real HTTPS URL so generated configuration and notification links point to the right place. The Beszel reverse-proxy guide also provides Nginx and Traefik examples.
Open the HTTPS address, sign in and verify the certificate. An extra identity proxy can protect the interface, but an interactive browser challenge in front of the agent endpoint will block unattended agents. Plan machine authentication deliberately instead of weakening the entire dashboard when a connection fails.
4. Connect each server securely
In the hub, use Add System to create a system and obtain its agent configuration. Give it a recognisable name such as uk-app-01 or us-worker-01. Copy the public KEY, registration TOKEN and hub URL from your own installation; never reuse somebody else's example credentials. The agent installation documentation explains the generated configuration.
On the server you want to monitor, create a separate directory and save this as compose.yaml, substituting the values from the hub:
services:
beszel-agent:
image: henrygd/beszel-agent:latest
restart: unless-stopped
network_mode: host
volumes:
- ./beszel_agent_data:/var/lib/beszel-agent
environment:
LISTEN: "127.0.0.1:45876"
HUB_URL: "https://monitor.example.com"
KEY: "REPLACE_WITH_YOUR_HUB_PUBLIC_KEY"
TOKEN: "REPLACE_WITH_THIS_SYSTEM_TOKEN"
DOCKER_HOST: ""
This starts with host metrics only. The agent uses an outbound WebSocket connection to the HTTPS hub; its SSH listener stays on loopback. You do not need to expose port 45876 publicly for this design. Beszel also supports hub-initiated SSH, but that is a different connection model. See its connection security documentation.
chmod 600 compose.yaml
docker compose config --quiet
docker compose up -d
docker compose logs --tail=50 beszel-agent
Finish adding the system in the hub, wait for a successful connection, and check that charts are receiving new samples. Repeat on each server with its own system registration. Keep agent data persistent and do not copy a running agent's data directory as a shortcut when cloning machines.
Add Docker metrics only when you need them
To include container statistics, remove DOCKER_HOST: "" and add this entry beneath the agent's existing volumes list:
- /var/run/docker.sock:/var/run/docker.sock:ro
Then recreate the agent with docker compose up -d. Treat Docker socket access as a significant privilege, even with a read-only filesystem mount: that mount is not a Docker API authorisation policy. Do not expose the socket over a public network. For tighter control, use a filtered socket proxy configured for Beszel's required access instead.
The environment-variable reference documents disabling Docker monitoring and using a socket proxy. It also documents loopback listener syntax. Keep host networking when you need host network-interface statistics, and review those interfaces so you do not misinterpret Docker bridge traffic as customer internet transfer.
5. Configure alerts that lead to action
Add a notification destination under Settings, then enable the relevant alerts for your systems. Beszel uses provider-specific notification URLs; Discord, Telegram and other services have different formats. Follow the official notifications guide and protect tokens like passwords.
Start with a small set of actionable checks. The following are operational suggestions, not universal thresholds:
- Disk capacity: leave enough headroom to investigate and clean up safely. A database disk deserves earlier intervention than a disposable build cache.
- Memory pressure: compare the graph with swap activity, process behaviour and out-of-memory events before assuming every occupied byte is a problem.
- Sustained CPU load: account for expected backups and builds. A short scheduled spike should not create the same response as prolonged pressure during customer traffic.
- System disconnected: investigate the machine, agent and network path separately. An offline agent is a symptom, not a diagnosis.
Test delivery to the real person or channel that will handle incidents. On a disposable monitored VM, briefly stop only its agent, confirm the configured status alert arrives, then start it again. Do not deliberately exhaust production disk or memory to test a notification.
Keep the monitoring hub under an independent external check. If the hub and notification sender fail together, a quiet channel can look deceptively reassuring. Put recovery instructions somewhere you can access without this VPS.
6. Back up the hub and plan updates
Metrics history and configuration become useful precisely when something has gone wrong. Save the Compose configuration, record the running image version, and keep a consistent copy of beszel_data outside the VPS. The agent configuration also contains credentials and needs protected storage.
For a straightforward small installation, a brief maintenance window allows a stopped-service backup. From the hub directory, these commands stop only the monitoring hub, archive its data and configuration, then start it again:
mkdir -p ~/beszel-backups
chmod 700 ~/beszel-backups
umask 077
docker compose stop beszel
tar -czf ~/beszel-backups/beszel-$(date +%F-%H%M%S).tar.gz compose.yaml beszel_data
docker compose start beszel
docker compose ps
Check that the archive command succeeded and that the hub restarted, even if the backup failed. Account for the temporary monitoring gap. Copy the archive to a protected off-server destination, encrypt it where appropriate and define a retention schedule. Do not regard another directory on the same VPS as an independent backup.
Test recovery on an isolated VM with the recorded compatible image version. Verify users, systems and historical data before calling the backup usable. Keep the recovery instance isolated from production agents and notification destinations until you deliberately switch over. Our encrypted Rclone and Storage Box guide covers one off-server copy workflow.
For updates, read release notes, take a fresh backup, update the hub and agents deliberately, and verify samples and alerts afterwards:
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=50
With pinned images, change the reviewed tag or digest first; pulling alone does not choose a new version. Do not assume downgrading a container reverses a database migration. Retain a matching pre-update backup and configuration for recovery.
Troubleshoot Beszel agents and missing metrics
| Problem | Check first |
|---|---|
| Dashboard does not open | Confirm the hub container is running, the proxy reaches 127.0.0.1:8090, and DNS points to this server. |
| HTTPS works, agent stays offline | Verify KEY, TOKEN and HUB_URL, inspect agent logs, and check that the proxy forwards WebSockets without an interactive challenge. |
| Only one location disconnects | Check that location's DNS resolution, certificate validation and outbound route before changing every agent. |
| No Docker containers appear | The initial example disables Docker monitoring. Review the optional socket configuration and permissions before enabling it. |
| Graphs show unexpected traffic | Identify included interfaces and bridge or overlay traffic. Monitoring counters are not automatically billing counters. |
| No alert arrives | Check the destination credentials, enabled system alerts and actual delivery. A saved notification URL is not a delivery test. |
Compare timestamps when investigating gaps. Keep credentials out of screenshots and support requests. Share the relevant error, connection method and version rather than posting the complete agent configuration publicly.
Monitor HYEHOST servers in Wolverhampton and Ashburn
A Cloud VPS is a natural home for the Linux hub: you control Docker, the proxy and backup jobs. With VPS Resource Pools, you can place individual VMs in Wolverhampton or Ashburn and mix the two locations within one pool. That makes a separate monitoring VM practical without combining monitoring and customer applications into one operating system.
For example, run an application VM in Wolverhampton, a worker in Ashburn and the monitoring hub on a separate VM. Both agents connect to the hub's HTTPS hostname. This example does not assume a shared private LAN spans regions, and it is not automatic failover: plan cross-region networking and recovery separately.
Use meaningful system names and record each machine's role, location and owner. Compare an incident with recent deployments before deciding to buy more resources. A steadily growing disk or a single container's memory leak calls for a different response from genuine sustained demand.
A Storage Box can hold encrypted backup copies; it is not where this Docker hub runs. For larger self-managed storage and application workloads, Storage VPS provides a different deployment option. Choose capacity based on measured use rather than retaining unlimited monitoring history by default.
Before you rely on the dashboard
- The administrator account exists and HTTPS works without certificate warnings.
- The hub's raw HTTP port and agent listener are not publicly reachable.
- Each expected server produces fresh, correctly labelled samples.
- Docker access is either intentionally disabled or deliberately authorised.
- A real notification has reached the correct recipient.
- An independent check watches the hub itself.
- An off-server backup has been restored successfully in isolation.
- Someone owns updates, alert response and retention.
Frequently asked questions
What is Beszel used for?
Beszel collects server resource metrics and presents their history in a central dashboard. It can help you investigate CPU, memory, disk and container usage across multiple machines.
Can Beszel monitor servers in different locations?
Yes, when each agent can reach the hub using the configured connection method. An outbound HTTPS WebSocket connection can connect UK and US servers without making the agent port publicly accessible.
Does Beszel replace Uptime Kuma?
Not for every monitoring job. Resource monitoring explains what is happening inside a server; an independent uptime check verifies whether an application is reachable from outside. Use both when you need both perspectives.
Do I need to expose port 45876?
Not for the outbound WebSocket design in this guide. The agent listener is bound to loopback and connects to the hub over HTTPS. A hub-initiated SSH design has different firewall requirements.
Can I install the hub on Shared Hosting or a Storage Box?
This Docker setup needs a Linux server you administer, such as a Cloud VPS. Shared Hosting and managed Storage Boxes are not Docker hosts. A Storage Box can hold copies of your hub backups.
Will monitoring prevent downtime?
No. Monitoring helps you notice and investigate problems, but recovery still needs someone or something to act. Backups, tested restores and independent alerts remain important.

