Saltar al contenido principal
50% de descuento todos los planes, tiempo limitado. Desde $2.48/mo
14 min left
Herramientas de desarrollo y DevOps

Cómo montar un stack de monitorización Grafana + Prometheus en tu VPS (guía de Docker Compose)

C Por Chike 14 min de lectura
Prometheus and Grafana monitoring stack illustration: a central dashboard panel showing Prometheus and Grafana logos over metric graphs, with three server nodes feeding metrics into it

Si aún no tienes claro qué son Prometheus y Grafana, lee nuestro artículo sobre Prometheus vs Grafana. Si ya conoces la diferencia, aquí tienes cómo ejecutarlos juntos.

Este artículo es la parte práctica. Despliega Prometheus, Grafana y Node Exporter en un solo VPS con Docker Compose, pone HTTPS delante de Grafana con Caddy, importa el panel Node Exporter Full (ID 1860) y muestra cómo recoger métricas de un segundo VPS a través de WireGuard.

La prueba original de abril de 2026 se ejecutó en Ubuntu 24.04 LTS con Docker Engine 27.x y Docker Compose v2.30. Las versiones fijadas en la configuración de más abajo se han actualizado desde entonces a las versiones soportadas actuales. En aquella prueba original con cinco hosts, el hub usaba unos 300 MB de RAM en reposo y entre 530 y 650 MB durante la recogida continua.

TL;DR

  • El VPS hub ejecuta Prometheus, Grafana y Node Exporter en un único stack de Compose, con Caddy instalado en el host como proxy inverso.
  • Prometheus y Grafana solo escuchan en 127.0.0.1. El acceso público pasa por Caddy con HTTPS automático.
  • Añade más servidores instalando Node Exporter en cada uno y agregando entradas a prometheus.yml.
  • WireGuard es la ruta de red recomendada entre el hub y los nodos. La red privada funciona bien cuando tus servidores ya comparten una red privada.
  • Un VPS de 2 GB bastó para la prueba con cinco hosts de más abajo, pero tómalo como una referencia y no como una regla fija según el número de hosts.

Lo que vas a montar

Diagram of monitoring traffic boundaries: ports 80 and 443 are public, Grafana on 3000, Prometheus on 9090 and Node Exporter on 9100 stay on loopback, and a remote Node Exporter on 10.10.0.2:9100 is reachable only over the private network

Esta es, a grandes rasgos, la pinta que tendrá el montaje cuando termines.

                 +-------------------+
                 |  Your laptop      |
                 +---------+---------+
                           | HTTPS
                           v
+--------------------------+----------------------------+
| MONITORING HUB VPS    (2 GB RAM starting point) |
|  Caddy        (reverse proxy, auto HTTPS)             |
|  Grafana      (port 3000, only via Caddy)             |
|  Prometheus   (port 9090, internal only)              |
|  Node Exporter (port 9100, scraped on localhost)      |
+----+---------------------------------+----------------+
     |                                 |
     | scrape over WireGuard           | scrape over WG
     v                                 v
+----+--------+                  +-----+-------+
|  App VPS 1  |                  |  App VPS 2  |
|  Node Expo. |                  |  Node Expo. |
+-------------+                  +-------------+

Un único VPS hub aloja todo el stack de monitorización. Cada uno de los demás VPS que quieras vigilar solo ejecuta Node Exporter. Prometheus, en el hub, recoge las métricas de todos. Grafana las visualiza. Caddy se encarga del HTTPS.

Requisitos previos

Para este montaje concreto necesitas un VPS con Ubuntu para el hub, un dominio y acceso sudo.

  • Un VPS con al menos 2 GB de RAM ejecutando Ubuntu 24.04 LTS.
  • Un nombre de dominio con un registro A apuntando a la IP pública del VPS (por ejemplo, grafana.example.com). Imprescindible para el HTTPS.
  • Acceso root o sudo por SSH.

A lo largo de esta guía, sustituye grafana.example.com por el subdominio que hayas apuntado realmente a tu VPS de monitorización. Usa el mismo dominio en la variable de entorno de Grafana, la comprobación de DNS y el Caddyfile.

Si solo quieres monitorizar un servidor y todavía no necesitas HTTPS, puedes levantar el stack de Compose en tu VPS actual sin la sección del proxy inverso. El resto de la guía sigue siendo válido.

Desplegar VPS Ubuntu

Lanza un VPS Ubuntu al instante con acceso root y almacenamiento NVMe.

Desplegar VPS Ubuntu

Paso 1: preparación del servidor

Conéctate por SSH al VPS hub con un usuario que tenga sudo. Empieza por actualizar el sistema.

sudo apt update && sudo apt upgrade -y

Instala Docker Engine y el plugin de Compose desde el repositorio oficial de Docker.

# Install prerequisites
sudo apt install -y ca-certificates curl gnupg lsb-release

# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the Docker repository
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Comprueba que ambos están instalados.

docker --version
docker compose version

Ambos comandos deben devolver una versión sin errores. Las versiones exactas de Docker Engine y Compose dependerán de lo que ofrezca el repositorio oficial cuando los instales.

sudo usermod -aG docker $USER

Cierra la sesión y vuelve a entrar antes de continuar, para que la nueva pertenencia al grupo surta efecto. El grupo docker otorga en la práctica privilegios de root, así que añade solo a administradores de confianza.

Configura UFW para permitir SSH, HTTP y HTTPS en el hub de monitorización. El puerto 80 se encarga de las redirecciones de HTTP a HTTPS y de la validación ACME. Grafana permanece detrás de Caddy.

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

No abras los puertos 3000, 9090 ni 9100 a internet. Por algo los servicios de monitorización escuchan en 127.0.0.1.

Paso 2: el stack de Compose

Crea un directorio para el stack y la configuración de Prometheus.

mkdir -p ~/monitoring/prometheus
cd ~/monitoring

Escribe el archivo de Compose.

# ~/monitoring/docker-compose.yml
services:
  prometheus:
    image: prom/prometheus:v3.13.2
    container_name: prometheus
    restart: unless-stopped
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=15d'
      - '--web.enable-lifecycle'
      - '--web.listen-address=127.0.0.1:9090'
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    network_mode: host
  node-exporter:
    image: prom/node-exporter:v1.12.1
    container_name: node-exporter
    restart: unless-stopped
    pid: host
    network_mode: host
    command:
      - '--path.rootfs=/host'
      - '--web.listen-address=127.0.0.1:9100'
      - '--collector.filesystem.mount-points-exclude=^/(dev|proc|sys|var/lib/docker/.+|var/lib/kubelet/.+)($$|/)'
    volumes:
      - '/:/host:ro,rslave'
  grafana:
    image: grafana/grafana:13.1.3
    container_name: grafana
    restart: unless-stopped
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_SERVER_ROOT_URL=https://grafana.example.com
      - GF_SERVER_HTTP_ADDR=127.0.0.1
    volumes:
      - grafana_data:/var/lib/grafana
    network_mode: host
    depends_on:
      - prometheus
volumes:
  prometheus_data:
  grafana_data:

Ahora escribe la configuración de Prometheus.

# ~/monitoring/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    monitor: 'monitoring-hub'
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['127.0.0.1:9090']
  - job_name: 'node'
    static_configs:
      - targets: ['127.0.0.1:9100']
        labels:
          host: 'monitoring-hub'

Crea un archivo .env con la contraseña de administrador de Grafana. Usa una contraseña fuerte. No subas este archivo a git.

cat > ~/monitoring/.env <<'EOF'
GRAFANA_ADMIN_PASSWORD='replace-with-a-strong-password'
EOF
chmod 600 ~/monitoring/.env

Algunas de las opciones anteriores merecen una explicación.

  • --web.listen-address=127.0.0.1:9090 hace que Prometheus escuche solo en la interfaz de loopback del host. Así el puerto 9090 queda fuera de la red pública, pero sigue siendo accesible para Grafana y para la administración local.
  • --web.enable-lifecycle habilita POST /-/reload, de modo que puedes aplicar cambios en la configuración de Prometheus sin reiniciar el contenedor.
  • pid: host, network_mode: host, el montaje bind de la raíz del host y --path.rootfs=/host le dan al Node Exporter en contenedor el contexto del host que necesita, en lugar de limitarse a vigilar su propio entorno de contenedor.
  • GF_USERS_ALLOW_SIGN_UP=false impide que los visitantes creen su propia cuenta de Grafana. Eso no convierte a Grafana en privado: la página de inicio de sesión sigue siendo accesible públicamente a través de Caddy.

Consejo pro: Si prefieres saltarte la instalación manual, Cloudzy ofrece despliegues en un clic de Grafana y Prometheus . El despliegue de Prometheus también puede instalar Node Exporter.

Paso 3: primer arranque y verificación

Levanta el stack.

cd ~/monitoring
docker compose up -d

Espera unos segundos y comprueba que los tres contenedores están en marcha.

docker compose ps

Los tres servicios deben aparecer en estado «running».

Abre un túnel SSH desde tu portátil para revisar la página de targets de Prometheus.

ssh -L 9090:localhost:9090 your-user@your-vps-ip

Después abre http://localhost:9090/targets en el navegador. Deberías ver dos targets, ambos en estado UP:

prometheus            UP    http://127.0.0.1:9090/metrics
node                  UP    http://127.0.0.1:9100/metrics

Si alguno aparece como DOWN, ve a la sección Problemas habituales. No sigas hasta que ambos estén UP.

Cierra el túnel cuando termines de revisar los targets. Desde fuera del VPS, Prometheus solo seguirá siendo accesible a través de este túnel SSH. El siguiente paso expone Grafana por HTTPS.

Paso 4: proxy inverso con HTTPS usando Caddy

Caddy es un único binario. Gestiona el HTTPS de forma automática. Para un proxy inverso de un solo sitio, su configuración es más corta que el bloque equivalente de Nginx.

Instala Caddy desde el repositorio oficial.

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
  sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
  sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddy

Antes del siguiente paso, confirma que tu registro DNS A de grafana.example.com apunta a la IP pública del VPS. Sin eso, la validación ACME falla.

dig +short grafana.example.com
# Should print the VPS public IP

Edita el Caddyfile.

# /etc/caddy/Caddyfile
grafana.example.com {
    reverse_proxy 127.0.0.1:3000
    encode gzip
}

Recarga Caddy.

sudo systemctl reload caddy

Caddy obtiene y renueva automáticamente certificados TLS de confianza pública mediante ACME, siempre que el dominio apunte a tu servidor y los puertos 80 y 443 sean accesibles. Abre https://grafana.example.com en el navegador: deberías ver la página de inicio de sesión de Grafana con una conexión HTTPS válida. Entra con admin y la contraseña de tu archivo .env.

Paso 5: añadir Prometheus como fuente de datos e importar el panel 1860

En la interfaz de Grafana, ve a Conexiones > Fuentes de datos > Añadir fuente de datos y elige Prometheus.

Pon esta URL:

http://127.0.0.1:9090

En este montaje, Grafana y Prometheus comparten la red del host, mientras que Prometheus solo escucha en loopback. Haz clic en Save & test y confirma que Grafana puede consultar la API de Prometheus. Debería aparecer «Successfully queried the Prometheus API».

Ahora importa el panel. Node Exporter Full (ID 1860, de rfmoz) es un panel comunitario muy usado para las métricas de Node Exporter. Cubre CPU, memoria, E/S de disco, red, descriptores de archivo y temperaturas del hardware cuando el host las expone. Además tiene variables para job e instance, así que sirve para el modelo hub-and-spoke sin tocar nada.

Ir a Paneles > Nuevo > Importar panel, introduce el ID de panel 1860, selecciona tu fuente de datos Prometheus e impórtalo.

El panel debería llenarse en cuanto tu target de Node Exporter esté UP. El panel 1860 usa además métricas de los recolectores opcionales systemd y processes en algunos gráficos, así que un gráfico vacío no significa necesariamente que el target esté roto.

Paso 6: añadir un segundo VPS (hub-and-spoke)

Antes de arrancar Node Exporter, asegúrate de que la IP privada a la que piensas enlazarlo ya existe en el segundo VPS. Si usas WireGuard, termina primero su configuración.

En el segundo VPS, instala Docker siguiendo la parte de instalación de Docker del paso 1, pero no abras los puertos 80 ni 443 solo para la monitorización. Después ejecuta únicamente Node Exporter.

mkdir -p ~/node-exporter
cd ~/node-exporter

cat > docker-compose.yml <<'EOF'
services:
  node-exporter:
    image: prom/node-exporter:v1.12.1
    container_name: node-exporter
    restart: unless-stopped
    pid: host
    command:
      - '--path.rootfs=/host'
      - '--web.listen-address=10.10.0.2:9100'  # bind to the private monitoring IP, never 0.0.0.0
    volumes:
      - '/:/host:ro,rslave'
    network_mode: host
EOF

docker compose up -d

Sustituye 10.10.0.2 por la IP privada de monitorización de este servidor. Si usas WireGuard, pon su IP de WireGuard. Si usas la red privada de Cloudzy, pon la IP de la interfaz privada del VPS. Si UFW ya está activo en este VPS, permite que solo el hub de monitorización llegue a Node Exporter. Por ejemplo, si la IP privada del hub es 10.10.0.1:

sudo ufw allow proto tcp from 10.10.0.1 to any port 9100
sudo ufw status

Sustituye 10.10.0.1 por la IP privada real del hub. Si UFW está inactivo, la opción explícita --web.listen-address sigue manteniendo a Node Exporter fuera de la interfaz pública, pero otras máquinas con acceso a esa red privada también pueden llegar al puerto 9100.

Dos buenas opciones para la ruta de red entre el hub y los nodos:

  1. Red WireGuard. Cada VPS se une a una red WireGuard y Prometheus consulta IP privadas. Es la opción más segura una vez configurado WireGuard. Ofrecemos WireGuard como despliegue en un clic, y también tenemos un tutorial de configuración ya publicado sobre ello.
  2. Red privada de Cloudzy. Las instancias VPS de Cloudzy en la misma región cuentan con una interfaz privada para el tráfico este-oeste, así que puedes consultar esa dirección en lugar de montar un túnel WireGuard aparte.

Cuando Node Exporter esté funcionando en el segundo VPS y sea accesible en su IP privada, sustituye el job node existente en prometheus.yml en el hub por el bloque de abajo.

# Update the existing 'node' job in ~/monitoring/prometheus/prometheus.yml
  - job_name: 'node'
    static_configs:
      - targets: ['127.0.0.1:9100']
        labels:
          host: 'monitoring-hub'
      - targets: ['10.10.0.2:9100']
        labels:
          host: 'app-vps-1'
          tier: 'production'

Recarga Prometheus sin reiniciar el contenedor.

curl -X POST http://localhost:9090/-/reload

Vuelve a abrir el túnel SSH del paso 3 y entra en http://localhost:9090/targets. El nuevo target debería aparecer como UP. Abre el panel Node Exporter Full, cambia la variable instance de arriba al servidor nuevo y deberías ver sus gráficas.

Uso de recursos y cuándo ampliar

Observed five-host baseline from the April 2026 test: Prometheus 250 to 350 MB, Grafana 200 MB, Caddy 40 MB, hub Node Exporter 15 to 20 MB, total hub 530 to 650 MB RAM on a 2 GB VPS with a 1.5 GB fifteen-day working set

Estas cifras salen de la prueba original de abril de 2026, en un VPS Ubuntu de 2 GB con cinco hosts monitorizados. Tómalas como referencia para esta carga de trabajo y no como una garantía de dimensionamiento para versiones más nuevas.

ComponenteRAM en reposoRAM en activo (1 host)RAM con 5 hostsDisco (retención 15 d, 5 hosts)
Prometheus~100 MB~150 MB~250-350 MB~500 MB a 1,5 GB
Grafana~150 MB~180 MB~200 MB~50 MB
Node Exporter~15 MB~20 MBno aplicainsignificante
Caddy~30 MB~40 MB~40 MBno aplica
Total del hub~300 MB~390 MB~530-650 MB~1,5 GB de conjunto de trabajo

Amplía cuando el hub empiece a quedarse corto de memoria o de margen de disco. El número de hosts por sí solo es un mal criterio de dimensionamiento, porque la cardinalidad de las series, los recolectores activados, el intervalo de recogida y la retención cambian el consumo. Para almacenamiento centralizado a largo plazo, Prometheus admite integraciones de almacenamiento remoto. VictoriaMetrics es una opción compatible con Prometheus.

Problemas habituales

Los siete problemas que más aparecen, con sus soluciones.

  1. Prometheus accesible desde internet. Un simple mapeo de puertos 9090:9090 deja a Prometheus expuesto al mundo. Solución: mantén --web.listen-address=127.0.0.1:9090 en el comando de Prometheus, como se muestra arriba. Así Prometheus solo escucha en la interfaz de loopback del host.
  2. La fuente de datos de Grafana no consigue llegar a Prometheus. Este stack usa la red del host, así que Grafana puede llegar a Prometheus en http://127.0.0.1:9090. Comprueba que Prometheus está en marcha y sigue escuchando en loopback.
  3. El panel de Node Exporter muestra «No data». Tres causas habituales. (a) Prometheus no está recogiendo el target. Revisa /targets. (b) La etiqueta job de la variable del panel no coincide con el job_name de la configuración de scrape. (c) Un cortafuegos bloquea el puerto 9100 entre el hub y el target.
  4. La contraseña de administrador de Grafana sigue siendo admin/admin en producción. Establece GF_SECURITY_ADMIN_PASSWORD desde un archivo .env antes del primer arranque. Si se te pasó, cámbiala en el primer inicio de sesión y desactiva el registro.
  5. Caddy da «ACME challenge failed». El registro DNS A todavía no se ha propagado, o el puerto 80 está bloqueado. Ejecuta ufw allow 80,443/tcp, espera a que propague el DNS y ejecuta sudo systemctl reload caddy. Usa dig +short para confirmar la propagación.
  6. El disco de Prometheus se llena. Las etiquetas de alta cardinalidad o los intervalos de recogida cortos en muchos hosts pueden llenar el volumen rápido. Vigila prometheus_tsdb_head_series y el tamaño del volumen. Mitigaciones: desactiva los recolectores de Node Exporter que no uses, alarga scrape_interval a 30s o acorta la retención.
  7. Errores de permisos en los montajes bind. Si montas un directorio del host en lugar de un volumen con nombre, el UID del contenedor (65534 para Prometheus, 472 para Grafana) necesita permiso de escritura. Los volúmenes con nombre, como en el archivo de Compose de arriba, evitan este problema.

Cuándo este stack es exagerado

Si lo único que quieres es un aviso cuando una URL deje de responder, este stack es exagerado. Uptime Kuma encaja mucho mejor y es más ligero si solo necesitas comprobaciones básicas de disponibilidad.

Preguntas frecuentes

¿Cuál es la diferencia entre Prometheus y Grafana?

Prometheus es una base de datos de series temporales: recoge métricas de los targets configurados en el intervalo que definas, las guarda en disco y responde consultas PromQL. Grafana es una capa de visualización que se conecta a Prometheus (y a muchas otras fuentes) y dibuja paneles. Casi siempre querrás ambos: Prometheus para recoger y almacenar, Grafana para mostrar.

¿Cuánta RAM necesita un montaje de Prometheus + Grafana?

Un hub de monitorización que ejecuta Prometheus, Grafana, Node Exporter y un proxy inverso en un solo VPS usa unos 300 MB de RAM en reposo y entre 530 y 650 MB cuando recoge activamente cinco hosts cada 15 segundos.

¿Puedo monitorizar varios servidores con una sola instancia de Grafana?

Sí. El patrón habitual es hub-and-spoke. Una única instancia de Prometheus en un VPS hub recoge el Node Exporter que corre en cada uno de los demás servidores que quieras vigilar. Grafana, en el hub, consulta a ese único Prometheus. El panel Node Exporter Full (ID 1860) tiene una variable instance, así que cambias de servidor desde un solo panel.

¿Cuál es el mejor panel de Grafana para Node Exporter?

Para este montaje, Node Exporter Full (panel ID 1860, de rfmoz) es una opción por defecto muy sólida. Cubre las principales métricas de host de Node Exporter y admite las variables job e instance para monitorizar varios servidores. Algunos gráficos dependen de recolectores opcionales de Node Exporter, así que un gráfico vacío no significa necesariamente que el target esté roto.

¿Cómo expongo Grafana por HTTPS?

Ejecuta Grafana enlazado a 127.0.0.1:3000 y pon delante un proxy inverso que se encargue del HTTPS. Caddy es la opción más sencilla: un Caddyfile de cuatro líneas con reverse_proxy 127.0.0.1:3000 y un bloque de dominio lo hace todo, incluida la gestión automática de los certificados TLS.

¿Son Prometheus + Grafana gratuitos para uso comercial?

Prometheus se distribuye bajo licencia Apache 2.0. Grafana OSS es AGPLv3. El uso interno y comercial de Grafana OSS sin modificar está permitido, pero modificarlo, distribuirlo u ofrecer una versión modificada a través de una red puede generar obligaciones de compartir el código bajo la AGPL. Grafana Enterprise y Grafana Cloud se rigen por condiciones comerciales aparte.

¿Cuándo debería pasar de Prometheus a VictoriaMetrics?

Plantéate VictoriaMetrics cuando una retención más larga, una alta cardinalidad de series o varias instancias de Prometheus compliquen operar la TSDB local de Prometheus dentro del presupuesto de memoria y disco de tu servidor. VictoriaMetrics puede recibir datos de Prometheus y exponer una API de consultas compatible con Prometheus, así que sirve como almacenamiento a largo plazo o como backend de métricas para Grafana. Pruébala con tu propia carga en lugar de cambiar al llegar a un umbral fijo de RAM.

Compartir

Más del blog

Sigue leyendo.

¿Listo para desplegar? Desde $2,48/mes.

Cloud independiente desde 2008. AMD EPYC, NVMe, 40 Gbps. Reembolso en 14 días.