Servidores

Monitoreo de servidores Linux con Grafana y Prometheus

Monitoreo de servidores Linux: Grafana + Prometheus desde cero

Si tienes un servidor (Nextcloud, Pi-hole, una app, lo que sea), necesitas saber qué está pasando dentro. CPU, RAM, disco, red, servicios caídos. Grafana + Prometheus es el estándar de la industria para esto, y montarlo es más fácil de lo que parece.

—

TL;DR — Lo que vas a tener al final

  • Tiempo de setup: 1.5-2 horas para stack funcional.
  • Requisitos: Server con 2+ GB RAM, Docker, root.
  • Resultado: Stack Prometheus + Grafana + Alertmanager con alertas a Telegram.
  • Troubleshooting: promtool query, métricas de exporters, log de alertmanager.

¿Qué es cada cosa?

Prometheus: base de datos de series temporales que recopila métricas de tus servidores cada N segundos. Las guarda y las expone para consultas.

Grafana: panel visual que consulta Prometheus y muestra gráficos bonitos. Soporta alertas, dashboards compartibles, múltiples data sources.

Node Exporter: agente que instalas en cada servidor a monitorear. Lee /proc, /sys y métricas del sistema, y las expone en formato Prometheus.

Alertmanager: recibe alertas de Prometheus y las enruta (email, Slack, Telegram, etc.).

El flujo: Node Exporter → Prometheus → Grafana → tu navegador.

—

Lo que necesitas

  • Un servidor Linux (donde correrá Prometheus + Grafana).
  • Uno o más servidores a monitorear (puede ser el mismo).
  • Docker + Docker Compose instalados.
  • 10-30 minutos.

—

Paso 1: Crear el directorio del stack

Vamos a centralizar todo el stack (configs de Prometheus, configs de Alertmanager, datos persistentes de Grafana) en un solo directorio bajo tu home. Así tienes un solo lugar para hacer backup, restaurar o migrar a otro servidor. Las subcarpetas prometheus/ y grafana/ son convenciones — Prometheus las monta con bind-mounts en el compose, y los volúmenes nombrados (prometheus_data, grafana_data) persisten incluso si borrás este directorio.


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

Si en algún momento necesitas mover el stack a otro server, basta copiar ~/monitoring/ y volver a correr docker compose up -d — los volúmenes nombrados se exportan con docker volume inspect y se migran aparte. Si quieres evitar este paso extra desde el principio, definí los volúmenes con paths absolutos en el docker-compose.yml (./prometheus-data:/prometheus).

—

Paso 2: Configurar Prometheus

Crea prometheus/prometheus.yml:


global:
  scrape_interval: 15s
  evaluation_interval: 15s
# Configuración de Alertmanager
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']
# Reglas de alerta
rule_files:
  - "alerts.yml"
# Qué métricas scrapeamos
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']
  # Si tienes otros servidores en la LAN, agregas aquí:
  # - job_name: 'node-servidor-2'
  #   static_configs:
  #     - targets: ['192.168.1.50:9100']

Crea prometheus/alerts.yml:


groups:
  - name: sistema
    rules:
      # Disco casi lleno
      - alert: DiscoCasiLleno
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 < 10
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Disco casi lleno en {{ $labels.instance }}"
          description: "Menos del 10% libre en /"
      # CPU alta
      - alert: CPUAlta
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "CPU > 80% en {{ $labels.instance }}"
      # Memoria alta
      - alert: MemoriaAlta
        expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Memoria > 90% en {{ $labels.instance }}"
      # Servidor caído (no responde)
      - alert: ServidorCaido
        expr: up == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.instance }} no responde"

—

Paso 3: Configurar Alertmanager

Crea alertmanager/alertmanager.yml:


global:
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: '[email protected]'
  smtp_auth_username: '[email protected]'
  smtp_auth_password: 'tu-app-password-de-gmail'
route:
  receiver: 'email-default'
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
receivers:
  - name: 'email-default'
    email_configs:
      - to: '[email protected]'
        send_resolved: true

Para Telegram, agrega otra ruta:


receivers:
  - name: 'telegram'
    telegram_configs:
      - bot_token: 'TU_BOT_TOKEN'
        chat_id: TU_CHAT_ID
        send_resolved: true
route:
  receiver: 'telegram'
  routes:
    - match:
        severity: critical
      receiver: 'email-default'

—

Paso 4: Crear el docker-compose.yml


services:
  prometheus:
    image: prom/prometheus:v2.54.1  # Pinneado: latest se rompe entre versiones; v2.54.1 es estable 2024
    container_name: prometheus
    restart: always
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./prometheus/alerts.yml:/etc/prometheus/alerts.yml:ro
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'
      - '--storage.tsdb.path=/prometheus'
  alertmanager:
    image: prom/alertmanager:v0.27.0  # Pinneado
    container_name: alertmanager
    restart: always
    ports:
      - "9093:9093"
    volumes:
      - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
  node-exporter:
    image: prom/node-exporter:v1.8.2  # Pinneado
    container_name: node-exporter
    restart: always
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--path.rootfs=/rootfs'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)"
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--path.rootfs=/rootfs'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: always
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_USER: admin
      GF_SECURITY_ADMIN_PASSWORD: cambia-esto-ahora
      GF_USERS_ALLOW_SIGN_UP: "false"
    volumes:
      - grafana_data:/var/lib/grafana
volumes:
  prometheus_data:
  grafana_data:

Arranca todo:

docker compose up -d (con guion y espacio, no docker-compose) lee el docker-compose.yml del directorio actual, descarga las imágenes que faltan, crea la red interna monitoring_default y arranca los cuatro servicios en background (-d). El down se hace con docker compose down (conserva volúmenes) o docker compose down -v (borra volúmenes — peligroso en producción).


docker compose up -d
docker compose ps

Espera 30 segundos y verifica:

/-/healthy es el endpoint de health check que Prometheus expone en su puerto 9090; devuelve 200 OK cuando el servidor está listo para servir queries. /api/health es el equivalente de Grafana, devuelve {"database": "ok"} cuando SQLite y plugins están inicializados. Si curl no devuelve 200 después de 30 segundos, revisa docker compose logs prometheus y docker compose logs grafana para encontrar el error.


# Prometheus debe responder en 9090
curl http://localhost:9090/-/healthy
# Grafana debe responder en 3000
curl http://localhost:3000/api/health

Troubleshooting: si curl da Connection refused, el puerto no está publicado al host o el contenedor está en crash loop. verifica con docker compose ps que todos los servicios están Up (healthy) (no Up ni Restarting). Si Prometheus queda en Restarting, mira docker compose logs prometheus — causas típicas: error de sintaxis en prometheus.yml (YAML es estricto con indentación), o el volumen prometheus_data quedó corrupto de un run anterior (borrá el volumen con docker compose down -v y arrancá de nuevo). Si Grafana arranca pero el healthcheck falla, suele ser porque no terminó de inicializar SQLite — espera 60 segundos más.

—

Paso 5: Configurar Grafana

Abre http://tu-servidor:3000 en el navegador. Login con admin / cambia-esto-ahora (te pedirá cambiar la contraseña).

Agregar Prometheus como data source

1. Click en el ícono de engranaje (esquina inferior izquierda) → Data Sources.

2. Click Add data source.

3. Selecciona Prometheus.

4. URL: http://prometheus:9090 (nombre del servicio Docker).

5. Click Save & Test. Debe decir “Data source is working”.

Importar dashboard de Node Exporter

La comunidad mantiene dashboards oficiales. El más usado es el ID 1860 (Node Exporter Full):

1. Click en el ícono “+” → Import dashboard.

2. Pega el ID 1860.

3. Selecciona tu data source de Prometheus.

4. Click Import.

Tendrás un dashboard con 50+ paneles: CPU, RAM, disco, red, load average, file descriptors, etc.

—

Paso 6: Configurar alertas desde Grafana (opcional, más amigable)

Grafana puede gestionar alertas sin tocar Prometheus. Ve a Alerting → Alert rules y crea:


# Ejemplo: alerta de CPU alta
Query: 100 - (avg by(host) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
Condition: > 80
For: 5m
Notification: email-admin

Más visual que editar YAML. Pero las alertas en Prometheus (las del alerts.yml) son más potentes para reglas complejas.

—

Paso 7: Monitorear múltiples servidores

Si quieres monitorear otros servidores además del principal, instala Node Exporter en cada uno:

prometheus-node-exporter es el paquete Debian/Ubuntu oficial del exporter de Prometheus (binario escrito en Go que expone métricas del sistema en /metrics formato Prometheus). El servicio systemd escucha en 9100 y lee /proc, /sys y selectores de hardware sin necesidad de configuración adicional.


# En cada servidor Linux a monitorear
sudo apt install -y prometheus-node-exporter
sudo systemctl enable --now prometheus-node-exporter

Por defecto escucha en 9100. Verifica:

curl localhost:9100/metrics devuelve cientos de líneas en formato nombre{labels} valor, una por cada métrica expuesta (CPU, memoria, red, FS, etc.). Si no devuelve nada, el servicio no está corriendo (systemctl status prometheus-node-exporter) o el puerto está bloqueado por firewall local.


curl http://localhost:9100/metrics | head -5
# Debe devolver métricas en texto plano

Ahora edita prometheus/prometheus.yml y agrega el servidor:


scrape_configs:
  - job_name: 'node-servidor-2'
    static_configs:
      - targets: ['192.168.1.50:9100']
        labels:
          host: servidor-web
  - job_name: 'node-servidor-3'
    static_configs:
      - targets: ['192.168.1.51:9100']
        labels:
          host: servidor-db

Reinicia Prometheus:

docker compose restart prometheus envía SIGTERM al contenedor principal y lo vuelve a levantar; el healthcheck de Node Exporter tardará 15 segundos en reflejarse en el dashboard. Si no aparece, revisa curl http://prometheus:9090/api/v1/targets desde dentro del contenedor — state: up significa que el scrape funciona, state: down muestra el error (típicamente connection refused o i/o timeout).


docker compose restart prometheus

Importante: si los servidores están detrás de NAT o firewall, usa Pushgateway o un túnel WireGuard/Tailscale para conectar.

Troubleshooting: si después del restart Prometheus no ve el nuevo target, casi siempre es por DNS o firewall. Los nombres como node-servidor-2 no resuelven: usa la IP directa (192.168.1.50:9100). Si la IP es privada y el Prometheus está en otro segmento, el firewall del server destino (o iptables) está bloqueando el :9100. verifica con nc -zv 192.168.1.50 9100 desde el server de Prometheus. Para servidores detrás de NAT estricto sin IP pública, las opciones son: (a) Pushgateway (el server empuja métricas a un endpoint público), (b) tunnel inverso SSH (ssh -R 9100:localhost:9100), o (c) mesh VPN (Tailscale, WireGuard) que pone a todos los nodos en una red privada virtual.

—

Paso 8: Configurar notificaciones reales

Telegram (recomendado, gratis, instantáneo)

1. Habla con @BotFather en Telegram, crea un bot, obtén el token.

2. Envía un mensaje a tu bot, luego ve a https://api.telegram.org/botTU_TOKEN/getUpdates para obtener tu chat_id.

3. Edita alertmanager/alertmanager.yml:


receivers:
  - name: 'telegram'
    telegram_configs:
      - bot_token: '123456:ABC-DEF...'
        chat_id: 987654321
        send_resolved: true
        message: |
          {{ .CommonAnnotations.summary }}
          {{ .CommonAnnotations.description }}

4. Reinicia Alertmanager: docker compose restart alertmanager.

Discord / Slack / PagerDuty

Soportados nativamente. Cambia el receiver:


# Slack
slack_configs:
  - api_url: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX'
    channel: '#alertas'
# Discord (via webhook)
webhook_configs:
  - url: 'https://discord.com/api/webhooks/...'

—

Dashboards útiles que vale la pena importar

ID Nombre Para qué sirve
1860 Node Exporter Full Métricas completas del sistema
893 Docker Container (cAdvisor) Métricas de contenedores Docker
315 Prometheus Stats Estado de Prometheus mismo
6417 Blackbox Exporter Uptime de sitios web

Para importar: + → Import → pega el ID.

—

Monitorear Docker containers

¿Quieres ver CPU/RAM de cada contenedor? Agrega cAdvisor:


  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    container_name: cadvisor
    restart: always
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro

Y en Prometheus:


  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

Dashboard recomendado: ID 893.

—

Seguridad: protege tu stack

Por defecto, todo está expuesto. En producción:


services:
  grafana:
    ports:
      - "127.0.0.1:3000:3000"  # Solo accesible desde localhost
  prometheus:
    ports:
      - "127.0.0.1:9090:9090"

Para acceder desde fuera, usa Nginx como reverse proxy con HTTPS (igual que en la guía de Nextcloud), o WireGuard/Tailscale para acceder solo tú.

—

Retención de datos

Por defecto Prometheus guarda 30 días (lo configuramos con --storage.tsdb.retention.time=30d). Para más tiempo, usa Thanos o Cortex. Para la mayoría, 30 días es suficiente.

Las métricas se guardan en el volumen Docker prometheus_data. Verifica espacio:

docker system df reporta el espacio total usado por imágenes, contenedores y volúmenes en /var/lib/docker. Si prometheus_data está cerca del límite del disco, los scrapes empiezan a fallar con errores storage out of space — Prometheus se recupera solo cuando se libera espacio, pero pierde capacidad de retención.


docker system df

Troubleshooting: si Prometheus está cerca del límite de retención, puedes bajarla temporalmente sin tocar el docker-compose.yml pasando --storage.tsdb.retention.time=15d como override (docker compose up -d con variable de entorno PROMETHEUS_ARGS). O limpiá manualmente con docker exec prometheus promtool tsdb compact (compacta bloques sin borrar) o docker exec prometheus rm -rf /prometheus/chunks_head/* (acción drástica: borra el bloque WAL en memoria y todo lo no persistido — solo si sabes que el repo ya está commiteado). El flag prometheus_tsdb_head_series expuesto en /metrics muestra cuántas series tienes activas: si pasa de 1 millón, es hora de federar o reducir la cardinalidad con metric_relabel_configs.

—

Alternativas más simples

Si esto te parece demasiado, considera:

  • Netdata: un solo binario, UI web automática, casi cero configuración. Ideal para un solo servidor.
  • Glances: CLI con UI web. Más simple pero menos potente.
  • Uptime Kuma: solo para uptime de servicios (¿está caído mi sitio?), no métricas.
  • Prometheus + Grafana en managed: Grafana Cloud tiene free tier para 10k series.

Mi recomendación: si tienes 1-3 servidores, empieza con Netdata. Si tienes más o quieres alertas, Prometheus + Grafana.

—

Próximos pasos

Con Grafana + Prometheus puedes:

1. Monitorear tu sitio web con Blackbox Exporter (uptime, latencia).

2. Tracking de deployments (rollouts vs métricas).

3. Crear SLOs (Service Level Objectives).

4. Integrar con Loki para logs.

5. Integrar con Tempo para tracing distribuido.

La stack completa (Prometheus + Grafana + Loki + Tempo) se llama Grafana Stack o PLG y es el reemplazo open source de soluciones como Datadog o New Relic.

¿Próximo post? Estaba pensando en Netdata para monitoreo rápido de un solo servidor o Blackbox Exporter para monitorear uptime de sitios web. Déjamelo en comentarios.

Si te sirvió, suscríbete al blog para no perderte los siguientes tutoriales.

Preguntas frecuentes

¿Por qué Monitoreo de servidores Linux con Grafana y Prometheus es relevante para sysadmins Linux?

Forma parte del flujo diario de administración. Los conceptos explicados se aplican directamente a servidores en producción y resuelven problemas reales que enfrentan sysadmins hispanohablantes.

¿Qué necesito para empezar con Monitoreo de servidores Linux con?

Distribución Linux actualizada (Debian, Ubuntu, RHEL, Fedora o Arch), acceso root, y conexión a internet. Para producción: entorno de staging separado antes de aplicar cambios.

¿Cuáles son los errores más comunes con Monitoreo de servidores Linux con?

Los tres más frecuentes: (1) saltar la lectura de logs, (2) aplicar cambios directos en producción sin probar, (3) olvidar permisos y ownership. La documentación y un plan de rollback siempre.

¿Cuándo usar Monitoreo de servidores Linux con y cuándo una alternativa?

Esta solución es ideal para el caso descrito. Alternativas como Docker, Ansible o configuración manual pueden ser mejores según contexto: portabilidad, escala y reproducibilidad son los factores clave.

¿Cómo migro desde una configuración previa a Monitoreo de servidores Linux con?

Documentar el estado actual, probar la nueva configuración en staging, validar funcionalmente, y aplicar en producción con rollback plan listo. Los posts de SoyLinux incluyen troubleshooting para los problemas más comunes.

Lee también

Alfonso Moreno | Sysadmin Senior

Soy Alfonso, sysadmin senior con RHCE y más de 10 años administrando sistemas Linux para empresas y proyectos personales. Me especializo en infraestructura, redes, virtualización, monitoring, automation y self-hosting. Sobre SoyLinux.com SoyLinux.com es un blog técnico en español sobre Linux, software libre y self-hosting. Lo mantengo en mi tiempo libre. Áreas de expertise - Linux server administration: RHEL, CentOS, Rocky, Alma, Fedora, Debian, Ubuntu - Network services: Postfix, BIND, Samba, NFS, Squid - Virtualización y containers: KVM, Proxmox, Docker, Podman - Monitoring: Prometheus, Grafana, Zabbix - Automation: Ansible, Bash scripting - Self-hosting: Vaultwarden, Nextcloud, Jellyfin, Immich, Homelab Contacto - Email: [email protected]

8 thoughts on “Monitoreo de servidores Linux con Grafana y Prometheus”

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

11074 Nextcloud Métricas específicas de Nextcloud