Proxmox监控报告 - VM状态、主机资源使用情况、温度控制 - 通过Telegram定时发送
高级
这是一个自动化工作流,包含 18 个节点。主要使用 Set, Ssh, Code, Telegram, HttpRequest 等节点。 Proxmox系统监控 - 通过Telegram发送虚拟机状态、主机资源和温度警报
前置要求
- •Telegram Bot Token
- •可能需要目标 API 的认证凭证
分类
-
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "EyPTvUFPOkBXeelq",
"meta": {
"instanceId": "5c7ce220523e8664f49208a8be668a8dc6fab5f747ce4de865fa1309727919f1"
},
"name": "Proxmox 监控报告 - VM 状态、主机资源使用情况、温度控制 - 通过 Telegram 导出定时发送",
"tags": [],
"nodes": [
{
"id": "62234df5-c87e-40f7-8fca-0b2cb4346d31",
"name": "每15分钟定时执行",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-896,
224
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
},
"typeVersion": 1.1
},
{
"id": "698e55da-cdf3-475f-b009-34e075274dca",
"name": "设置变量",
"type": "n8n-nodes-base.set",
"position": [
-672,
224
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "var1",
"name": "PROXMOX_IP",
"type": "string",
"value": "192.168.1.100"
},
{
"id": "var2",
"name": "PROXMOX_PORT",
"type": "string",
"value": "8006"
},
{
"id": "var3",
"name": "PROXMOX_NODE",
"type": "string",
"value": "pve"
},
{
"id": "var4",
"name": "TELEGRAM_CHAT_ID",
"type": "string",
"value": "YOUR_CHAT_ID"
},
{
"id": "var5",
"name": "PROXMOX_USER",
"type": "string",
"value": "root@pam"
},
{
"id": "var6",
"name": "PROXMOX_PASSWORD",
"type": "string",
"value": "your_password"
}
]
}
},
"typeVersion": 3.3
},
{
"id": "b25669c5-a50b-4d0d-9b1b-fb763661bd4a",
"name": "Proxmox 登录",
"type": "n8n-nodes-base.httpRequest",
"position": [
-448,
224
],
"parameters": {
"url": "=https://{{ $json.PROXMOX_IP }}:{{ $json.PROXMOX_PORT }}/api2/json/access/ticket",
"method": "POST",
"options": {
"allowUnauthorizedCerts": true
},
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "username",
"value": "={{ $json.PROXMOX_USER }}"
},
{
"name": "password",
"value": "={{ $json.PROXMOX_PASSWORD }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "25af5d5f-3a23-45cf-8387-c00d756cfcb6",
"name": "准备认证",
"type": "n8n-nodes-base.set",
"position": [
-224,
224
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "ticket",
"name": "ticket",
"type": "string",
"value": "={{ $json.data.ticket }}"
},
{
"id": "csrf",
"name": "csrf",
"type": "string",
"value": "={{ $json.data.CSRFPreventionToken }}"
},
{
"id": "ip",
"name": "PROXMOX_IP",
"type": "string",
"value": "={{ $('Set Variables').item.json.PROXMOX_IP }}"
},
{
"id": "port",
"name": "PROXMOX_PORT",
"type": "string",
"value": "={{ $('Set Variables').item.json.PROXMOX_PORT }}"
},
{
"id": "node",
"name": "PROXMOX_NODE",
"type": "string",
"value": "={{ $('Set Variables').item.json.PROXMOX_NODE }}"
}
]
}
},
"typeVersion": 3.3
},
{
"id": "43ffeb7f-396a-4e69-a8cc-dc17b506321c",
"name": "API - VM 列表",
"type": "n8n-nodes-base.httpRequest",
"position": [
0,
0
],
"parameters": {
"url": "=https://{{ $json.PROXMOX_IP }}:{{ $json.PROXMOX_PORT }}/api2/json/nodes/{{ $json.PROXMOX_NODE }}/qemu",
"options": {
"allowUnauthorizedCerts": true
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Cookie",
"value": "=PVEAuthCookie={{ $json.ticket }}"
},
{
"name": "CSRFPreventionToken",
"value": "={{ $json.csrf }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "66371dcf-84e5-4467-a104-a466517ee645",
"name": "API - 节点任务",
"type": "n8n-nodes-base.httpRequest",
"position": [
0,
224
],
"parameters": {
"url": "=https://{{ $('Set Variables').item.json.PROXMOX_IP }}:{{ $('Set Variables').item.json.PROXMOX_PORT }}/api2/json/nodes/{{ $('Set Variables').item.json.PROXMOX_NODE }}/tasks?limit=100",
"options": {
"allowUnauthorizedCerts": true
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Cookie",
"value": "=PVEAuthCookie={{ $('Prepare Auth').item.json.ticket }}"
},
{
"name": "CSRFPreventionToken",
"value": "={{ $json.csrf }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "fe91fc19-09e6-44c9-a0d2-403494e5273e",
"name": "API - 节点状态",
"type": "n8n-nodes-base.httpRequest",
"position": [
0,
448
],
"parameters": {
"url": "=https://{{ $('Set Variables').item.json.PROXMOX_IP }}:{{ $('Set Variables').item.json.PROXMOX_PORT }}/api2/json/nodes/{{ $('Set Variables').item.json.PROXMOX_NODE }}/status",
"options": {
"allowUnauthorizedCerts": true
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Cookie",
"value": "=PVEAuthCookie={{ $('Prepare Auth').item.json.ticket }}"
},
{
"name": "CSRFPreventionToken",
"value": "={{ $json.csrf }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "958b184a-aade-42c1-aa6b-26f4bc3d0aa1",
"name": "SSH - 获取传感器数据",
"type": "n8n-nodes-base.ssh",
"position": [
304,
224
],
"parameters": {
"command": "=# Temperature sensors\nsensors 2>/dev/null | grep -E 'Package|Core' || echo 'No temperature data available'\n\n# Detailed uptime\nuptime"
},
"credentials": {
"sshPassword": {
"id": "AR4GTfnrziYoW31z",
"name": "SSH Password account"
}
},
"typeVersion": 1
},
{
"id": "5d2150c2-34b8-4cbc-8b08-263dc9a2b583",
"name": "处理数据",
"type": "n8n-nodes-base.code",
"position": [
528,
112
],
"parameters": {
"jsCode": "// Get data from previous nodes by name\nconst sshData = $input.first().json.stdout;\nconst vmData = $('API - VM List').first().json.data;\nconst nodeData = $('API - Node Status').first().json.data;\nconst tasksData = $('API - Node Tasks').first().json.data;\n\nif (!vmData) {\n throw new Error('VM data not received from API - VM List node');\n}\nif (!nodeData) {\n throw new Error('Node status data not received from API - Node Status node');\n}\nif (!tasksData) {\n throw new Error('Tasks data not received from API - Node Tasks node');\n}\n\n// Parse SSH output for temperature\nconst sshLines = (sshData || '').split('\\n');\nconst tempLines = sshLines.filter(l => l.includes('Package') || l.includes('Core'));\n\nlet temperatureDisplay = 'No temperature data available';\nlet hasTempWarning = false;\n\nif (tempLines.length > 0) {\n const tempData = [];\n let hasHighTemp = false;\n \n for (const line of tempLines) {\n const currentMatch = line.match(/([+\\-]?[0-9.]+)°C/);\n const highMatch = line.match(/high\\s*=\\s*([+\\-]?[0-9.]+)°C/);\n \n if (currentMatch && highMatch) {\n const current = parseFloat(currentMatch[1]);\n const high = parseFloat(highMatch[1]);\n const label = line.split(':')[0].trim();\n \n tempData.push({ label, current, high, line: line.trim() });\n \n if (current >= high) {\n hasHighTemp = true;\n hasTempWarning = true;\n }\n }\n }\n \n if (hasHighTemp) {\n temperatureDisplay = tempData.map(t => t.line).join('\\n');\n } else {\n const avgTemp = (tempData.reduce((sum, t) => sum + t.current, 0) / tempData.length).toFixed(1);\n const maxTemp = Math.max(...tempData.map(t => t.current)).toFixed(1);\n const minTemp = Math.min(...tempData.map(t => t.current)).toFixed(1);\n temperatureDisplay = `Average: ${avgTemp}°C (Min: ${minTemp}°C, Max: ${maxTemp}°C)`;\n }\n}\n\n// Parse uptime from SSH\nlet uptimeString = 'N/A';\nconst uptimeLine = sshLines.find(l => l.includes('up'));\nif (uptimeLine) {\n uptimeString = uptimeLine.trim();\n}\n\n// VM statistics\nconst totalVMs = vmData.length;\nconst runningVMs = vmData.filter(vm => vm.status === 'running').length;\nconst stoppedVMs = totalVMs - runningVMs;\n\n// Find recently stopped VMs from task log\nconst now = Math.floor(Date.now() / 1000);\nconst fifteenMinutesAgo = now - 900;\n\nconst recentStopTasks = tasksData.filter(task => {\n const isStopTask = task.type === 'qmstop' || task.type === 'qmshutdown';\n const taskTime = task.starttime || task.endtime || 0;\n return isStopTask && taskTime >= fifteenMinutesAgo;\n});\n\nconst recentlyStoppedVMs = recentStopTasks.map(task => {\n let vmid = 'N/A';\n vmid = task.id;\n \n const vm = vmData.find(v => String(v.vmid) === String(vmid));\n const vmName = vm ? vm.name : 'Unknown';\n \n const taskTime = task.starttime || task.endtime || now;\n const minutesAgo = Math.floor((now - taskTime) / 60);\n \n return {\n id: vmid,\n name: vmName,\n minutesAgo: minutesAgo,\n status: task.status || 'stopped'\n };\n});\n\nconst recentlyStopped = recentlyStoppedVMs.length;\n\n// Node statistics from API\nconst cpuUsage = nodeData.cpu ? (nodeData.cpu * 100).toFixed(2) + '%' : 'N/A';\nconst memTotal = nodeData.memory ? (nodeData.memory.total / (1024**3)).toFixed(2) + ' GB' : 'N/A';\nconst memUsed = nodeData.memory ? (nodeData.memory.used / (1024**3)).toFixed(2) + ' GB' : 'N/A';\nconst memPercent = nodeData.memory ? ((nodeData.memory.used / nodeData.memory.total) * 100).toFixed(2) + '%' : 'N/A';\nconst uptimeSeconds = nodeData.uptime || 0;\nconst uptimeDays = Math.floor(uptimeSeconds / 86400);\nconst uptimeHours = Math.floor((uptimeSeconds % 86400) / 3600);\nconst uptimeFormatted = `${uptimeDays}d ${uptimeHours}h`;\n\nreturn {\n timestamp: new Date().toISOString(),\n vms: {\n total: totalVMs,\n running: runningVMs,\n stopped: stoppedVMs,\n recentlyStopped: recentlyStopped,\n recentlyStoppedDetails: recentlyStoppedVMs\n },\n host: {\n cpu: cpuUsage,\n memoryUsed: memUsed,\n memoryTotal: memTotal,\n memoryPercent: memPercent,\n uptime: uptimeFormatted,\n uptimeDetailed: uptimeString,\n temperature: temperatureDisplay,\n tempWarning: hasTempWarning\n }\n};"
},
"typeVersion": 2
},
{
"id": "3396072a-4d74-4b52-a8a4-55ba02f75bc2",
"name": "生成格式化消息",
"type": "n8n-nodes-base.code",
"position": [
528,
352
],
"parameters": {
"jsCode": "const data = $input.first().json;\n\nconst tempWarningEmoji = data.host.tempWarning ? '🔥 ' : '';\nconst tempTitle = data.host.tempWarning ? 'Temperature Warning' : 'Temperature Data';\n\nlet recentlyStoppedSection = '';\nif (data.vms.recentlyStopped > 0 && data.vms.recentlyStoppedDetails && data.vms.recentlyStoppedDetails.length > 0) {\n const vmList = data.vms.recentlyStoppedDetails\n .map(vm => ` • VM ${vm.id} - ${vm.name} (${vm.minutesAgo} min ago)`)\n .join('\\n');\n recentlyStoppedSection = `\\n\\n<b>Recently Stopped VMs Details:</b>\\n${vmList}`;\n}\n\nconst message = `<b>Proxmox Monitoring Report</b>\n<i>Generated: ${new Date(data.timestamp).toLocaleString('en-US')}</i>\n\n<b>━━━━━━━━━━━━━━━━━━━━</b>\n<b>Virtual Machines</b>\n<b>━━━━━━━━━━━━━━━━━━━━</b>\n\n<b>Total VMs:</b> ${data.vms.total}\n<b>Running:</b> ${data.vms.running} ✅\n<b>Stopped:</b> ${data.vms.stopped} ⛔\n<b>Recently Stopped:</b> ${data.vms.recentlyStopped} ⚠️${recentlyStoppedSection}\n\n<b>━━━━━━━━━━━━━━━━━━━━</b>\n<b>Host Resources</b>\n<b>━━━━━━━━━━━━━━━━━━━━</b>\n\n<b>CPU Usage:</b> ${data.host.cpu}\n<b>Memory:</b> ${data.host.memoryUsed} / ${data.host.memoryTotal}\n (${data.host.memoryPercent})\n<b>Uptime:</b> ${data.host.uptime}\n\n<b>━━━━━━━━━━━━━━━━━━━━</b>\n<b>${tempWarningEmoji}${tempTitle}</b>\n<b>━━━━━━━━━━━━━━━━━━━━</b>\n\n<code>${data.host.temperature}</code>`;\n\nreturn { message };"
},
"typeVersion": 2
},
{
"id": "81a4878f-35a2-44d1-81a2-ca209d6e70e3",
"name": "发送 Telegram 报告",
"type": "n8n-nodes-base.telegram",
"position": [
816,
224
],
"webhookId": "0a44bae4-6570-4b87-8080-4328fe78a753",
"parameters": {
"text": "={{ $json.message }}",
"chatId": "={{ $('Set Variables').first().json.TELEGRAM_CHAT_ID }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"id": "FUXl519hpM0FsK8j",
"name": "Telegram account"
}
},
"typeVersion": 1.2
},
{
"id": "31ae9494-5e80-40be-8aea-4ca982960dbc",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1184,
16
],
"parameters": {
"width": 380,
"height": 180,
"content": "## Proxmox 监控工作流"
},
"typeVersion": 1
},
{
"id": "467412ef-997f-4666-81e2-01c3fb23202f",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-784,
400
],
"parameters": {
"width": 320,
"height": 292,
"content": "## 需要配置"
},
"typeVersion": 1
},
{
"id": "9f4196b9-741d-4536-b487-89be23dfa9e3",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-432,
-16
],
"parameters": {
"width": 300,
"height": 204,
"content": "## 认证流程"
},
"typeVersion": 1
},
{
"id": "23393f4f-3ba3-4900-aec5-7952f9b64586",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-96,
608
],
"parameters": {
"width": 300,
"height": 272,
"content": "## 数据收集"
},
"typeVersion": 1
},
{
"id": "7be5a2e6-d39a-4b4f-9cfd-888eab5261ce",
"name": "便签说明4",
"type": "n8n-nodes-base.stickyNote",
"position": [
176,
-16
],
"parameters": {
"width": 300,
"height": 220,
"content": "## SSH 温度检查"
},
"typeVersion": 1
},
{
"id": "af79ac1a-e92a-47aa-b541-4d038175f28e",
"name": "便签说明5",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
-128
],
"parameters": {
"width": 320,
"height": 264,
"content": "## 数据处理"
},
"typeVersion": 1
},
{
"id": "e4bc84d3-85ba-4cbe-bb21-8832642ddf82",
"name": "便签 6",
"type": "n8n-nodes-base.stickyNote",
"position": [
816,
384
],
"parameters": {
"width": 300,
"height": 256,
"content": "## TELEGRAM 配置"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "2c9715a6-bb36-4d9d-8476-cd3c18a1fac0",
"connections": {
"Prepare Auth": {
"main": [
[
{
"node": "API - VM List",
"type": "main",
"index": 0
}
]
]
},
"Process Data": {
"main": [
[
{
"node": "Generate Formatted Message",
"type": "main",
"index": 0
}
]
]
},
"API - VM List": {
"main": [
[
{
"node": "API - Node Tasks",
"type": "main",
"index": 0
}
]
]
},
"Proxmox Login": {
"main": [
[
{
"node": "Prepare Auth",
"type": "main",
"index": 0
}
]
]
},
"Set Variables": {
"main": [
[
{
"node": "Proxmox Login",
"type": "main",
"index": 0
}
]
]
},
"API - Node Tasks": {
"main": [
[
{
"node": "API - Node Status",
"type": "main",
"index": 0
}
]
]
},
"API - Node Status": {
"main": [
[
{
"node": "SSH - Get Sensors",
"type": "main",
"index": 0
}
]
]
},
"SSH - Get Sensors": {
"main": [
[
{
"node": "Process Data",
"type": "main",
"index": 0
}
]
]
},
"Schedule Every 15min": {
"main": [
[
{
"node": "Set Variables",
"type": "main",
"index": 0
}
]
]
},
"Generate Formatted Message": {
"main": [
[
{
"node": "Send Telegram Report",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
Telegram AI频道机器人 - 支持文本和图像响应的TGPT生成器
使用GPT-4和TGPT在Telegram频道中生成文本和图像响应
If
Set
Code
+8
22 节点Vigh Sandor
PKI证书与CRL监控器 - 自动过期警报系统
监控PKI证书和CRL过期情况并发送Telegram和SMS警报
If
Set
Code
+9
44 节点Vigh Sandor
使用Robot Framework、ArgoCD和完整KinD生命周期实现自动化Kubernetes测试
基于 Robot Framework、ArgoCD 和完整 KinD 生命周期的自动化 Kubernetes 测试
If
Set
Gitlab
+10
73 节点Vigh Sandor
开发运维
Kubernetes监控与告警 - 部署和Pod状态 - Telegram告警
Kubernetes部署和Pod监控,带Telegram告警
If
Code
Telegram
+4
14 节点Vigh Sandor
在线营销周报
AI营销报告(Google Analytics、Google Ads、Meta Ads) - 通过邮件/Telegram发送
Set
Code
Telegram
+13
51 节点Friedemann Schuetz
营销
AI驱动视频创作与上传至Instagram、TikTok和YouTube
从云端硬盘进行AI驱动视频创作并上传至Instagram、TikTok和YouTube
If
Set
Code
+14
53 节点DevCode Journey
内容创作