AutomationFlowsSlack & Telegram › Automated Homelab Updates via Discord & SSH

Automated Homelab Updates via Discord & SSH

Original n8n title: Homelab

HomeLab. Uses scheduleTrigger, discord, ssh. Scheduled trigger; 8 nodes.

Cron / scheduled trigger★★★★☆ complexity8 nodesDiscordSsh
Slack & Telegram Trigger: Cron / scheduled Nodes: 8 Complexity: ★★★★☆ Added:

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
{
  "updatedAt": "2025-10-06T04:57:49.000Z",
  "createdAt": "2025-07-29T18:48:28.008Z",
  "id": "X5baTUVFHhvSO1SC",
  "name": "HomeLab",
  "active": true,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -720,
        -288
      ],
      "id": "ab1cfe2d-a3d2-4f14-91ea-fc161b070951",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "authentication": "webhook",
        "content": "={{ $json.message }}",
        "options": {}
      },
      "type": "n8n-nodes-base.discord",
      "typeVersion": 2,
      "position": [
        -48,
        -288
      ],
      "id": "146421f7-1e45-486b-98a4-4deb773b9669",
      "name": "Discord",
      "credentials": {
        "discordWebhookApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const output = $('update system').first().json.stdout\nlet message = \"\";\nlet status = \"\u2705\";\nconst logSnippet = output.slice(-1000);\nconst userId = \"664803448629493816\"; // Ganti dengan user Discord yang ingin ditag\nconst mention = `<@${userId}>`;\n\nif (output.toLowerCase().includes(\"error\") || output.toLowerCase().includes(\"failed\")) {\n  status = \"\u274c\";\n  message = `\\`\\`\\`\\n${logSnippet}\\n\\`\\`\\`\\n\u274c Update failed!\\n${mention}`;\n} else if (output.toLowerCase().includes(\"a reboot is required\")) {\n  status = \"\ud83d\udd04\";\n  message = `\\`\\`\\`\\n${logSnippet}\\n\\`\\`\\`\\n\ud83d\udd04 Update completed but reboot is required.\\n${mention}`;\n} else {\n  status = \"\u2705\";\n  message = `\\`\\`\\`\\n${logSnippet}\\n\\`\\`\\`\\n\u2705 System updated successfully!`;\n}\n\nreturn [{\n  json: {\n    status,\n    message\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -272,
        -288
      ],
      "id": "d5808171-3559-4005-9116-b68f0adad9c8",
      "name": "Code"
    },
    {
      "parameters": {
        "authentication": "webhook",
        "content": "={{ $json.content }}\n-----------------------------------------",
        "options": {}
      },
      "type": "n8n-nodes-base.discord",
      "typeVersion": 2,
      "position": [
        -48,
        -64
      ],
      "id": "ba513429-2751-4051-b2d3-edf67c497de2",
      "name": "Discord1",
      "credentials": {
        "discordWebhookApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const rawLog = $input.first().json.stdout;  // log input dari node sebelumnya\n\nconst updatedImages = [];\nconst failedImages = [];\n\nconst lines = rawLog.split(\"\\n\");\n\nfor (let i = 0; i < lines.length; i++) {\n  const line = lines[i].trim();\n\n  // Cek baris \"Pulling image\"\n  if (line.startsWith(\"[*] Pulling image:\")) {\n    const image = line.replace(\"[*] Pulling image: \", \"\").trim();\n    const statusLine = lines[i + 3] || \"\";  // Baris ke-3 setelah ini biasanya status\n    const errorLine = lines[i + 1] || \"\";   // Jika error, muncul setelah ini\n\n    if (statusLine.includes(\"Image is up to date\")) {\n      // Lewatkan (tidak perlu dicatat)\n    } else if (errorLine.includes(\"Error response from daemon\")) {\n      failedImages.push(`${image} \u274c`);\n    } else {\n      updatedImages.push(`${image} \u2705`);\n    }\n  }\n}\n\n// Format pesan\nconst startedAt = rawLog.match(/Started at (.+?) ===/i)?.[1] || \"Unknown\";\nconst completedAt = rawLog.match(/Completed at (.+?) ===/i)?.[1] || \"Unknown\";\n\nlet message = `\ud83d\udee0\ufe0f **Docker Auto Update Summary**\\n\\n`;\nmessage += `\ud83d\udd53 **Started**: ${startedAt}\\n\u2705 **Completed**: ${completedAt}\\n\\n`;\n\nif (updatedImages.length > 0) {\n  message += `\ud83d\udd04 **Updated Images:**\\n${updatedImages.map(i => `\u2022 ${i}`).join(\"\\n\")}\\n\\n`;\n}\n\nif (failedImages.length > 0) {\n  message += `\u2757 **Failed Pulls:**\\n${failedImages.map(i => `\u2022 ${i}`).join(\"\\n\")}\\n\\n`;\n}\n\nif (updatedImages.length === 0 && failedImages.length === 0) {\n  message += `\ud83d\udce6 All containers already up to date.\\n`;\n}\n\nreturn [\n  {\n    json: {\n      content: message  // Output ke Discord node\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -272,
        -64
      ],
      "id": "2566227c-7ce0-498a-b457-bff46bf30732",
      "name": "Code1"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 3
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -720,
        -64
      ],
      "id": "ddf8f63b-c2d1-4ac1-ac51-86d0760cfc1a",
      "name": "Schedule Trigger1"
    },
    {
      "parameters": {
        "command": "sudo nala update && sudo nala upgrade -y"
      },
      "type": "n8n-nodes-base.ssh",
      "typeVersion": 1,
      "position": [
        -496,
        -288
      ],
      "id": "683f5583-acd1-4443-9c9c-091509c29b68",
      "name": "update system",
      "credentials": {
        "sshPassword": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "command": "sudo ./autoupdate.sh",
        "cwd": "/home/n8nbot/dockerUpdate"
      },
      "type": "n8n-nodes-base.ssh",
      "typeVersion": 1,
      "position": [
        -496,
        -64
      ],
      "id": "38bb81de-883a-486d-8c34-8dc590a392bd",
      "name": "update docker",
      "credentials": {
        "sshPassword": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "update system",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "Discord",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code1": {
      "main": [
        [
          {
            "node": "Discord1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger1": {
      "main": [
        [
          {
            "node": "update docker",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "update system": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "update docker": {
      "main": [
        [
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": "AvhjGJdACMdnvIEn"
  },
  "staticData": {
    "node:Schedule Trigger": {
      "recurrenceRules": []
    },
    "node:Schedule Trigger1": {
      "recurrenceRules": []
    },
    "node:Metopen": {
      "recurrenceRules": []
    },
    "node:AI": {
      "recurrenceRules": []
    },
    "node:Informasi": {
      "recurrenceRules": []
    },
    "node:Jaringan": {
      "recurrenceRules": []
    },
    "node:Distribusi": {
      "recurrenceRules": []
    },
    "node:Embedded": {
      "recurrenceRules": []
    },
    "node:Sinyal": {
      "recurrenceRules": []
    },
    "node:Tatul": {
      "recurrenceRules": []
    },
    "node:prak distribusi": {
      "recurrenceRules": []
    },
    "node:PrakEmbedded": {
      "recurrenceRules": []
    }
  },
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "versionId": "d1dced24-4b25-45dc-9e2e-3a376d75255f",
  "triggerCount": 2,
  "shared": [
    {
      "updatedAt": "2025-07-29T18:48:28.014Z",
      "createdAt": "2025-07-29T18:48:28.014Z",
      "role": "workflow:owner",
      "workflowId": "X5baTUVFHhvSO1SC",
      "projectId": "DiQC0tGxFhuiK9UM"
    }
  ],
  "tags": []
}

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

HomeLab. Uses scheduleTrigger, discord, ssh. Scheduled trigger; 8 nodes.

Source: https://github.com/SamVivan1/n8n-Workflows-Backup/blob/main/homelab-X5baTUVFHhvSO1SC.json — 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

Absen Otomatis. Uses discord, ssh, scheduleTrigger, executeWorkflowTrigger. Scheduled trigger; 16 nodes.

Discord, Ssh, Execute Workflow Trigger
Slack & Telegram

Absen Nami. Uses ssh, discord, scheduleTrigger. Scheduled trigger; 13 nodes.

Ssh, Discord
Slack & Telegram

Absen Nay. Uses ssh, discord, scheduleTrigger. Scheduled trigger; 13 nodes.

Ssh, Discord
Slack & Telegram

Wait Schedule. Uses spotify, supabase, compareDatasets, noOp. Scheduled trigger; 54 nodes.

Spotify, Supabase, YouTube +1
Slack & Telegram

This n8n template demonstrates how to automatically monitor and track username and nickname changes across your Discord server members. Perfect for community moderation, security monitoring, and maint

Discord, Data Table