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 →
{
"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.
discordWebhookApisshPassword
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 →