Beszel is a lightweight server monitoring hub with a web UI, historical data, Docker container stats, and alerting. It consists of a hub (central dashboard) and agents (installed on each monitored server). This guide deploys the hub with Docker, an Nginx reverse proxy, and a Let’s Encrypt SSL certificate, then covers agent installation.
Prerequisites
Docker and Docker Compose installed on the hub server — see Install Docker
A domain or subdomain pointed to the hub server (e.g., monitor.example.com)
Ports 80 and 443 are open in your firewall
Step 1: Deploy the Beszel Hub
Create a directory and Docker Compose file:
mkdir -p /opt/beszel && cd /opt/beszel
cat > docker-compose.yml << 'EOF'
services:
beszel:
image: henrygd/beszel:latest
container_name: beszel
restart: unless-stopped
volumes:
- ./data:/beszel_data
ports:
- "127.0.0.1:8090:8090"
EOF
Start the container:
The hub is now running on 127.0.0.1:8090.
Step 2: Install Nginx
Debian / Ubuntu
RHEL / AlmaLinux / Rocky
apt update && apt install -y nginx
systemctl enable nginx
dnf install -y nginx
systemctl enable nginx
systemctl start nginx
Replace monitor.example.com with your actual domain:
cat > /etc/nginx/sites-available/beszel << 'CONF'
server {
listen 80;
listen [::]:80;
server_name monitor.example.com;
location / {
proxy_pass http://127.0.0.1:8090;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
CONF
See all 18 lines
Enable the site and reload Nginx:
ln -sf /etc/nginx/sites-available/beszel /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx
RHEL-Based Systems RHEL, AlmaLinux, and Rocky do not use sites-available/sites-enabled by default. Place the configuration in /etc/nginx/conf.d/beszel.conf Instead, skip the symlink step.
Step 4: Install SSL with Certbot
Debian / Ubuntu
RHEL / AlmaLinux / Rocky
apt install -y certbot python3-certbot-nginx
dnf install -y epel-release
dnf install -y certbot python3-certbot-nginx
Obtain and install the certificate:
certbot --nginx -d monitor.example.com
Verify automatic renewal:
Step 5: Access the Hub
Open https://monitor.example.com in your browser. On first visit, create your admin account at the /_/ admin path.
Installing the Agent
The Beszel agent runs on each server you want to monitor and reports back to the hub. It does not require Docker.
Add a System in the Hub
Log in to the Beszel hub
Click Add System
Enter a name and the server’s IP/hostname
The hub will generate a public key — copy it
Install the Agent
On the server you want to monitor, run:
Linux (any distro)
Docker
curl -sL https://raw.githubusercontent.com/henrygd/beszel/main/supplemental/scripts/install-agent.sh -o install-agent.sh
chmod +x install-agent.sh
./install-agent.sh
The installer will prompt for:
The hub’s public key (paste the key from Step 1)
The port for the agent to listen on (default: 45876)
docker run -d \
--name beszel-agent \
--restart unless-stopped \
--network host \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e PORT= 45876 \
-e KEY="PASTE_HUB_PUBLIC_KEY_HERE" \
henrygd/beszel-agent:latest
Open the Agent Port
On the monitored server, allow the agent port in the firewall:
# Allow only the hub server to reach the agent
ufw allow from HUB_SERVER_IP to any port 45876/tcp comment "Beszel Agent"
firewall-cmd --permanent --add-rich-rule= 'rule family=ipv4 source address=HUB_SERVER_IP port port=45876 protocol=tcp accept'
firewall-cmd --reload
Restrict agent access to the hub server’s IP only. There is no reason for other hosts to reach the agent port.
Updating
Hub
cd /opt/beszel
docker compose pull
docker compose up -d
Agent (systemd)
curl -sL https://raw.githubusercontent.com/henrygd/beszel/main/supplemental/scripts/install-agent.sh | bash
Agent (Docker)
docker pull henrygd/beszel-agent:latest
docker stop beszel-agent && docker rm beszel-agent
# Re-run the docker run command from the installation step
All-in-One Hub Script
Edit the DOMAIN variable before running:
#!/bin/bash
set -euo pipefail
# --- Configuration ---
DOMAIN = "monitor.example.com"
# ---------------------
echo "=== Beszel Hub Setup ==="
. /etc/os-release
DISTRO = " $ID "
if ! command -v docker & > /dev/null ; then
echo "Docker is not installed. Run the Docker install script first."
exit 1
fi
# Deploy Beszel
echo "--- Deploying Beszel ---"
mkdir -p /opt/beszel && cd /opt/beszel
cat > docker-compose.yml << 'EOF'
services:
beszel:
image: henrygd/beszel:latest
container_name: beszel
restart: unless-stopped
volumes:
- ./data:/beszel_data
ports:
- "127.0.0.1:8090:8090"
EOF
docker compose up -d
# Install Nginx
echo "--- Installing Nginx ---"
case " $DISTRO " in
debian | ubuntu )
apt update -qq
apt install -y nginx certbot python3-certbot-nginx
;;
almalinux | rocky | centos | rhel | cloudlinux | fedora )
dnf install -y nginx epel-release
dnf install -y certbot python3-certbot-nginx
systemctl start nginx
;;
esac
systemctl enable nginx
# Configure Nginx
echo "--- Configuring Nginx ---"
case " $DISTRO " in
debian | ubuntu )
NGINX_CONF = "/etc/nginx/sites-available/beszel"
cat > " $NGINX_CONF " << CONF
server {
listen 80;
listen [::]:80;
server_name $DOMAIN ;
location / {
proxy_pass http://127.0.0.1:8090;
proxy_http_version 1.1;
proxy_set_header Upgrade \$ http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$ host;
proxy_set_header X-Real-IP \$ remote_addr;
proxy_set_header X-Forwarded-For \$ proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$ scheme;
}
}
CONF
ln -sf " $NGINX_CONF " /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
;;
almalinux | rocky | centos | rhel | cloudlinux | fedora )
cat > /etc/nginx/conf.d/beszel.conf << CONF
server {
listen 80;
listen [::]:80;
server_name $DOMAIN ;
location / {
proxy_pass http://127.0.0.1:8090;
proxy_http_version 1.1;
proxy_set_header Upgrade \$ http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$ host;
proxy_set_header X-Real-IP \$ remote_addr;
proxy_set_header X-Forwarded-For \$ proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$ scheme;
}
}
CONF
;;
esac
nginx -t && systemctl reload nginx
# SSL
echo "--- Obtaining SSL Certificate ---"
certbot --nginx -d " $DOMAIN " --non-interactive --agree-tos --register-unsafely-without-email --redirect
echo ""
echo "=== Setup Complete ==="
echo "Access Beszel at: https:// $DOMAIN "
echo "Create your admin account at: https:// $DOMAIN /_/"
See all 106 lines