Tutoriales de VPS
Desplegar Beszel en un VPS (2026): monitorización ligera de servidores, métricas de contenedores Docker, alertas y HTTPS
Despliega el panel de monitorización ligero Beszel en un VPS, configura el Hub, el Agent, HTTPS con Caddy, métricas de contenedores Docker y alertas, y completa la incorporación de varios servidores, copias de seguridad, actualizaciones y resolución de problemas habituales.

Desplegar Beszel en un VPS (2026): monitorización ligera de servidores, métricas de contenedores Docker, alertas y HTTPS
Si solo quieres ver la CPU, la memoria, el disco y el estado de los contenedores Docker de unos pocos VPS, Prometheus + Grafana suele resultar algo pesado; y si solo instalas Uptime Kuma, tampoco ves por qué se ralentiza el host. Beszel se sitúa justo en medio: un panel de gestión Hub más un Agent por servidor, y en pocos minutos ves métricas históricas y alertas.
Esta guía despliega la versión estable v0.18.7 de julio de 2026. Los ejemplos usan etiquetas de imagen fijas en lugar de latest, y cubren HTTPS, la dirección de conexión del Agent, las copias de seguridad y la resolución de problemas de una vez.
El Beszel Hub almacena sistemas, usuarios, datos históricos y alertas; el Agent recopila las métricas de CPU, memoria, carga, disco, red, temperatura y contenedores Docker/Podman del servidor donde se ejecuta.
Es adecuado para laboratorios domésticos, equipos pequeños y la monitorización rápida de hasta una docena de VPS. Si necesitas PromQL complejo, agregación de métricas a largo plazo o métricas de negocio personalizadas, consulta el tutorial de Prometheus + Grafana en VPS. Si solo te importa si un sitio web abre y una página de estado pública, Uptime Kuma es más directo.
También hay un problema práctico: si el Hub y los servicios monitorizados están en el mismo VPS, cuando esa máquina se cae por completo, el Hub tampoco puede enviar notificaciones. Para entornos importantes, lo mejor es ejecutar el Hub de forma independiente, o activar el Heartbeat externo de Beszel para enviar el estado a otro servicio de monitorización.
Beszel no establece oficialmente una configuración mínima estricta. Para uso personal puedes empezar con 1 núcleo, 1 GB de memoria y 10 GB de disco libre; lo que realmente afecta al disco es el número de nodos y el tiempo de retención del historial, así que no lo tomes como un valor garantizado.
Prepara un dominio, por ejemplo monitor.example.com, con registros A/AAAA apuntando al VPS del Hub. Abre los puertos según el método de conexión:
| Dirección | Puerto | Uso |
|---|---|---|
| Público al Hub | TCP 80/443 | Certificados de Caddy y página web de gestión |
| Local del Hub | TCP 8090 | Beszel Hub, solo enlazado a la dirección de loopback |
| Hub al Agent | TCP 45876 | Solo necesario en modo SSH pull |
| Agent al Hub | TCP 443 | Modo WebSocket push |
Para VPS remotos se recomienda WebSocket por defecto: el Agent se conecta activamente a la dirección HTTPS del Hub, sin necesidad de exponer 45876 a Internet. Si eliges el modo SSH, permite el 45876 del Agent solo desde la IP del Hub. Antes de modificar el firewall, puedes leer la guía de UFW para evitar el bloqueo de SSH.
Registra una línea base antes de desplegar, para que luego puedas saber por las curvas si algo es anómalo:
free -h
df -h
uptime
docker system df
timedatectl status
Si el disco ya está casi lleno, no esperes que el contenedor de monitorización lo salve; primero ocúpate de los registros y las copias de seguridad. La hora del sistema también debe ser precisa, de lo contrario los gráficos y las horas de las alertas de varios VPS no coincidirán. Cuando prepares la monitorización de más de veinte servidores, ejecuta primero unos pocos nodos durante una semana y luego decide el disco y la política de retención según el crecimiento real de beszel_data; es más fiable que copiar los números de capacidad de otros.
Primero instala Docker Engine y el plugin Compose, luego crea el directorio:
sudo mkdir -p /opt/beszel
sudo chown "$USER":"$USER" /opt/beszel
cd /opt/beszel
mkdir -p beszel_data beszel_agent_data beszel_socket
Crea un nuevo docker-compose.yml. Deja valores de marcador de posición para el Agent por ahora y arranca solo el Hub la primera vez:
services:
beszel:
image: henrygd/beszel:0.18.7
container_name: beszel
restart: unless-stopped
environment:
APP_URL: https://monitor.example.com
ports:
- 127.0.0.1:8090:8090
volumes:
- ./beszel_data:/beszel_data
- ./beszel_socket:/beszel_socket
beszel-agent:
image: henrygd/beszel-agent:0.18.7
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: YOUR_SYSTEM_TOKEN
KEY: "YOUR_SYSTEM_PUBLIC_KEY"
Comprueba la configuración y arranca solo el Hub:
docker compose config
docker compose up -d beszel
docker compose ps
docker compose logs --tail=100 beszel
curl -I http://127.0.0.1:8090
Puedes verificar la versión de la imagen en los Releases oficiales. Cambia la etiqueta al actualizar; no dejes que una sola reconstrucción cambie de versión en silencio. Para las comprobaciones de estado, el registro y los límites de recursos de Compose en producción, consulta la lista de configuración de producción de Docker Compose.
El Agent de Beszel puede conectarse al Hub mediante WebSocket, por lo que el proxy inverso debe permitir conexiones de larga duración. La configuración de Caddy no puede ser solo la línea más corta; el ejemplo oficial también establece el tamaño del cuerpo de la solicitud y un tiempo de lectura de 360 segundos:
monitor.example.com {
request_body {
max_size 10MB
}
reverse_proxy 127.0.0.1:8090 {
transport http {
read_timeout 360s
}
}
}
Valida y recarga:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -I https://monitor.example.com
sudo ss -lntup | grep -E ':443|:8090|:45876'
8090 solo debe escuchar en 127.0.0.1. Para el proceso de instalación completo, consulta la guía del proxy inverso Caddy. APP_URL debe ser la dirección HTTPS final; se usa para los enlaces de notificación y la generación de la configuración del Agent.
Abre https://monitor.example.com y crea la primera cuenta. Beszel se basa en PocketBase, y la configuración inicial crea tanto un usuario del Hub como un superusuario de PocketBase; cambiar la contraseña de las dos cuentas más adelante no se sincroniza automáticamente, así que es mejor etiquetarlas por separado en tu gestor de contraseñas.
Haz clic en Add System en la esquina superior derecha, rellena el nombre del sistema y establece Host/IP en:
/beszel_socket/beszel.sock
La interfaz mostrará una Public Key y un Token. Sustituye KEY y TOKEN en el Compose por ellos respectivamente, y luego arranca el Agent local:
docker compose up -d beszel-agent
docker compose logs --tail=100 beszel-agent
docker compose ps
Solo cuando el sistema pase de Pending a Up y aparezca el primer conjunto de datos de CPU y memoria se habrá completado la conexión. No envíes Keys, Tokens ni URL de notificación reales a un repositorio Git.
La forma más sencilla para los nodos remotos es copiar el Compose generado desde la página Add System del Hub. En modo WebSocket el Agent accede activamente al Hub, y puedes usar la siguiente estructura:
services:
beszel-agent:
image: henrygd/beszel-agent:0.18.7
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
environment:
HUB_URL: https://monitor.example.com
TOKEN: YOUR_SYSTEM_TOKEN
KEY: "YOUR_SYSTEM_PUBLIC_KEY"
DISABLE_SSH: "true"
DISABLE_SSH=true significa usar solo WebSocket y no arrancar ya el servicio SSH del Agent. Si cambias al modo SSH, la dirección de conexión se invierte: el Hub accede activamente al 45876 del Agent; un iptables FORWARD DROP estricto también puede bloquear el tráfico saliente del contenedor del Hub, en cuyo caso volver a WebSocket es más fácil de diagnosticar.
Cada nodo usa su propio Token de sistema; no copies el mismo directorio de datos del Agent en varias máquinas. Si la huella cambia tras una migración del servidor, confirma el nodo de destino en el Hub y vuelve a registrarlo, en lugar de reiniciar repetidamente y esperar suerte.
El Agent lee la lista de contenedores y las estadísticas a través del Docker Socket; primero compara la salida en ambos lados:
docker ps
docker stats --no-stream
docker compose logs --tail=150 beszel-agent
ls -l /var/run/docker.sock
Las causas habituales son una ruta de Socket incorrecta, que Podman use otro Socket, que el Agent no se haya recreado o que el contenedor esté excluido por EXCLUDE_CONTAINERS. Tras modificar el montaje, ejecuta:
docker compose up -d --force-recreate beszel-agent
:ro solo restringe cómo se monta el sistema de archivos dentro del contenedor; no convierte el Docker Socket en una interfaz de bajos privilegios. Un proceso que puede acceder al Socket suele tener una capacidad de control del host muy alta. No expongas la API de Docker en 0.0.0.0:2375, ni des al Agent privileged: true solo para ver métricas.
Abre las alertas en la lista de sistemas y primero establece los umbrales de desconexión, disco, memoria o CPU. No copies los umbrales a ciegas: una base de datos que se mantiene al 80% de memoria a largo plazo sin fluctuaciones de Swap no es lo mismo que un servicio web que de repente pasa del 30% al 80%.
La entrada de notificaciones está en Settings > Notifications, y Beszel usa URL de Shoutrrr. Por ejemplo, un ntfy autoalojado puede escribirse como:
ntfy://:[email protected]/beszel-alerts
Después de guardar, envía primero una notificación de prueba y luego baja brevemente el umbral de un nodo que no sea de producción para confirmar que se reciben tanto el disparo como la recuperación de la alerta. La URL de notificación contiene credenciales, así que cúbrela antes de compartir capturas de pantalla y registros. Si el Hub y el servicio de notificaciones también están en el mismo VPS averiado, las alertas tampoco saldrán.
Beszel también admite enviar periódicamente un Heartbeat a una dirección externa. Apunta HEARTBEAT_URL a otro Uptime Kuma, Healthchecks.io o un servicio similar, y aunque el Hub se desconecte por completo, el servicio externo podrá detectar la interrupción del latido. No sustituye a las alertas de recursos, sino que cubre específicamente el punto ciego de "el propio sistema de monitorización murió y nadie lo sabe". Tras configurarlo, detén una vez el Hub en un entorno de prueba para confirmar que la alerta externa se dispara realmente, y luego restaura el servicio.
Los datos principales están en /opt/beszel/beszel_data. El panel de administración permite guardar en disco o en almacenamiento compatible con S3, pero aun así debes hacer periódicamente una prueba de recuperación. Una copia de seguridad sencilla con parada se puede hacer así:
cd /opt/beszel
backup_date="$(date +%F)"
docker compose stop beszel
sudo tar -czf "/var/backups/beszel-${backup_date}.tar.gz" \
beszel_data docker-compose.yml
docker compose start beszel
sudo tar -tzf "/var/backups/beszel-${backup_date}.tar.gz" | head
curl -I https://monitor.example.com
El archivo comprimido también debe copiarse a otra máquina o a un almacenamiento de objetos. Para operaciones formales puedes combinarlo con el simulacro de copia de seguridad y restauración en VPS.
Consulta los Releases antes de actualizar y, una vez completada la copia de seguridad, cambia la misma etiqueta de versión tanto en el Hub como en el Agent:
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 beszel
docker compose logs --tail=100 beszel-agent
No des por terminado el mantenimiento hasta que la página, un Agent local y un Agent remoto funcionen con normalidad. Si falla, restaura la etiqueta de imagen original; si la nueva versión ya ha modificado la estructura de datos, restaura la misma copia de seguridad previa a la actualización, no solo rebajes la imagen y fuerces.
Haz otra ronda de aceptación antes de poner en producción: tras reiniciar Docker, el Hub y el Agent deben recuperarse automáticamente; apaga un Agent de prueba y la alerta de desconexión debe llegar según lo esperado; tras la recuperación el estado debe volver a verde; extrae la copia de seguridad en otra máquina y al menos deberías ver los datos de PocketBase y el archivo Compose. Ver curvas en la página de inicio no significa que las alertas, la persistencia y la cadena de recuperación funcionen.
curl -Iv https://monitor.example.com
sudo journalctl -u caddy -n 100 --no-pager
docker compose logs --tail=150 beszel
Revisa especialmente el DNS, los certificados, APP_URL, el read_timeout de Caddy y si 8090 sigue enlazado a la dirección de loopback.
docker compose logs --tail=200 beszel-agent
curl -I https://monitor.example.com
sudo ss -lntup | grep 45876
En modo WebSocket, comprueba HUB_URL, el Token, la Key y la huella del nodo; en modo SSH, comprueba además el 45876 del Hub al Agent y el firewall de reenvío. No mezcles los dos modos al diagnosticar.
cd /opt/beszel
docker compose config
du -sh beszel_data
df -h
Si el Compose no monta el ./beszel_data del host en /beszel_data, los datos históricos se pierden al eliminar el contenedor. Antes de restaurar, conserva el estado actual y confirma el contenido de la copia de seguridad; no sobrescribas directamente la única copia.
- Quieres ver rápidamente varios servidores y recursos de Docker: elige Beszel;
- Quieres monitorizar URL, caducidad de certificados y una página de estado pública: elige Uptime Kuma;
- Quieres recopilar métricas de negocio, escribir consultas complejas y escalar a largo plazo: elige Prometheus + Grafana.
La ventaja de Beszel es el despliegue ligero y la rapidez de inicio; su punto débil es que las consultas personalizadas y el ecosistema no están a la altura de Prometheus. Conecta primero un VPS no crítico, provoca una alerta de prueba y luego haz una copia de seguridad en otra máquina que puedas extraer; solo cuando los tres pasos pasen, añade los nodos de producción en bloque.