AutomationFlowsSlack & Telegram › Proxmox System Monitor - Vm Status, Host Resources & Temperature Alerts via…

Proxmox System Monitor - Vm Status, Host Resources & Temperature Alerts via…

Original n8n title: Proxmox System Monitor - Vm Status, Host Resources & Temperature Alerts via Telegram

ByVigh Sandor @vighsandor on n8n.io

This n8n workflow monitors your Proxmox VE server and sends automated reports to Telegram every 15 minutes. It tracks VM status, host resource usage, temperature sensors, and detects recently stopped VMs. n8n instance (self-hosted or cloud) Proxmox VE server with API access…

Cron / scheduled trigger★★★★☆ complexity18 nodesHTTP RequestSshTelegram
Slack & Telegram Trigger: Cron / scheduled Nodes: 18 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #9733 — we link there as the canonical source.

This workflow follows the HTTP Request → Telegram recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "EyPTvUFPOkBXeelq",
  "name": "Proxmox Monitoring Report - VM Status, Host Resource Usage, Temperature Control - Sheduled with Telegram Export",
  "tags": [],
  "nodes": [
    {
      "id": "62234df5-c87e-40f7-8fca-0b2cb4346d31",
      "name": "Schedule Every 15min",
      "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": "Set Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        -672,
        224
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "var1",
              "name": "PROXMOX_IP",
              "type": "string",
              "value": "0.0.0.0"
            },
            {
              "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 Login",
      "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": "Prepare Auth",
      "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 List",
      "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 - Node Tasks",
      "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 - Node Status",
      "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 - Get Sensors",
      "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": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5d2150c2-34b8-4cbc-8b08-263dc9a2b583",
      "name": "Process Data",
      "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.]+)\u00b0C/);\n    const highMatch = line.match(/high\\s*=\\s*([+\\-]?[0-9.]+)\u00b0C/);\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}\u00b0C (Min: ${minTemp}\u00b0C, Max: ${maxTemp}\u00b0C)`;\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": "Generate Formatted Message",
      "type": "n8n-nodes-base.code",
      "position": [
        528,
        352
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\nconst tempWarningEmoji = data.host.tempWarning ? '\ud83d\udd25 ' : '';\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 => `  \u2022 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>\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501</b>\n<b>Virtual Machines</b>\n<b>\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501</b>\n\n<b>Total VMs:</b> ${data.vms.total}\n<b>Running:</b> ${data.vms.running} \u2705\n<b>Stopped:</b> ${data.vms.stopped} \u26d4\n<b>Recently Stopped:</b> ${data.vms.recentlyStopped} \u26a0\ufe0f${recentlyStoppedSection}\n\n<b>\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501</b>\n<b>Host Resources</b>\n<b>\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501</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>\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501</b>\n<b>${tempWarningEmoji}${tempTitle}</b>\n<b>\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501</b>\n\n<code>${data.host.temperature}</code>`;\n\nreturn { message };"
      },
      "typeVersion": 2
    },
    {
      "id": "81a4878f-35a2-44d1-81a2-ca209d6e70e3",
      "name": "Send Telegram Report",
      "type": "n8n-nodes-base.telegram",
      "position": [
        816,
        224
      ],
      "parameters": {
        "text": "={{ $json.message }}",
        "chatId": "={{ $('Set Variables').first().json.TELEGRAM_CHAT_ID }}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "31ae9494-5e80-40be-8aea-4ca982960dbc",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1184,
        16
      ],
      "parameters": {
        "width": 380,
        "height": 180,
        "content": "## Proxmox Monitoring Workflow\n\nMonitors your Proxmox VE server every 15 minutes and sends automated reports via Telegram.\n\nTracks VM status, host resources, temperature sensors, and recently stopped VMs."
      },
      "typeVersion": 1
    },
    {
      "id": "467412ef-997f-4666-81e2-01c3fb23202f",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -784,
        400
      ],
      "parameters": {
        "width": 320,
        "height": 292,
        "content": "## CONFIGURATION REQUIRED\n\n1. Set your Proxmox IP, port, and node name\n2. Enter Proxmox username (with realm, e.g. root@pam)\n3. Add your Proxmox password\n4. Set your Telegram Chat ID\n\nRequires: lm-sensors installed on Proxmox host"
      },
      "typeVersion": 1
    },
    {
      "id": "9f4196b9-741d-4536-b487-89be23dfa9e3",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -432,
        -16
      ],
      "parameters": {
        "width": 300,
        "height": 204,
        "content": "## Authentication Flow\n\nLogs into Proxmox API to obtain:\n- Session ticket (valid 15 minutes)\n- CSRF prevention token\n\nBoth are required for subsequent API calls"
      },
      "typeVersion": 1
    },
    {
      "id": "23393f4f-3ba3-4900-aec5-7952f9b64586",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        608
      ],
      "parameters": {
        "width": 300,
        "height": 272,
        "content": "## Data Collection\n\nGathers data from Proxmox API:\n- VM list and status\n- Recent task log (stop/shutdown events)\n- Node resources (CPU, memory, uptime)\n\nRuns sequentially to ensure authenticated requests"
      },
      "typeVersion": 1
    },
    {
      "id": "7be5a2e6-d39a-4b4f-9cfd-888eab5261ce",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        176,
        -16
      ],
      "parameters": {
        "width": 300,
        "height": 220,
        "content": "## SSH Temperature Check\n\nConnects via SSH to read temperature sensors using the sensors command.\n\nRequires SSH Password credential configured with your Proxmox host details."
      },
      "typeVersion": 1
    },
    {
      "id": "af79ac1a-e92a-47aa-b541-4d038175f28e",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        -128
      ],
      "parameters": {
        "width": 320,
        "height": 264,
        "content": "## Data Processing\n\nAnalyzes all collected data:\n- Counts running/stopped VMs\n- Detects VMs stopped in last 15 minutes\n- Calculates resource usage percentages\n- Evaluates temperature thresholds\n- Formats uptime statistics\n\nGenerates structured report with HTML formatting for Telegram"
      },
      "typeVersion": 1
    },
    {
      "id": "e4bc84d3-85ba-4cbe-bb21-8832642ddf82",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        816,
        384
      ],
      "parameters": {
        "width": 300,
        "height": 256,
        "content": "## TELEGRAM CONFIGURATION\n\n1. Create bot via @BotFather\n2. Get bot token and add as credential\n3. Chat ID already set in Set Variables node\n\nMessages use HTML parse mode for formatting"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "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
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This n8n workflow monitors your Proxmox VE server and sends automated reports to Telegram every 15 minutes. It tracks VM status, host resource usage, temperature sensors, and detects recently stopped VMs. n8n instance (self-hosted or cloud) Proxmox VE server with API access…

Source: https://n8n.io/workflows/9733/ — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

Automatically fetch existing domains from Notion's Database and verify the validity of SSL certificates through SSL-Checker. If the validity period is less than 14 days, send a Telegram message notifi

HTTP Request, Notion, Execute Workflow Trigger +2
Slack & Telegram

This workflow is for system administrators or self-hosted n8n users who want to automatically check and update their n8n instance to the latest version — with Telegram notifications for every step. Th

HTTP Request, Telegram, n8n +2
Slack & Telegram

GNCA AI News Pipeline. Uses rssFeedRead, httpRequest, telegram, errorTrigger. Scheduled trigger; 29 nodes.

RSS Feed Read, HTTP Request, Telegram +1
Slack & Telegram

n8n update. Uses ssh, manualTrigger, scheduleTrigger, stickyNote. Event-driven trigger; 27 nodes.

Ssh, HTTP Request, Telegram
Slack & Telegram

This workflow is for DevOps engineers, system administrators, and Docker users who want to automate the process of checking for updates, verifying them, and applying updates to their Docker-based depl

Ssh, HTTP Request, Telegram