
Всем привет! Меня зовут Анатолий Зотов, я системный архитектор SOC в RED Security. Как центр мониторинга и реагирования на кибератаки, мы должны быстро и внятно видеть, что происходит с железом и ОС на хостах: не кончается ли место на диске, не улетела ли память и не уперся ли CPU в потолок. Как это реализовать, да еще и безопасно?
Когда мы только приступали к задаче, первой мыслью, конечно, был Zabbix, как и у половины планеты. Но у нас никто не горел желанием поднимать еще одну систему, раскатывать агенты, подбирать шаблоны и разбираться с нюансами. Времени, как обычно, не завезли. А вот Grafana у нас уже была, поэтому я подумал — а что, если просто использовать то, что уже есть? Так я и наткнулся на связку «node_exporter → Prometheus → Grafana».
Эта статья для тех, кто хочет быстро начать мониторить хосты и не готов тратить вечность на внедрение тяжелой системы, особенно если Grafana уже живет в вашей инфраструктуре. Если Grafana и Prometheus у вас еще нет, то дополнительно расскажу быстрый старт через Docker Compose.
Гайд будет о том, как:
поставить на каждый хост node_exporter (один бинарник);
подключить Prometheus, который собирает метрики с хостов и хранит их в своей TSDB;
использовать Grafana для визуализации и алертов;
опционально включить TLS или mTLS, чтобы метрики не были доступны «всем, кто нашел порт 9100».
Подойдет или не подойдет, вот в чем вопрос…
Сразу отмечу границы связки «node_exporter → Prometheus → Grafana». Она хорошо зайдет, если вам нужно закрыть базовые метрики хостов: CPU, RAM, диск и файловые системы, сеть. Также подойдет, если хочется быстро получить понятную картину по инфраструктуре и у вас уже есть Grafana с Prometheus или их легко поднять.
В наличии должны быть:
Linux + systemd на целевых хостах;
OpenSSL (на хостах и на машине, где выпускаете сертификаты);
сетевой доступ Prometheus → хосты по 9100/tcp;
желательно, чтобы firewall разрешал 9100 только от Prometheus.
Но как единственная система мониторинга она не потянет, если вам нужны сложные проверки приложений и бизнес-логики из «коробки», автоматический discovery всего без настройки или централизованное управление конфигами агентов без вашей автоматизации. Придется либо дополнять стек, либо смотреть в сторону более «тяжелых» решений.
Если решение вам подходит и требования учтены — можно идти дальше.
Схема и поток данных
В связке есть три основных компонента:
на каждом Linux-хосте работает node_exporter — он собирает системные метрики и отдает их по HTTP или HTTPS;
Prometheus регулярно ходит к хостам на эндпоинт /metrics, забирает данные по scrape-модели и сохраняет их в своей TSDB;
Grafana подключается к Prometheus и отвечает за визуализацию, дашборды и алертинг.

Если нужно шифрование и взаимная аутентификация, добавляется четвертый элемент — CA (центр сертификации), где выпускаются и управляются сертификаты для компонентов.
После можно выбрать уровень защиты канала в зависимости от требований и того, сколько времени вы готовы потратить на настройку. Тут три варианта:
HTTP — быстрый старт и минимум действий, но метрики могут утечь, если порт окажется доступен не там, где планировалось;
HTTPS c TLS — трафик уже зашифрован, однако любой, кто оказался внутри сети, все еще сможет забирать метрики, если нет дополнительной авторизации;
HTTPS c mTLS — здесь node_exporter отдает метрики только для клиентов с сертификатом, подписанным вашим CA. Для внутренней инфраструктуры очень практично.
В статье покажу вариант с mTLS (рекомендую), а также дам короткую инструкцию «как сделать HTTP», если вам нужна максимально быстрая установка без лишней возни. Перейдем к главному.
Шаг 0. Скачиваем node_exporter
Начнем с установки самого node_exporter. Актуальные релизы лежат на GitHub в репозитории Prometheus. По установке все стандартно: выбираем нужную версию и архитектуру под ваш хост, скачиваем архив, распаковываем и кладем бинарник в /usr/local/bin. Ниже покажу пример для linux-amd64:
# пример: linux-amd64 VERSION="1.10.2" ARCH="linux-amd64" curl -L -o /tmp/node_exporter.tar.gz "https://github.com/prometheus/node_exporter/releases/download/v${VERSION}/node_exporter-${VERSION}.${ARCH}.tar.gz" tar -xzf /tmp/node_exporter.tar.gz -C /tmp sudo install -m 0755 "/tmp/node_exporter-${VERSION}.${ARCH}/node_exporter" /usr/local/bin/node_exporter rm -rf "/tmp/node_exporter-${VERSION}.${ARCH}" /tmp/node_exporter.tar.gz
Если у хостов нет выхода в интернет — схема та же, просто скачайте архив на сервере с доступом наружу и перенесите его внутрь контура любым привычным способом.
Шаг 1. Готовим пользователя и каталоги
Дальше создаем отдельного системного пользователя под сервис: делаем группу, пользователя без shell-доступа и домашнего каталога, затем готовим директорию для конфигурации:
sudo groupadd -r node_exporter sudo useradd -r -s /usr/sbin/nologin -g node_exporter -M node_exporter sudo mkdir -p /etc/node_exporter sudo chown root:node_exporter /etc/node_exporter sudo chmod 750 /etc/node_exporter
Так мы ограничиваем права: конфигурацию может менять только root, а сам сервис получает доступ через свою группу.
Сам бинарник лучше оставить владельцем root:root, чтобы сервисный пользователь не мог его подменить. Это простой шаг, который закрывает лишний вектор риска.
sudo chown root:root /usr/local/bin/node_exporter sudo chmod 755 /usr/local/bin/node_exporter
Шаг 2. Настраиваем CA и сертификаты (TLS/mTLS)
Если шифрование вам не нужно, можно сразу переходить к настройке systemd и запуску в HTTP-режиме.
Самый простой HTTP-режим без TLS (опционально)
Если задача — запустить мониторинг максимально быстро и без шифрования, можно обойтись без --web.config.file и включить обычный HTTP. В systemd это будет выглядит так:
*** ExecStart=/usr/local/bin/node_exporter --web.listen-address=:9100 ***
В таком режиме обязательно ограничьте доступ к порту 9100 через firewall и разрешите подключения только со стороны Prometheus — иначе метрики будут доступны всем, кто видит этот хост в сети.
Однако я рекомендую сценарий с mTLS, когда мы шифруем канал и добавляем взаимную аутентификацию.
Вариант с TLS/mTLS
2.1. Создаем свой CA-сертификат и ключ (один раз)
На контроллере CA или админ-хосте генерируем корневой ключ и самоподписанный сертификат центра сертификации:
На контроллере/админ-хосте:
openssl genrsa -out ca.key 4096 chmod 600 ca.key openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -subj "/C=XX/ST=State/L=City/O=Example/OU=Monitoring/CN=PromCA" -out ca.crt chmod 644 ca.crt
Важно: приватный ключ ca.key никуда за пределы контроллера не уходит. На хостах нужен только публичный ca.crt.
2.2. Делаем сертификат для node_exporter (на каждый хост)
Теперь для каждого хоста выпускаем отдельный серверный сертификат. Сначала на самом хосте генерируем приватный ключ и CSR (не забудьте указать реальные DNS-имя и IP-адрес):
sudo openssl genrsa -out /etc/node_exporter/node_exporter.key 4096 sudo chmod 600 /etc/node_exporter/node_exporter.key HOST_FQDN="$(hostname -f)" # если делаете на контроллере замените HOST_IP="192.0.2.10" # пример, замените sudo openssl req -new -key /etc/node_exporter/node_exporter.key -subj "/CN=${HOST_FQDN}" -addext "subjectAltName = DNS:${HOST_FQDN}, IP:${HOST_IP}" -addext "extendedKeyUsage = serverAuth" -out /etc/node_exporter/node_exporter.csr
CSR переносим на контроллер и подписываем нашим CA:
openssl x509 -req -in node_exporter.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out node_exporter.crt -days 3650 -sha256 -copy_extensions copy
После подписи на хосте должно остаться три файла:
/etc/node_exporter/node_exporter.key— приватный ключ (он уже создан и остаётся на хосте);/etc/node_exporter/node_exporter.crt— серверный сертификат;/etc/node_exporter/ca.crt— публичный сертификат вашего CA.
2.3. Выпускаем клиентский сертификат Prometheus (нужен для mTLS)
Для mTLS Prometheus тоже должен предъявлять сертификат при подключении к node_exporter. Для этого выпускаем клиентский сертификат с extendedKeyUsage=clientAuth . На контроллере:
openssl genrsa -out prometheus.key 4096 chmod 600 prometheus.key openssl req -new -key prometheus.key -subj "/CN=prometheus" -out prometheus.csr cat >prometheus_ext.cnf <<'EOF' extendedKeyUsage=clientAuth keyUsage=digitalSignature EOF openssl x509 -req -in prometheus.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out prometheus.crt -days 3650 -sha256 -extfile prometheus_ext.cnf rm -f prometheus_ext.cnf
Эти файлы затем понадобятся в scrape_config Prometheus: ca.crt, prometheus.crt, prometheus.key. На этом этапе у нас подготовленно все необходимое для защищённого соединения между Prometheus и node_exporter.
2.4 Включаем TLS/mTLS в node_exporter
Теперь осталось включить TLS на стороне node_exporter и, при необходимости, потребовать клиентский сертификат от Prometheus для mTLS. Для этого создаём конфигурационный файл /etc/node_exporter/web-config.yml:
tls_server_config: cert_file: "/etc/node_exporter/node_exporter.crt" key_file: "/etc/node_exporter/node_exporter.key" # Ниже как раз наш mTLS: требуем клиентский сертификат Prometheus, # если node_exporter не будет требовать клиенсткий серт, то подключится сможет любой! client_ca_file: "/etc/node_exporter/ca.crt" client_auth_type: "RequireAndVerifyClientCert"
Здесь node_exporter использует свой сертификат для TLS и проверяет, что клиент (Prometheus) предъявляет сертификат, подписанный вашим CA. Дальше аккуратно выставляем права на файлы, чтобы приватные ключи не оказались доступны лишним пользователям:
sudo chown node_exporter:node_exporter /etc/node_exporter/node_exporter.key /etc/node_exporter/node_exporter.crt sudo chmod 600 /etc/node_exporter/node_exporter.key /etc/node_exporter/node_exporter.crt sudo chown root:node_exporter /etc/node_exporter/ca.crt /etc/node_exporter/web-config.yml sudo chmod 644 /etc/node_exporter/ca.crt sudo chmod 640 /etc/node_exporter/web-config.yml
Шаг 3. Создаем systemd-сервис
Теперь оформим node_exporter как обычный systemd-сервис. Создаем файл /etc/systemd/system/node_exporter.service со всем содержимым:
[Unit] Description=Prometheus Node Exporter After=network-online.target Wants=network-online.target [Service] User=node_exporter Group=node_exporter ExecStart=/usr/local/bin/node_exporter --web.listen-address=:9100 --web.config.file=/etc/node_exporter/web-config.yml Restart=on-failure RestartSec=5s NoNewPrivileges=true PrivateTmp=true ProtectHome=true ProtectSystem=full [Install] WantedBy=multi-user.target
Перечитываем конфигурацию systemd и запускаем сервис:
sudo systemctl daemon-reload sudo systemctl enable --now node_exporter sudo systemctl status node_exporter --no-pager
На этом этапе node_exporter уже установлен и запущен. Дальше остается настроить Prometheus, чтобы он начал забирать метрики.
Шаг 4. Проверяем доступность метрик с Prometheus
Перед тем как подключать все в конфиг, убеждаемся, что Prometheus действительно может достучаться до node_exporter. Проверяем это с хоста, где работает Prometheus. Если у вас включены TLS и mTLS, запрос должен выглядеть так:
curl --cacert ca.crt --cert prometheus.crt --key prometheus.key https://192.0.2.10:9100/metrics
Если всё настроено корректно, вы увидите большой текстовый вывод с метриками. Если TLS/mTLS не используются, достаточно обычного HTTP:
curl http://192.0.2.10:9100/metrics
Важно: если mTLS включен, но не дает --cert и --key, сервер обязан отказать в подключении. Это простой способ проверить, что проверка клиентского сертификата действительно работает.
Шаг 5. Разворачиваем Grafana и Prometheus через Docker Compose
Если Prometheus и Grafana уже есть в инфраструктуре, этот шаг можно пропустить. Ниже — минимальный вариант, который можно развернуть за несколько минут.
5.1. Собираем структуру директорий
Я обычно использую такую структуру:
monitoring/ docker-compose.yml prometheus/ prometheus.yml targets/ hosts.yml pki/ ca.crt prometheus.crt prometheus.key
Если используете TLS/mTLS, в prometheus/pki/ должны лежать три файла: ca.crt, prometheus.crt, prometheus.key.
5.2. Готовим prometheus.yml
Создайте файл monitoring/prometheus/prometheus.yml и положите в него конфигурацию ниже. Здесь три «джоба»: сам Prometheus, метрики Grafana и node_exporter. Список хостов для node_exporter вынесен в отдельный targets-файл, чтобы добавлять и убирать хосты без правок основного конфига:
global: scrape_interval: 15s scrape_configs: - job_name: "prometheus" static_configs: - targets: ["prometheus:9090"] - job_name: "grafana" metrics_path: /metrics static_configs: - targets: ["grafana:3000"] - job_name: "node_exporter" scheme: https file_sd_configs: - files: - /etc/prometheus/targets/hosts.yml tls_config: ca_file: /etc/prometheus/pki/ca.crt cert_file: /etc/prometheus/pki/prometheus.crt key_file: /etc/prometheus/pki/prometheus.key insecure_skip_verify: false
Если TLS не используется, логика та же: меняете scheme: https на scheme: http и удаляете блок tls_config. Все остальное можно оставить как есть.
5.3. Заполняем targets-файл
Теперь создайте файл monitoring/prometheus/targets/hosts.yml. В нем перечисляем хосты с node_exporter и, если нужно, сразу добавляем лейблы:
- targets: - "192.0.2.10:9100" - "192.0.2.11:9100" labels: group: "Automation" environment: "prod"
Эти лейблы потом удобно использовать в фильтрах Grafana и в алертах.
5.4. Поднимаем стек через docker-compose.yml
Файл monitoring/docker-compose.yml лежит в корне каталога monitoring/. Вводим:
services: grafana: image: grafana/grafana:latest container_name: grafana restart: unless-stopped environment: GF_USERS_ALLOW_SIGN_UP: "false" GF_AUTH_ANONYMOUS_ENABLED: "false" GF_METRICS_ENABLED: "true" volumes: - grafana-data:/var/lib/grafana networks: [ monitoring ] ports: - "3000:3000" prometheus: image: prom/prometheus:latest 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" volumes: - ./prometheus:/etc/prometheus:ro - prometheus-data:/prometheus networks: [ monitoring ] ports: - "9090:9090" networks: monitoring: volumes: grafana-data: prometheus-data:
Запускаем через:
docker compose up -d
5.5. Проверяем, что все поднялось
После запуска мы должны увидеть:
Grafana: http://localhost:3000 (первый вход обычно admin/admin, дальше попросит сменить пароль);
Prometheus: http://localhost:9090.
Если что-то не поднимается, первым делом смотрим логи:
docker logs grafana docker logs prometheus
5.6. Перечитываем targets после изменений
Если вы добавили или убрали хосты в monitoring/prometheus/targets/hosts.yml, самый простой вариант — перезаписать конфигурацию Prometheus через reload-эндпоинт:
curl -X POST http://localhost:9090/-/reload
(или можно перезапустить контейнер Prometheus).
Шаг 6. Подключаем Prometheus в Grafana и добавляем дашборды
Когда Prometheus уже собирает метрики, остается подключить его к Grafana. Сначала интерфейсе Grafana добавляем источник данных: Connections → Data sources → Add data source → Prometheus.
Если все развернуто через docker-compose и сервисы в одной сети, в качестве URL указываем:
После импортируем готовые дашборды для node_exporter. На Grafana.com их много, есть вполне удачные шаблоны с CPU, памятью, дисками и сетью. Дальше уже творческая часть.
Алертинг: заготовки под CPU/RAM/DISK
Здесь оставляю место под ваши «боевые» правила — порог/длительность/labels. Ниже — один пример запроса для CPU, который удобно показывать на графике (и уже потом превращать в alert).
CPU — пример PromQL для процента загрузки + обогащение nodename
( 1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) ) * 100 * on(instance) group_left(nodename) node_uname_info{job="node_exporter"}
Этот запрос считает процент загрузки CPU по instance и дополнительно подтягивает nodename, чтобы в графике было видно не только адрес, но и имя хоста.
Пороговые значения и длительность лучше подбирать по реальной статистике: сначала несколько дней понаблюдать, а уже потом включать жесткие алерты.
Частые ошибки и важные уточнения
По опыту, большинство проблем всплывает на этапе TLS/mTLS. Ниже — типовые симптомы и куда смотреть в первую очередь:
x509: certificate signed by unknown authority
Обычно это говорит о том, что Prometheus не видит ваш ca.crt или использует другой CA. Проверьте путь в tls_config.ca_file и убедитесь, что это тот же сертификат, которым подписан node_exporter.
... doesn't contain any IP SANs
Это значит, что вы скрейпите хост по IP, но в сертификате node_exporter нет IP в subjectAltName. Либо добавьте IP в SAN при выпуске сертификата, либо переходите на скрейп по DNS-имени, которое уже есть в SAN.
mTLS включен, но targets в статусе Down
Чаще всего Prometheus не передает клиентский сертификат. Проверьте, что в scrape_config указаны cert_file и key_file и что сертификат действительно выпущен с extendedKeyUsage=clientAuth и подписан тем же CA, который указан в client_ca_file на стороне node_exporter.
permission denied при чтении ключа
Проверьте владельца и права на /etc/node_exporter/node_exporter.key. И отдельно — от какого пользователя реально стартует сервис. Если это node_exporter, у него должны быть права на чтение ключа.
Команда systemctl status node_exporter — это первый и самый быстрый способ проверить работу сервиса и нет ли очевидных ошибок.
Дополнительно отмечу:
ca.key храните отдельно и максимально аккуратно. В идеале — в секрет-хранилище или вообще офлайн. Утечка CA — это перевыпуск всего.
Бинарник node_exporter лучше оставить root:root, чтобы сервисный пользователь не мог его подменить.
Ограничьте доступ к 9100/tcp только со стороны Prometheus.
Следите за сроком действия сертификатов. Иначе в какой-то момент все «просто перестанет работать», причем обычно в самый неудобный день.
Что бы я сделал следующим шагом
После базового запуска логично двигаться дальше:
Автоматизировать выпуск и продление сертификатов — через Ansible, CFSSL, step-ca или то, что уже используется в вашей инфраструктуре.
Добавить discovery хостов. Если у вас уже есть file_sd_configs, это хороший старт для интеграции с inventory или CMDB.
Настроить полноценные алерты по CPU, RAM и DISK и отправку уведомлений в удобный канал — почту, мессенджер или систему инцидентов.
Развернуть реверс-прокси на 80/443 (например, NGINX), чтобы закрыть прямой доступ и не открывать наружу порты 9090 и 3000.
Удачи! И пусть ваши диски не заканчиваются в пятницу вечером 🙂

