VPSРейтинг
DevOpsФевраль 2026 · 15 мин чтения

Prometheus + Grafana на VPS: мониторинг сервера за 15 минут

Диск заполнился, сервер упал, вы узнали от пользователей — классическая история. Prometheus собирает метрики каждые 15 секунд, Grafana рисует красивые графики, а Telegram присылает алерт до того, как что-то сломается. Поднимем весь стек одним docker compose up -d.

1. Архитектура: как работает стек

Три компонента решают три разные задачи:

Node ExporterАгент на сервере

Читает метрики из /proc и /sys (CPU, RAM, диск, сеть) и отдаёт их по HTTP на порту 9100. Это просто бинарник — он ничего не хранит и не отправляет.

PrometheusБаза данных временных рядов

Каждые 15 секунд сам ходит к Node Exporter и забирает (scrape) метрики. Хранит их до 30 дней. Принимает PromQL-запросы от Grafana.

GrafanaВизуализация и алерты

Подключается к Prometheus как к источнику данных, строит дашборды и отправляет уведомления в Telegram, Slack или email при срабатывании алертов.

Поток данных

Node Exporter
:9100/metrics
scrape каждые 15с
Prometheus
:9090
PromQL-запросы
Grafana
:3000

Требования к VPS

Для мониторинга 1–3 серверов: 1 ГБ RAM минимум, 2 ГБ комфортно. Диск: ~5 ГБ на 30 дней метрик одного сервера. Виртуализация — только KVM (Docker не работает на OpenVZ).

2. Установка через Docker Compose

Если Docker ещё не установлен — сначала установите его. Подробнее в статье Docker Compose на VPS. Иначе сразу создаём структуру проекта.

Создать директорию проекта
mkdir -p ~/monitoring && cd ~/monitoring

Файл .env — пароль Grafana

~/monitoring/.env
# Пароль администратора Grafana
GRAFANA_ADMIN_PASSWORD=ЗАМЕНИТЕ_НА_СЛОЖНЫЙ_ПАРОЛЬ

# Замените на ваш домен (или оставьте для доступа по IP)
GRAFANA_ROOT_URL=https://grafana.example.com

docker-compose.yml

~/monitoring/docker-compose.yml
version: "3.9"

services:
  # ── Prometheus: сбор и хранение метрик ───────────────────
  prometheus:
    image: prom/prometheus:v2.54.1
    container_name: prometheus
    restart: unless-stopped
    ports:
      - "127.0.0.1:9090:9090"   # только localhost
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'   # хранить 30 дней
      - '--storage.tsdb.path=/prometheus'
    extra_hosts:
      - "host.docker.internal:host-gateway"   # доступ к хосту

  # ── Grafana: дашборды и алерты ────────────────────────────
  grafana:
    image: grafana/grafana:11.4.0
    container_name: grafana
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"   # только localhost
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_SERVER_ROOT_URL=${GRAFANA_ROOT_URL}
    depends_on:
      - prometheus

  # ── Node Exporter: метрики хоста ─────────────────────────
  node-exporter:
    image: prom/node-exporter:v1.8.2
    container_name: node-exporter
    restart: unless-stopped
    network_mode: host   # нужен для доступа к /proc и /sys хоста
    pid: host
    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)($$|/)'

volumes:
  prometheus_data:
  grafana_data:

Почему network_mode: host у Node Exporter?

Node Exporter должен читать метрики реального хоста, а не контейнера. При network_mode: host он слушает напрямую на порту 9100 хоста. Prometheus обращается к нему через псевдоним host.docker.internal, который Docker резолвит в IP шлюза (172.17.0.1 или аналог).

3. Настройка Prometheus

Создайте файл конфигурации в той же директории:

~/monitoring/prometheus.yml
global:
  scrape_interval: 15s       # как часто собирать метрики
  evaluation_interval: 15s   # как часто проверять правила алертов

scrape_configs:
  # Prometheus мониторит сам себя
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # Метрики этого сервера
  - job_name: 'node'
    static_configs:
      - targets: ['host.docker.internal:9100']
        labels:
          instance: 'main-server'   # замените на имя вашего сервера

После изменения prometheus.yml перезагрузите конфиг без перезапуска контейнера:

Горячая перезагрузка конфига Prometheus
curl -X POST http://localhost:9090/-/reload

4. Запуск и вход в Grafana

Запустить стек
cd ~/monitoring

# Запустить все сервисы в фоне
docker compose up -d

# Проверить статус
docker compose ps

# Убедиться, что Node Exporter отдаёт метрики
curl http://localhost:9100/metrics | head -20

Через 30–60 секунд Grafana будет доступна. Пока Nginx ещё не настроен, проверьте через SSH-туннель с локального компьютера:

SSH-туннель для временного доступа (на локальном компьютере)
# Туннель: localhost:3000 → сервер:3000
ssh -L 3000:127.0.0.1:3000 user@YOUR_SERVER_IP

# Теперь откройте в браузере: http://localhost:3000

Первый вход в Grafana

  1. 1Откройте http://localhost:3000
  2. 2Логин: admin, пароль: тот, что задали в .env
  3. 3Connections → Data sources → Add data source → Prometheus
  4. 4URL: http://prometheus:9090 → Save & test

5. Импорт готового дашборда

Не нужно строить графики вручную — на grafana.com/grafana/dashboards тысячи готовых дашбордов. Для Node Exporter лучший — Node Exporter Full (ID: 1860). Он показывает всё: CPU по ядрам, RAM, диски, сеть, температуру.

Как импортировать дашборд

  1. 1В Grafana: Dashboards → Import
  2. 2В поле "Import via grafana.com" введите 1860 → Load
  3. 3Выберите Prometheus как Data Source → Import
  4. 4Готово — сразу увидите все метрики сервера
ID 1860Node Exporter Full

Полный мониторинг Linux-сервера: CPU, RAM, диск, сеть. 20+ панелей.

ID 3662Prometheus 2.0 Stats

Мониторинг самого Prometheus: scrape-лаги, размер хранилища, производительность.

ID 13659Node Exporter Quickstart

Упрощённый вариант для тех, кому нужен минимум без лишнего.

ID 405Node Exporter Server Metrics

Классический дашборд с акцентом на дисковые метрики.

6. Nginx и SSL для Grafana

Grafana слушает только на 127.0.0.1:3000 — наружу не доступна. Настроим Nginx как прокси с SSL.

Установка Nginx и Certbot (если не установлены)
apt install nginx certbot python3-certbot-nginx -y
/etc/nginx/sites-available/grafana
server {
    listen 80;
    server_name grafana.example.com;

    location / {
        proxy_pass         http://127.0.0.1:3000;
        proxy_http_version 1.1;

        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;

        # WebSocket — нужен для live-обновления дашбордов
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
Активировать и получить SSL
ln -s /etc/nginx/sites-available/grafana /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

# SSL через Let's Encrypt
certbot --nginx -d grafana.example.com

Защита Prometheus

У Prometheus нет встроенной аутентификации. Если хотите веб-интерфейс Prometheus снаружи — добавьте HTTP Basic Auth в Nginx. Проще всего держать Prometheus только на localhost и работать с ним через SSH-туннель или Grafana.

7. Алерты в Telegram

Grafana Alerting (начиная с версии 8) умеет отправлять уведомления без сторонних инструментов. Настройка займёт 5 минут.

Шаг 1: создать Telegram-бота

  1. 1. Откройте @BotFather в Telegram → /newbot
  2. 2. Введите имя бота и username (должен заканчиваться на bot)
  3. 3. Сохраните токен вида 1234567890:AAF...
  4. 4. Напишите боту любое сообщение (иначе бот не сможет отправлять вам)

Шаг 2: получить Chat ID

Получить Chat ID (замените TOKEN на реальный)
curl -s "https://api.telegram.org/botTOKEN/getUpdates" | python3 -c "
import sys, json
data = json.load(sys.stdin)
print(data['result'][0]['message']['chat']['id'])
"

Если в группе — добавьте бота в группу, напишите там что-нибудь, затем выполните команду выше. Chat ID группы будет отрицательным числом.

Шаг 3: настроить Contact Point в Grafana

  1. 1. Alerting → Contact points → Add contact point
  2. 2. Name: Telegram, Integration: Telegram
  3. 3. Bot API Token: вставьте токен
  4. 4. Chat ID: вставьте числовой ID
  5. 5. Test → Save contact point

Шаг 4: создать правило алерта

Пример: алерт при загрузке CPU выше 85% на протяжении 5 минут.

  1. 1. Alerting → Alert rules → New alert rule
  2. 2. Data source: Prometheus, Query A:
PromQL для загрузки CPU (вставить в query A)
100 - (
  avg by(instance) (
    rate(node_cpu_seconds_total{mode="idle"}[5m])
  ) * 100
)
  1. 3. Reduce: Last, Threshold: IS ABOVE 85
  2. 4. Evaluation: каждые 1m, Pending period: 5m
  3. 5. Contact point: Telegram
  4. 6. Summary: "Высокая загрузка CPU на {{ $labels.instance }}"
  5. 7. Save rule

RAM > 90%

(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

Threshold: > 90

Диск > 85%

100 - ((node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100)

Threshold: > 85

Сервер недоступен

up{job="node"}

Threshold: == 0

8. Мониторинг нескольких серверов

Prometheus и Grafana живут на одном сервере. На каждом дополнительном сервере нужно установить только Node Exporter — лёгкий бинарник без зависимостей.

Установка Node Exporter без Docker (на втором сервере)

Второй сервер: установка Node Exporter как systemd-сервис
# Скачать актуальный бинарник
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz

# Распаковать и установить
tar xzf node_exporter-*.tar.gz
cp node_exporter-*/node_exporter /usr/local/bin/
useradd -rs /bin/false node_exporter

# Создать systemd-юнит
cat > /etc/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Node Exporter
After=network.target

[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now node_exporter

# Проверить
curl http://localhost:9100/metrics | grep node_uname

Закрыть порт 9100 — только для вашего Prometheus

Второй сервер: UFW — открыть 9100 только для Prometheus-сервера
# Замените IP на адрес вашего Prometheus-сервера
ufw allow from PROMETHEUS_SERVER_IP to any port 9100
ufw deny 9100

Добавить второй сервер в prometheus.yml

~/monitoring/prometheus.yml — добавить targets
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node'
    static_configs:
      - targets:
          - 'host.docker.internal:9100'   # этот сервер
          - '1.2.3.4:9100'               # второй сервер
          - '5.6.7.8:9100'               # третий сервер
        labels:
          env: 'production'

Применить изменения без перезапуска:

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

После этого в Grafana переключайте серверы через переменную instance — дашборд Node Exporter Full поддерживает это из коробки.

Метки для удобной фильтрации

Добавляйте метки к каждому серверу, чтобы различать их в Grafana:

      - targets: ['1.2.3.4:9100']
        labels:
          instance: 'server-2-frankfurt'
          role: 'web'

9. Шпаргалка по PromQL

Эти запросы удобно вставлять в Grafana (Add panel → Query) или проверять прямо в интерфейсе Prometheus (/graph).

МетрикаPromQL-запрос
Загрузка CPU, %100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
Использование RAM, %(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
Свободный диск, GBnode_filesystem_avail_bytes{mountpoint="/"} / 1024^3
Диск занят, %100 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"} * 100)
Входящий трафик, MB/srate(node_network_receive_bytes_total{device!="lo"}[5m]) / 1024^2
Исходящий трафик, MB/srate(node_network_transmit_bytes_total{device!="lo"}[5m]) / 1024^2
Uptime, дниnode_time_seconds - node_boot_time_seconds) / 86400
Нагрузка (Load Average 1m)node_load1
Сервер onlineup{job="node"}

Полезные команды управления стеком

# Статус всех сервисов
docker compose -f ~/monitoring/docker-compose.yml ps

# Логи Prometheus
docker compose -f ~/monitoring/docker-compose.yml logs -f prometheus

# Горячая перезагрузка конфига Prometheus
curl -X POST http://localhost:9090/-/reload

# Проверить, что Prometheus видит все targets
curl -s http://localhost:9090/api/v1/targets | python3 -m json.tool | grep health

# Место на диске под метрики Prometheus
du -sh /var/lib/docker/volumes/monitoring_prometheus_data

# Бэкап volumes
docker run --rm \
  -v monitoring_prometheus_data:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/prometheus-$(date +%Y%m%d).tar.gz /data

Частые вопросы

Нужен VPS для мониторинга? Смотрите наш рейтинг

Топ VPS хостингов →

Смотрите также