写在前面:为什么你的 VPS 需要一套正经监控系统
很多站长在 VPS 上跑着业务,服务器状态全靠”感觉”——感觉今天网站慢了,感觉磁盘快满了,感觉 CPU 负载有点高。等到真正出问题的时候,往往是网站已经挂了几个小时,用户投诉了才手忙脚乱地登录上去看日志。这种”佛系运维”在小站时代或许还能凑合,但只要你的站点有一定流量,或者跑了多个服务,一套自动化的监控告警系统就是刚需。
开源监控方案里,Prometheus + Grafana 的组合是目前社区最主流的选择。Prometheus 负责采集和存储时序数据,Grafana 负责可视化展示,Alertmanager 负责告警推送。三者配合默契,而且全都免费开源,跑在 512MB 的小鸡上也能流畅运行。本文会从零开始,手把手教你在 VPS 上搭建完整的监控栈,并集成 Telegram 告警通知。

一、架构概览:这套监控系统由哪些组件组成
在开始动手之前,我们先搞清楚整个系统的架构和工作流程。这样可以避免”知其然而不知其所以然”的尴尬。
核心组件
| 组件 | 功能 | 资源占用 |
|---|---|---|
| Prometheus Server | 时序数据库,负责拉取指标数据并存储 | 内存 ~150MB,磁盘视保留策略而定 |
| Node Exporter | 部署在被监控机器上,暴露系统指标 | 内存 ~20MB,CPU 几乎无感 |
| Grafana | 可视化面板,接入 Prometheus 数据源 | 内存 ~80MB,含 SQLite 和面板渲染 |
| Alertmanager | 接收告警规则触发的事件,负责路由和去重 | 内存 ~30MB |
数据流
Node Exporter 每 15 秒采集一次系统指标(CPU、内存、磁盘、网络等),暴露在 HTTP 端点上。Prometheus Server 定期从这些端点拉取数据(pull 模式),存入本地的时序数据库。Grafana 通过 PromQL 查询 Prometheus 中的数据,绘制成可视化图表。Alertmanager 接收 Prometheus 触发的告警,根据规则路由到 Telegram、邮件等渠道。
这种 pull 模式的设计有一个显著优势:你不需要在被监控机器上安装 Agent(除了 Node Exporter 这个只读指标暴露器),监控端完全掌控采集节奏,不会因为被监控端异常而导致数据丢失。被监控机器即使挂了,Prometheus 也能通过”最后一次拉取失败”这一事实来触发告警。
二、安装 Prometheus Server
Prometheus 官方提供了预编译的二进制包,安装非常简洁。我们直接下载最新稳定版。
下载与解压
1
2
3
4
5 cd /opt
wget https://github.com/prometheus/prometheus/releases/download/v2.53.0/prometheus-2.53.0.linux-amd64.tar.gz
tar xzf prometheus-2.53.0.linux-amd64.tar.gz
mv prometheus-2.53.0.linux-amd64 prometheus
cd prometheus
创建系统用户
从安全角度考虑,不要让 Prometheus 以 root 身份运行:
1
2
3
4 useradd --no-create-home --shell /bin/false prometheus
mkdir -p /data/prometheus
chown prometheus:prometheus /data/prometheus
chown -R prometheus:prometheus /opt/prometheus
配置文件
编辑
1 | /opt/prometheus/prometheus.yml |
,这是最简可用的配置:
1
2
3
4
5
6
7
8
9
10
11
12 global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
这里
1 | scrape_interval |
表示每 15 秒拉取一次指标,
1 | evaluation_interval |
表示每 15 秒评估一次告警规则。
1 | scrape_configs |
中定义了两个 job:一个是 Prometheus 自身(暴露自身运行指标),另一个是 Node Exporter。后面加了新机器,只需在
1 | targets |
列表里追加 IP 即可。
Systemd 服务
创建
1 | /etc/systemd/system/prometheus.service |
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 [Unit]
Description=Prometheus
After=network.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/opt/prometheus/prometheus \
--config.file=/opt/prometheus/prometheus.yml \
--storage.tsdb.path=/data/prometheus \
--web.console.templates=/opt/prometheus/consoles \
--web.console.libraries=/opt/prometheus/console_libraries
Restart=always
[Install]
WantedBy=multi-user.target
启动并设为开机自启:
1
2
3 systemctl daemon-reload
systemctl enable --now prometheus
systemctl status prometheus
确认 Prometheus 正常运行后,访问
1 | http://你的VPS_IP:9090 |
,应该能看到 Prometheus 的 Web UI。在”Status → Targets”页面可以确认所有目标是否处于 UP 状态。
三、部署 Node Exporter
Node Exporter 负责采集系统层面的指标,是整套监控系统的”眼睛”。
安装
1
2
3
4
5
6 cd /opt
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-1.8.2.linux-amd64.tar.gz
mv node_exporter-1.8.2.linux-amd64 node_exporter
useradd --no-create-home --shell /bin/false node_exporter
chown -R node_exporter:node_exporter /opt/node_exporter
Systemd 服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 cat > /etc/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Node Exporter
After=network.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/opt/node_exporter/node_exporter \
--collector.logind \
--collector.systemd \
--collector.processes \
--web.listen-address=:9100
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now node_exporter
这里启用了几个有用的 collector:
1 | logind |
监控登录会话,
1 | systemd |
监控 systemd 服务状态,
1 | processes |
监控进程数量和状态。如果你的 VPS 内存非常紧张(512MB 以下),可以去掉
1 | --collector.processes |
来节省一点资源。
验证 Node Exporter 是否正常工作:
1 curl http://localhost:9100/metrics | head -20
如果返回了一大堆以
1 | # HELP |
和
1 | # TYPE |
开头的指标数据,说明采集成功。现在回到 Prometheus 的配置,如果之前已经加上了
1 | localhost:9100 |
,Prometheus 会自动开始拉取数据。
四、安装配置 Grafana
Grafana 负责将 Prometheus 里枯燥的时序数据变成可视化的仪表盘。
安装(Ubuntu/Debian)
1
2
3
4
5 apt-get install -y software-properties-common
wget -q -O - https://packages.grafana.com/gpg.key | apt-key add -
add-apt-repository "deb https://packages.grafana.com/oss/deb stable main"
apt-get update
apt-get install -y grafana
CentOS/RHEL 用户
1
2
3
4
5
6
7
8
9
10
11
12 cat > /etc/yum.repos.d/grafana.repo << 'EOF'
[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
EOF
yum install -y grafana
启动 Grafana
1
2 systemctl enable --now grafana-server
systemctl status grafana-server
Grafana 默认监听 3000 端口。访问
1 | http://你的VPS_IP:3000 |
,默认用户名和密码都是
1 | admin |
,首次登录会要求修改密码。
连接 Prometheus 数据源
- 登录 Grafana 后,点击左侧齿轮图标 → “Data Sources”
- 点击 “Add data source” → 选择 “Prometheus”
- 在 URL 一栏填入
1http://localhost:9090
- 点击底部的 “Save & Test”,看到绿色提示 “Data source is working” 即表示连接成功
导入 Node Exporter 仪表盘
Grafana 社区有大量现成的仪表盘模板,我们不需要从头画图表。Node Exporter 最流行的仪表盘 ID 是 1860(作者:rfrail3,专为 Node Exporter 设计)。
- 在 Grafana 左侧菜单选择 “+” → “Import”
- 在 “Import via grafana.com” 输入框里填入
11860
,点击 “Load”
- 选择刚才创建的 Prometheus 数据源,点击 “Import”
几秒钟后,你就能看到 CPU 使用率、内存占用、磁盘 IO、网络流量、系统负载、进程数等几十个指标的实时图表。这个仪表盘非常全面,涵盖了日常运维需要关注的几乎所有系统指标。

五、配置告警:当服务器出问题时第一时间通知你
监控数据再好看,如果没人盯着看就失去了意义。告警功能才是监控系统的灵魂。当 CPU 持续飙高、磁盘快满、服务宕机时,我们需要第一时间收到通知。
安装 Alertmanager
1
2
3
4
5
6 cd /opt
wget https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz
tar xzf alertmanager-0.27.0.linux-amd64.tar.gz
mv alertmanager-0.27.0.linux-amd64 alertmanager
useradd --no-create-home --shell /bin/false alertmanager
chown -R alertmanager:alertmanager /opt/alertmanager
配置 Telegram 告警
首先创建一个 Telegram Bot,获取 Token。在 Telegram 中搜索 @BotFather,发送
1 | /newbot |
,按提示创建一个新 Bot,拿到 HTTP API Token(格式类似
1 | 123456789:ABCdefGHIjklmNOPqrsTUVwxyz |
)。然后搜索你的 Bot 用户名,发送
1 | /start |
,再访问以下 URL 获取 Chat ID:
1 https://api.telegram.org/bot<你的Token>/getUpdates
在返回的 JSON 中找到
1 | chat.id |
字段。
编辑
1 | /opt/alertmanager/alertmanager.yml |
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 global:
resolve_timeout: 5m
route:
group_by: ['alertname']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'telegram'
receivers:
- name: 'telegram'
telegram_configs:
- bot_token: 'YOUR_BOT_TOKEN'
chat_id: YOUR_CHAT_ID
send_resolved: true
parse_mode: 'HTML'
message: |
{{ if eq .Status "firing" }}🚨 <b>告警触发</b>{{ else }}✅ <b>告警恢复</b>{{ end }}
<b>告警名称:</b>{{ .GroupLabels.alertname }}
<b>严重级别:</b>{{ .CommonLabels.severity }}
<b>触发时间:</b>{{ .StartsAt.Format "2006-01-02 15:04:05" }}
<b>详情:</b>{{ .CommonAnnotations.summary }}
{{ .CommonAnnotations.description }}
创建 Systemd 服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 cat > /etc/systemd/system/alertmanager.service << 'EOF'
[Unit]
Description=Alertmanager
After=network.target
[Service]
User=alertmanager
Group=alertmanager
Type=simple
ExecStart=/opt/alertmanager/alertmanager \
--config.file=/opt/alertmanager/alertmanager.yml \
--storage.path=/data/alertmanager
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now alertmanager
在 Prometheus 中定义告警规则
创建
1 | /opt/prometheus/alert_rules.yml |
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 groups:
- name: node_alerts
interval: 15s
rules:
- alert: HighCPUUsage
expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
annotations:
summary: "CPU 使用率超过 80%(当前值:{{ $value | humanizePercentage }})"
description: "实例 {{ $labels.instance }} 的 CPU 使用率持续 5 分钟超过 80%,请检查是否有异常进程。"
- alert: HighDiskUsage
expr: (1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "磁盘空间使用率超过 85%(当前值:{{ $value | humanizePercentage }})"
description: "实例 {{ $labels.instance }} 的根分区磁盘使用率已超过 85%,请及时清理或扩容。"
- alert: DiskFull
expr: (1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})) * 100 > 93
for: 2m
labels:
severity: critical
annotations:
summary: "磁盘空间即将耗尽(当前值:{{ $value | humanizePercentage }})"
description: "实例 {{ $labels.instance }} 的根分区使用率已超过 93%,有宕机风险!"
- alert: HighMemoryUsage
expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
for: 5m
labels:
severity: warning
annotations:
summary: "内存使用率超过 90%(当前值:{{ $value | humanizePercentage }})"
description: "实例 {{ $labels.instance }} 的内存使用率超过 90%,建议检查内存泄漏或考虑扩容。"
- alert: NodeDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "服务器宕机"
description: "实例 {{ $labels.instance }} 已离线超过 1 分钟!"
- alert: HighLoadAverage
expr: node_load15 > (count(node_cpu_seconds_total{mode="idle"}) by (instance)) * 0.8
for: 10m
labels:
severity: warning
annotations:
summary: "系统负载过高(15 分钟负载:{{ $value }})"
description: "实例 {{ $labels.instance }} 的 15 分钟平均负载超过了 CPU 核心数的 80%,系统可能处于过载状态。"
然后在
1 | prometheus.yml |
中引用这个规则文件:
1
2
3
4
5
6
7 rule_files:
- "alert_rules.yml"
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
重启 Prometheus 使配置生效:
1 systemctl restart prometheus
现在,当 CPU 持续超过 80%、磁盘使用率超过 85%、服务器宕机等情况发生时,你的 Telegram 会立刻收到告警消息。当指标恢复正常时,Alertmanager 还会发送一条”告警恢复”的通知。
六、监控多台 VPS
如果你手里不止一台机器,这套方案同样可以轻松扩展。只需要在其他 VPS 上也安装 Node Exporter,然后在 Prometheus 的配置文件中添加对应目标即可。
在其他机器上安装 Node Exporter(步骤同上),然后在主 Prometheus 的
1 | prometheus.yml |
中追加:
1
2
3
4
5
6
7 - job_name: 'node'
static_configs:
- targets:
- 'localhost:9100' # 本机
- '192.168.1.2:9100' # 第二台 VPS
- '192.168.1.3:9100' # 第三台 VPS
- '你的其他VPS_IP:9100'
重启 Prometheus 后,Grafana 仪表盘会自动显示所有机器的数据,下拉菜单可以切换查看不同实例。Grafana 的 1860 号仪表盘已经内置了实例选择器,多台机器共享同一个面板,非常直观。
需要注意的是,如果被监控的 VPS 和 Prometheus 不在同一个内网,你需要确保 Node Exporter 的端口(9100)在防火墙上对 Prometheus 服务器的 IP 放开。但不要对全世界开放——只允许监控服务器的 IP 访问即可,可以在 Node Exporter 侧用 iptables 限制:
1
2 iptables -A INPUT -p tcp --dport 9100 -s 你的监控服务器IP -j ACCEPT
iptables -A INPUT -p tcp --dport 9100 -j DROP
七、数据保留策略与磁盘优化
Prometheus 默认将数据保留 15 天。对于小 VPS 来说,15 天的数据量大约占用 2-5GB 磁盘空间,取决于采集的指标数量。如果你的磁盘空间很紧张,可以缩短保留时间:
1 --storage.tsdb.retention.time=7d # 只保留 7 天数据
也可以在启动参数中加入
1 | --storage.tsdb.retention.size=10GB |
来限制数据最大占用空间,Prometheus 会自动删除最旧的数据来满足大小限制。
另外,Prometheus 的 WAL(预写日志)默认会占用不少磁盘 IO。如果你的 VPS 是 HDD 而非 SSD,可以考虑将 WAL 目录单独放在内存盘上:
1
2 mkdir -p /dev/shm/prometheus_wal
mount --bind /dev/shm/prometheus_wal /data/prometheus/wal
注意:重启后需要重新挂载,建议写入
1 | /etc/fstab |
。
八、安全加固要点
监控系统本身如果不安全,就等于把服务器的命脉拱手让人。以下是一些必须做的安全措施:
Grafana 反向代理 + HTTPS
永远不要直接通过公网 IP + 3000 端口暴露 Grafana。用 Nginx 反代并配置 HTTPS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 server {
listen 443 ssl;
server_name grafana.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/grafana.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/grafana.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}
Prometheus 加上认证
Prometheus 原生不支持认证,但可以通过 Nginx 反代加 basic auth 来实现:
1
2
3 apt-get install apache2-utils
htpasswd -c /etc/nginx/.htpasswd promadmin
# 输入密码
然后在 Nginx 配置中为 Prometheus 的 location 加上
1 | auth_basic |
指令。
Node Exporter 限制来源 IP
前面已经说过,用 iptables 限制只允许 Prometheus 服务器访问:
1
2 iptables -A INPUT -p tcp --dport 9100 -s 你的监控服务器IP -j ACCEPT
iptables -A INPUT -p tcp --dport 9100 -j DROP
想持久化保存 iptables 规则,Ubuntu 可以用
1 | iptables-persistent |
包,CentOS 则默认已经持久化。
九、扩展思考:还能监控什么
这套监控方案的可扩展性非常好。除了系统层面的指标,你还可以监控非常多的东西:
- Nginx 指标:开启 Nginx 的
1stub_status
模块,用 nginx-lua-prometheus 或 nginx-prometheus-exporter 采集请求数、连接数、响应状态码分布
- MySQL/PostgreSQL 指标:使用 mysqld_exporter 或 postgres_exporter 监控数据库连接数、慢查询、InnoDB 状态
- Redis 指标:使用 redis_exporter 监控缓存命中率、内存使用、客户端连接数
- Docker 容器指标:使用 cadvisor 或 dockerd 暴露的 Prometheus 端点,监控每个容器的 CPU、内存、网络 IO
- SSL 证书过期:使用 ssl_exporter 或 blackbox_exporter 监控域名证书的剩余有效期,提前通知续期
- HTTP 端点探活:使用 blackbox_exporter 对网站首页、API 接口进行 ICMP 和 HTTP 探测,发现 5xx 错误立刻告警
- WordPress 指标:通过自定义 exporter 采集 WordPress 的数据库查询次数、缓存命中率、PHP 进程数
所有这些 exporter 的部署方式都和 Node Exporter 一样——下载二进制文件、创建 systemd 服务、在 Prometheus 中添加 target。社区里几乎你能想到的所有中间件都有对应的 exporter。
十、常见问题排查
Prometheus 页面显示目标为 DOWN
最常见的原因是防火墙没有放开端口。检查 iptables 或云服务商的安全组规则,确保 Prometheus 所在的机器能访问到目标节点的 9100 端口。也可以用
1 | telnet 目标IP 9100 |
简单测试一下连通性。
Grafana 图表显示 “No data”
检查 Grafana 数据源配置是否正确。在 Grafana 的 Explore 页面(左侧指南针图标)输入 PromQL 查询
1 | up |
,如果能返回数据,说明数据源连接和 Prometheus 采集都正常。如果返回空结果,去 Prometheus 的 Web UI 确认数据是否正常写入。
告警没有触发
检查 Alertmanager 的 Web UI(端口 9093)看是否有告警被路由到。如果 Alertmanager 收到了告警但没有发送 Telegram 消息,检查
1 | bot_token |
和
1 | chat_id |
是否正确。Telegram Bot 需要在目标 Chat 中先被启动(发送
1 | /start |
)。
Prometheus 占用内存过高
Prometheus 的内存使用量和指标基数(cardinality)直接相关。如果你发现内存占用过高,检查是否有 exporter 暴露了过多高基数标签(比如包含大量唯一值的 label)。常用的优化手段包括:在
1 | scrape_config |
中用
1 | metric_relabel_configs |
丢弃不需要的高基数指标,或者缩短
1 | scrape_interval |
减少数据采样频率。
总结
Prometheus + Grafana + Alertmanager 这套组合拳,可以说是目前开源监控领域的最优解。它没有商业监控系统的授权限制,也没有 SaaS 监控服务的按节点收费,一套部署好之后可以无限扩展。对于 VPS 站长来说,花一个下午的时间搭好这套系统,以后就能在服务器出问题之前收到预警,而不是等问题发生了才去救火。
从最早的 Node Exporter 系统指标,到后续的数据库、中间件、自定义业务指标,这套方案可以伴随你的业务增长一路升级。真正的运维高手不是会修服务器的,而是能让服务器在出问题之前就被修好的——而监控系统就是做到这一点的基石。
汤不热吧