이메일 승인 및 SSH를 사용한 Docker 기반 n8n 업데이트 자동화
고급
이것은DevOps분야의자동화 워크플로우로, 27개의 노드를 포함합니다.주로 If, Set, Ssh, EmailSend, HttpRequest 등의 노드를 사용하며. 이메일 승인 및 SSH를 사용한 Docker 기반 n8n 업데이트 자동화
사전 요구사항
- •대상 API의 인증 정보가 필요할 수 있음
카테고리
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
"meta": {
"instanceId": "0cf1013c00750bfab7ca7f6a76bf0e8c2407d7a4a9a4e66c4888ec456837f043",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "6486fadd-3584-4544-9a02-57ede53e836b",
"name": "메모 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3456,
-448
],
"parameters": {
"color": 4,
"width": 280,
"height": 288,
"content": "## 🚀 WORKFLOW START\n\n**Triggers:**\n- Manual execution (test runs)\n- Automated every 3 days at 4 PM UTC\n\nThis workflow checks for n8n updates and sends an approval email, to automatically update the n8n instance."
},
"typeVersion": 1
},
{
"id": "683461fc-856d-41e8-9d49-9b725fa3a2fa",
"name": "일정 트리거",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-3120,
-368
],
"parameters": {
"rule": {
"interval": [
{
"daysInterval": 3,
"triggerAtHour": 16
}
]
}
},
"typeVersion": 1.2
},
{
"id": "ab507d4a-1a4c-49de-9b32-07f60969b0e7",
"name": "If No Changes",
"type": "n8n-nodes-base.if",
"position": [
-2000,
-368
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "47b24202-69ea-481a-8848-67de206ea3c0",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.update_available }}",
"rightValue": "=Download complete"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "bcdcdc19-e21c-48fb-80bb-014144c6fa6a",
"name": "Check Existence of Update Script",
"type": "n8n-nodes-base.ssh",
"position": [
-1328,
-384
],
"parameters": {
"cwd": "/root",
"command": "=sh -c \"if [ -f update_docker.sh ]; then echo true; else echo false; fi\""
},
"credentials": {
"sshPassword": {
"id": "09btBw3BAMtH8hXO",
"name": "SSH Password account"
}
},
"typeVersion": 1
},
{
"id": "a9cbbad8-5f2f-411f-bc4a-62230e93c0e2",
"name": "If File Exists",
"type": "n8n-nodes-base.if",
"position": [
-1104,
-384
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1cf2c480-a309-46bc-a0c4-c2cf9827822d",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.stdout }}",
"rightValue": "true"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "ba972070-a78a-4982-975f-7219f26571e3",
"name": "Create Update Script",
"type": "n8n-nodes-base.ssh",
"position": [
-880,
-304
],
"parameters": {
"cwd": "/root",
"command": "=sh -c \"printf '%s\\n' 'sleep 30s' 'cd /opt/n8n-docker-caddy' 'docker compose pull' 'docker compose down' 'docker compose up -d' > update_docker.sh; chmod +x update_docker.sh\""
},
"credentials": {
"sshPassword": {
"id": "09btBw3BAMtH8hXO",
"name": "SSH Password account"
}
},
"typeVersion": 1
},
{
"id": "12f9fcab-8bcb-4bea-8e66-69f5227fb7bf",
"name": "If Approved",
"type": "n8n-nodes-base.if",
"position": [
-1552,
-272
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "32c6b0f0-0747-47de-90e4-56ded46d3d34",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": "true"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "f3a6c807-0f12-45b6-bed7-ce4cbda4e42b",
"name": "No Updates",
"type": "n8n-nodes-base.noOp",
"position": [
-1776,
-464
],
"parameters": {},
"typeVersion": 1
},
{
"id": "3a90a6d9-b1b1-4f9b-8194-676dccbdb5a5",
"name": "Do Nothing",
"type": "n8n-nodes-base.noOp",
"position": [
-1328,
-160
],
"parameters": {},
"typeVersion": 1
},
{
"id": "c1dbc70c-db44-4f5c-9854-64d34d9f114f",
"name": "Ask For Approval to Update",
"type": "n8n-nodes-base.emailSend",
"position": [
-1776,
-272
],
"webhookId": "c1c2c77a-a3c1-4c4d-83e9-229dfc3b0903",
"parameters": {
"message": "=<h2>🔔 n8n Update Available</h2>\n\n<p>A new version of n8n is available on Docker Hub!</p>\n\n<table style=\"border-collapse: collapse; width: 100%; margin: 20px 0;\">\n <tr style=\"background-color: #f8f9fa;\">\n <td style=\"padding: 12px; border: 1px solid #dee2e6; font-weight: bold;\">Current Version:</td>\n <td style=\"padding: 12px; border: 1px solid #dee2e6;\">{{ $json.current_version }}</td>\n </tr>\n <tr>\n <td style=\"padding: 12px; border: 1px solid #dee2e6; font-weight: bold;\">New Version Available:</td>\n <td style=\"padding: 12px; border: 1px solid #dee2e6; color: #28a745; font-weight: bold;\">Latest from Docker Hub</td>\n </tr>\n <tr style=\"background-color: #f8f9fa;\">\n <td style=\"padding: 12px; border: 1px solid #dee2e6; font-weight: bold;\">Local Digest:</td>\n <td style=\"padding: 12px; border: 1px solid #dee2e6; font-family: monospace; font-size: 11px;\">{{ $json.local_digest }}</td>\n </tr>\n <tr>\n <td style=\"padding: 12px; border: 1px solid #dee2e6; font-weight: bold;\">Remote Digest:</td>\n <td style=\"padding: 12px; border: 1px solid #dee2e6; font-family: monospace; font-size: 11px;\">{{ $json.remote_digest }}</td>\n </tr>\n</table>\n\n<h3>📋 What happens if you approve?</h3>\n<ol>\n <li>Pull the new n8n Docker image from Docker Hub</li>\n <li>Restart the n8n container with the new version</li>\n</ol>\n\n<h3>🔧 Manual Update Option</h3>\n<p>If you prefer to update manually later, run these commands on your server:</p>\n<pre style=\"background-color: #f8f8f8; padding: 10px; border-radius: 4px; border: 1px solid #ddd;\">\ncd /opt/n8n-docker-caddy\ndocker compose pull\ndocker compose down\ndocker compose up -d\n</pre>\n\n<p><strong>Do you want to proceed with the automatic update?</strong></p>",
"options": {
"limitWaitTime": {
"values": {
"resumeAmount": 3
}
},
"appendAttribution": false
},
"subject": "Approval Required for Updating n8n!",
"toEmail": "youremail@yourdomain.com",
"fromEmail": "info@yourdomain.com",
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double"
}
}
},
"credentials": {
"smtp": {
"id": "7qY1U0ZUdM7HKciv",
"name": "SMTP account"
}
},
"typeVersion": 2.1
},
{
"id": "0829b238-0c14-4be8-bbf1-edaa63016b51",
"name": "메모 - Auto Update",
"type": "n8n-nodes-base.stickyNote",
"position": [
-992,
-112
],
"parameters": {
"color": 6,
"width": 320,
"height": 432,
"content": "## 🔧 AUTOMATED UPDATE PROCESS\n\n**Three-step update execution:**\n\n1. **Check Script**: Verify if update script exists\n2. **Create Script** (if needed): Generate update script with:\n - 30-second delay\n - Navigate to docker directory\n - Execute update commands\n3. **Execute**: Run script in background via `nohup`\n\n**The 60-second delay ensures this workflow completes before container restarts!**"
},
"typeVersion": 1
},
{
"id": "c68450b6-ff97-4be4-932f-42dbabdab811",
"name": "메모 - Script Logic",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1392,
-672
],
"parameters": {
"color": 7,
"width": 280,
"height": 248,
"content": "## 🎯 SCRIPT LOGIC\n\n**Optimizes script creation:**\n\n- If script exists → Use it directly\n- If script missing → Create new one\n\nPrevents unnecessary file operations and ensures idempotency."
},
"typeVersion": 1
},
{
"id": "277ab82a-701a-4edc-8def-1dab9165ebe2",
"name": "메모 - Final Execution",
"type": "n8n-nodes-base.stickyNote",
"position": [
-976,
-752
],
"parameters": {
"color": 3,
"width": 320,
"height": 328,
"content": "## 🚀 FINAL EXECUTION\n\n**Runs in background:**\n\nExecutes `update_docker.sh` with:\n- `nohup`: Runs independently of this session\n- `> update.log`: Logs output for debugging\n- `2>&1`: Captures both stdout and stderr\n- `&`: Background execution\n\n**Workflow completes immediately, update happens 30 seconds later!**"
},
"typeVersion": 1
},
{
"id": "5a44fe76-5ca3-4477-9f5d-486c8abec4ab",
"name": "Execute Update Script",
"type": "n8n-nodes-base.ssh",
"position": [
-656,
-400
],
"parameters": {
"cwd": "/root",
"command": "=sh -c \"exec >/root/update.log 2>&1; nohup /root/update_docker.sh &\""
},
"credentials": {
"sshPassword": {
"id": "09btBw3BAMtH8hXO",
"name": "SSH Password account"
}
},
"typeVersion": 1
},
{
"id": "9a65a79e-eb2e-4ad2-8920-fe6a4a8053c6",
"name": "메모",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3536,
-928
],
"parameters": {
"color": 5,
"width": 3104,
"height": 1520,
"content": "# n8n-Self-Updater"
},
"typeVersion": 1
},
{
"id": "9b195a5d-3057-4690-9a7f-63947349df7b",
"name": "Get Local Image Digest",
"type": "n8n-nodes-base.ssh",
"position": [
-2672,
-368
],
"parameters": {
"cwd": "/root",
"command": "sh -c \"docker inspect n8n-docker-caddy-n8n-1 --format='{{index .Image}}' | xargs docker inspect --format='{{index .RepoDigests 0}}'\""
},
"credentials": {
"sshPassword": {
"id": "09btBw3BAMtH8hXO",
"name": "SSH Password account"
}
},
"typeVersion": 1
},
{
"id": "9f46efa6-bfa4-43cc-bc8b-50f4789bfc3f",
"name": "Get Remote Image Digest",
"type": "n8n-nodes-base.httpRequest",
"position": [
-2448,
-368
],
"parameters": {
"url": "https://hub.docker.com/v2/repositories/n8nio/n8n/tags/latest",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "b06e54b7-3760-46b6-b35b-95f74ea19ada",
"name": "메모 9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2224,
-672
],
"parameters": {
"width": 320,
"height": 264,
"content": "## 🔀 UPDATE CHECK\n\n**Checks if update exists:**\n\nCompares local vs remote digest:\n- If digests match → No update (top path)\n- If digests differ → Update available (bottom path)\n\n**Prevents unnecessary email notifications!**"
},
"typeVersion": 1
},
{
"id": "ef630305-91e7-4d78-9a8d-a2729063ddb0",
"name": "Prepare Update Data",
"type": "n8n-nodes-base.set",
"position": [
-2224,
-368
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "832662b6-8fe8-4849-870b-71d32bf88a46",
"name": "current_version",
"type": "string",
"value": "={{ $('Get Current n8n Version').first().json.stdout }}"
},
{
"id": "local-digest-assign",
"name": "local_digest",
"type": "string",
"value": "={{ $('Get Local Image Digest').first().json.stdout.split('@')[1] }}"
},
{
"id": "remote-digest-assign",
"name": "remote_digest",
"type": "string",
"value": "={{ $('Get Remote Image Digest').first().json.digest }}"
},
{
"id": "new-version-assign",
"name": "update_available",
"type": "boolean",
"value": "={{ $('Get Local Image Digest').first().json.stdout.split('@')[1] !== $('Get Remote Image Digest').first().json.digest }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "71409d64-8391-4f08-8359-223728303c20",
"name": "메모",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1840,
-736
],
"parameters": {
"color": 4,
"width": 320,
"height": 224,
"content": "## ⛔ NO UPDATES FOUND\n\nWorkflow ends when:\n- Local and remote digests match\n- Already running latest version\n\n**No unnecessary emails!**\n\nWorkflow completes silently."
},
"typeVersion": 1
},
{
"id": "1c01f1f9-5c06-41fd-a130-44c43f9a5c11",
"name": "메모 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2864,
-656
],
"parameters": {
"color": 5,
"width": 280,
"height": 248,
"content": "## 🔍 GET CURRENT INFO\n\nRetrieves:\n1. Current n8n version\n2. Local image digest (RepoDigest)\n\nThis tells us what we're currently running."
},
"typeVersion": 1
},
{
"id": "09ef5f83-d20d-489f-9199-aa1ce267427b",
"name": "메모 4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2528,
-144
],
"parameters": {
"color": 6,
"width": 280,
"height": 236,
"content": "## 🔎 CHECK REMOTE DIGEST\n\nQueries Docker Hub registry to get:\n- Remote image digest for :latest tag\n- WITHOUT pulling the image!\n\nUses Docker Registry HTTP API v2."
},
"typeVersion": 1
},
{
"id": "0aaada39-31ce-49b8-8526-b22264de5092",
"name": "Get Current n8n Version",
"type": "n8n-nodes-base.ssh",
"position": [
-2896,
-368
],
"parameters": {
"cwd": "/root",
"command": "=sh -c \"docker exec n8n-docker-caddy-n8n-1 n8n --version\""
},
"credentials": {
"sshPassword": {
"id": "09btBw3BAMtH8hXO",
"name": "SSH Password account"
}
},
"typeVersion": 1
},
{
"id": "9982be9b-af55-4364-a29a-d70dca2af86e",
"name": "메모 5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1888,
-64
],
"parameters": {
"color": 3,
"width": 320,
"height": 232,
"content": "## 📧 APPROVAL REQUEST\n\nSends email with:\n- Current version\n- Digest comparison\n- **Approve/Disapprove buttons**\n\nn8n stays exactly as-is until you click APPROVE!"
},
"typeVersion": 1
},
{
"id": "4cf50320-6d4a-4af1-ac91-941f8f2c7851",
"name": "메모 - Declined1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1408,
0
],
"parameters": {
"color": 4,
"width": 280,
"height": 248,
"content": "## 🛑 UPDATE DECLINED\n\nWorkflow ends when:\n- User clicks **Decline**\n- Update will wait for next check or manual execution\n\n**Manual option always available!**"
},
"typeVersion": 1
},
{
"id": "69673ede-0abc-43ec-86ea-5ae72a6289d2",
"name": "메모 6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4080,
-160
],
"parameters": {
"color": 2,
"width": 496,
"height": 408,
"content": "## 📊 WORKFLOW SUMMARY\n\n**Flow:**\n1. Get current version + local digest\n2. Get remote digest from Docker Hub\n3. Compare digests\n4. If different → Request approval with version info\n5. If approved → Pull and restart\n6. If same → Silent skip\n\n**Benefits:**\n- Bandwidth efficient\n- Clear version comparison\n- Manual approval control\n- No spam when no updates"
},
"typeVersion": 1
},
{
"id": "b1613e0c-a14f-4903-96c3-dedd46423a25",
"name": "설정up Requirements",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4080,
-928
],
"parameters": {
"width": 500,
"height": 704,
"content": "## 🧩 SETUP REQUIREMENTS\n\n**1️⃣ SSH Credentials**\n- Go to *Credentials → New → SSH Password*\n- Enter:\n - Host: your VPS IP (e.g., 165.22.xx.xx)\n - Port: 22\n - Username: root / ubuntu\n - Password or Private Key\n\n\n**2️⃣ SMTP Credentials (Email)**\n- Go to *Credentials → New → SMTP*\n- Fill in:\n - Host: smtp.yourprovider.com\n - Port: 465 (SSL) / 587 (TLS)\n - User: your email\n - Password: email password or app password\n\n\n**3️⃣ Docker Server Setup**\n- Ensure Docker + docker-compose are installed\n- n8n is deployed via docker-compose (e.g., /opt/n8n-docker-caddy)\n\n\n**4️⃣ Workflow Setup**\n- Import the JSON workflow\n- Edit Email Node → update `fromEmail` & `toEmail`\n- Connect correct SSH + SMTP credentials\n- Enable Schedule Trigger (optional)\n\n✅ Once complete, test manually before activating auto checks."
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"12f9fcab-8bcb-4bea-8e66-69f5227fb7bf": {
"main": [
[
{
"node": "bcdcdc19-e21c-48fb-80bb-014144c6fa6a",
"type": "main",
"index": 0
}
],
[
{
"node": "3a90a6d9-b1b1-4f9b-8194-676dccbdb5a5",
"type": "main",
"index": 0
}
]
]
},
"ab507d4a-1a4c-49de-9b32-07f60969b0e7": {
"main": [
[
{
"node": "f3a6c807-0f12-45b6-bed7-ce4cbda4e42b",
"type": "main",
"index": 0
}
],
[
{
"node": "c1dbc70c-db44-4f5c-9854-64d34d9f114f",
"type": "main",
"index": 0
}
]
]
},
"a9cbbad8-5f2f-411f-bc4a-62230e93c0e2": {
"main": [
[
{
"node": "5a44fe76-5ca3-4477-9f5d-486c8abec4ab",
"type": "main",
"index": 0
}
],
[
{
"node": "ba972070-a78a-4982-975f-7219f26571e3",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "0aaada39-31ce-49b8-8526-b22264de5092",
"type": "main",
"index": 0
}
]
]
},
"ef630305-91e7-4d78-9a8d-a2729063ddb0": {
"main": [
[
{
"node": "ab507d4a-1a4c-49de-9b32-07f60969b0e7",
"type": "main",
"index": 0
}
]
]
},
"ba972070-a78a-4982-975f-7219f26571e3": {
"main": [
[
{
"node": "5a44fe76-5ca3-4477-9f5d-486c8abec4ab",
"type": "main",
"index": 0
}
]
]
},
"9b195a5d-3057-4690-9a7f-63947349df7b": {
"main": [
[
{
"node": "9f46efa6-bfa4-43cc-bc8b-50f4789bfc3f",
"type": "main",
"index": 0
}
]
]
},
"0aaada39-31ce-49b8-8526-b22264de5092": {
"main": [
[
{
"node": "9b195a5d-3057-4690-9a7f-63947349df7b",
"type": "main",
"index": 0
}
]
]
},
"9f46efa6-bfa4-43cc-bc8b-50f4789bfc3f": {
"main": [
[
{
"node": "ef630305-91e7-4d78-9a8d-a2729063ddb0",
"type": "main",
"index": 0
}
]
]
},
"c1dbc70c-db44-4f5c-9854-64d34d9f114f": {
"main": [
[
{
"node": "12f9fcab-8bcb-4bea-8e66-69f5227fb7bf",
"type": "main",
"index": 0
}
]
]
},
"bcdcdc19-e21c-48fb-80bb-014144c6fa6a": {
"main": [
[
{
"node": "a9cbbad8-5f2f-411f-bc4a-62230e93c0e2",
"type": "main",
"index": 0
}
]
]
}
}
}자주 묻는 질문
이 워크플로우를 어떻게 사용하나요?
위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.
이 워크플로우는 어떤 시나리오에 적합한가요?
고급 - 데브옵스
유료인가요?
이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.
관련 워크플로우 추천
n8n 업데이트
Telegram 승인 시스템을 사용한 Docker 컨테이너 업데이트 자동화
If
Set
Ssh
+
If
Set
Ssh
27 노드Jaber Zare
데브옵스
자동화된 n8n 워크플로우 백업至 GitHub 및 삭제 추적
삭제 추적이 포함된 GitHub 자동화 n8n 워크플로우 백업
If
N8n
Set
+
If
N8n
Set
31 노드Marcial Ambriz
데브옵스
셀프 호스팅 앱 자동 업데이트 (Coolify 배포)
Coolify 배포를 통한 자체 호스팅 애플리케이션 자동 업데이트
If
Set
Merge
+
If
Set
Merge
18 노드Edoardo Guzzi
데브옵스
Typebot 플로우와 GitHub 양방향 동기화, Typebot API 사용
Typebot API를 활용한 Typebot 플로우와 GitHub 양방향 동기화
If
Set
Code
+
If
Set
Code
31 노드Marcial Ambriz
데브옵스
GitHub 동기화 대시보드 - V2
提交 기록과 롤백 기능을 갖춘 GitHub 워크플로우 버전 관리 대시보드
If
N8n
Set
+
If
N8n
Set
94 노드Eduard
데브옵스
미국 하원 법안을 기반으로 Gemini AI를 사용하여 주간 동물권 행동 요약 보고서 생성
미국 하원 법안을 기반으로 Gemini AI를 사용하여 주간 동물권 행동 요약 보고서 생성
If
Set
Html
+
If
Set
Html
26 노드Open Paws
소셜 미디어