자동화된 웹사이트 가동 시간 모니터링 및 이메일 알림, GitHub 상태 페이지 업데이트
고급
이것은DevOps분야의자동화 워크플로우로, 19개의 노드를 포함합니다.주로 If, Code, Gmail, Github, Switch 등의 노드를 사용하며. 자동화 웹사이트 가동 시간 모니터링 및 이메일 알림, GitHub 상태 페이지 업데이트
사전 요구사항
- •Google 계정 및 Gmail API 인증 정보
- •GitHub Personal Access Token
- •대상 API의 인증 정보가 필요할 수 있음
카테고리
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
"id": "PAjyHjl5YdaEp6Y2",
"meta": {
"instanceId": "cb69a80257e9c986533bb4191c0c85ea4947fbef18ed5faeb970927362aeebdc",
"templateCredsSetupCompleted": true
},
"name": "Automated Website Uptime Monitor with Email Alerts & GitHub Status Page Update",
"tags": [],
"nodes": [
{
"id": "24b40a8b-20b2-4ead-87a4-0be04641323a",
"name": "일정 트리거",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-3568,
-80
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 2
}
]
}
},
"typeVersion": 1.2
},
{
"id": "09c86eff-846d-43d1-a93f-f398f2223d67",
"name": "HTTP 요청",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
-3360,
-80
],
"parameters": {
"url": "https://app.yourdomain.com/health",
"options": {
"response": {
"response": {
"fullResponse": true
}
}
}
},
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "7c7791f1-9174-4a60-b6bd-80f32d220952",
"name": "메모",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3808,
-480
],
"parameters": {
"color": 7,
"width": 400,
"height": 368,
"content": "> **About 📝**\n- Runs automatically every **2 minutes**.\n- Acts as the \"heartbeat\" of the workflow.\n- You can change the interval to any value (e.g., seconds, minutes, hours, days).\n- Useful when you want continuous monitoring without manual input.\nThe workflow checks your website every **2 minutes** (interval configurable). \n- If the website is **down (503, bad response, or error)** → it sends an email alert and updates the GitHub-hosted status page to show **Down**. \n- If the website is **up (200)** → it updates the GitHub-hosted status page to show **Up**. \n- The email notification includes an **HTML-formatted alert page**. \n- You can use GitHub Pages to **host the status page** publicly. \n"
},
"typeVersion": 1
},
{
"id": "99b08165-3c6c-4505-94e9-a23d7bdf606f",
"name": "메모1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3344,
160
],
"parameters": {
"color": 7,
"width": 320,
"height": 272,
"content": "> **HTML Request & Switch 📝**\n- Pings the target website (ex:(`https://app.yourdomain.com/health`).\n- Returns the **status code** and full response.\n- If website responds with **200**, site is considered **Up**.\n- If request fails (e.g., 503, ERR_BAD_RESPONSE), it will be treated as **Down**.\n- Always outputs data (even on error), ensuring the workflow doesn’t break.\n"
},
"typeVersion": 1
},
{
"id": "aad36f3c-6f6a-4c2a-9d9a-db60a08b54a7",
"name": "메모4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3312,
-224
],
"parameters": {
"width": 294,
"height": 80,
"content": "Here, upload your Website URL. EX: (`https://app.yourdomain.cc/health`)"
},
"typeVersion": 1
},
{
"id": "b4d88251-7516-4f8d-998b-86aa4e62f201",
"name": "메모2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2720,
-656
],
"parameters": {
"color": 7,
"width": 288,
"height": 256,
"content": "> **Email 📝**\n- Sends an **email alert** if the site is down.\n- Recipient: `example@gmail.com` (replace with your email/team DL).\n- Subject: \"Server Down\".\n- Message: Pre-styled HTML alert page with error details.\n- Can be customized for different recipients or notification styles.\n \n\n \n"
},
"typeVersion": 1
},
{
"id": "3c09250f-9f90-48fd-8a95-0c3d28ac3c90",
"name": "메모5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2608,
-368
],
"parameters": {
"width": 214,
"height": 80,
"content": "Upload with your Email ID.\nEX:\nexamaple@gmail.com"
},
"typeVersion": 1
},
{
"id": "741d5e5b-88f1-4acb-8ed8-0527f3c9448f",
"name": "메모6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2160,
192
],
"parameters": {
"color": 7,
"width": 560,
"height": 192,
"content": "> **Extract from File(Github)📝**\n\n-Extract the file from the Github Repository if the status is same (Extracted Status = Github Status) then make no changes/ no commit into Github.\n-If both are no same then commit the status in the Github."
},
"typeVersion": 1
},
{
"id": "348d04d6-1b88-4cb6-80f2-93a136850a81",
"name": "메모7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2464,
-144
],
"parameters": {
"height": 80,
"content": "-Upload your GitHub Repository owner URL.\n-Upload your Repository Name.\n"
},
"typeVersion": 1
},
{
"id": "83ddb904-7e94-4d2d-8cbe-a02e832435a1",
"name": "메모8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2800,
224
],
"parameters": {
"color": 7,
"width": 384,
"height": 368,
"content": "> **Template HTML Code & GitHub 📝**\n- Dynamically creates the **status page HTML (index.html) from the existing template**.\n- Two modes:\n - **Up** → Green status page with \"Server Up\".\n - **Down** → Red status page with error details (status code + error message).\n- You can fully customize the HTML & CSS here for branding.\n - Commits the newly generated `index.html` file to your GitHub repo.\n- Path: `index.html` in repository (default branch).\n- Commit message is configurable (default: \"test\").\n- If GitHub Pages is enabled, this file becomes the **live status page**."
},
"typeVersion": 1
},
{
"id": "d4f178ad-6597-4944-aa80-7335f26be23d",
"name": "Update Index.html file",
"type": "n8n-nodes-base.github",
"position": [
-1504,
-16
],
"webhookId": "efc7d4f3-037b-4ade-aab0-e9ec870bd39d",
"parameters": {
"owner": {
"__rl": true,
"mode": "url",
"value": "https://github.com/<OWNER_NAME>"
},
"filePath": "index.html",
"resource": "file",
"operation": "edit",
"binaryData": true,
"repository": {
"__rl": true,
"mode": "name",
"value": "status"
},
"commitMessage": "test"
},
"typeVersion": 1.1
},
{
"id": "7d86a237-36e6-4ce8-95cf-19ab8a58581d",
"name": "Send a notification mail",
"type": "n8n-nodes-base.gmail",
"position": [
-2832,
-384
],
"webhookId": "50a40372-a118-4922-9abe-ab5c3065b284",
"parameters": {
"sendTo": "example@gmail.com",
"message": "=\n <!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Status Page</title>\n <style>\n body {\n font-family: Arial, sans-serif;\n background: #f9fafb;\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n margin: 0;\n }\n\n .status-container {\n text-align: center;\n padding: 2rem 3rem;\n }\n\n .status {\n font-size: 2rem;\n font-weight: bold;\n margin: 1rem 0;\n }\n\n .up {\n color: #fff;\n background-color: #16a34a; /* green */\n }\n\n .down {\n color: #fff;\n background-color: #dc2626; /* red */\n }\n\n .label {\n font-size: 1rem;\n color: #fff;\n text-transform: uppercase;\n letter-spacing: 2px;\n }\n </style>\n</head>\n<body class=\"down\">\n <div class=\"status-container down\">\n <div class=\"label\">Server Status</div>\n <div class=\"status down\">Down</div>\n <div class=\"down\">503</div>\n <div class=\"down\">ERR_BAD_RESPONSE</div>\n </div>\n</body>\n</html>\n\t",
"options": {},
"subject": "Server Down"
},
"typeVersion": 2.1
},
{
"id": "ba9b1eb6-6fcd-4ca8-b308-2b0daad7c299",
"name": "Switch - status code",
"type": "n8n-nodes-base.switch",
"position": [
-3152,
-80
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "503",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1f49118f-0394-43bb-aaa0-2a850da82ac7",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.error.status }}",
"rightValue": 503
}
]
},
"renameOutput": true
},
{
"outputKey": "200",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "55486cce-71e5-4c93-a518-09c108a2f307",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.statusCode }}",
"rightValue": 200
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "ec136a3f-e79d-4480-8c19-893184458928",
"name": "Extract from File - Generated HTML",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-2528,
-16
],
"parameters": {
"options": {},
"operation": "text"
},
"typeVersion": 1
},
{
"id": "3e4c16f9-25f7-4944-958a-3f5c2a8651b9",
"name": "Template HTML 코드",
"type": "n8n-nodes-base.code",
"position": [
-2720,
-16
],
"parameters": {
"jsCode": "// n8n Code node (JavaScript)\n\nconst items = [];\n if ($input.first().json.statusCode){\n const htmlContent = `\n <!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Status Page</title>\n <style>\n body {\n font-family: Arial, sans-serif;\n background: #f9fafb;\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n margin: 0;\n }\n\n .status-container {\n text-align: center;\n padding: 2rem 3rem;\n }\n\n .status {\n font-size: 2rem;\n font-weight: bold;\n margin: 1rem 0;\n }\n\n .up {\n color: #fff;\n background-color: #16a34a; /* green */\n }\n\n .down {\n color: #fff;\n background-color: #dc2626; /* red */\n }\n\n .label {\n font-size: 1rem;\n color: #fff;\n text-transform: uppercase;\n letter-spacing: 2px;\n }\n </style>\n</head>\n<body class=\"up\">\n <div class=\"status-container up\">\n <div class=\"label\">Server Status</div>\n <div class=\"status\">Up</div>\n <!-- If server is down, replace above with -->\n <!-- <div class=\"status down\">Down</div> -->\n </div>\n</body>\n</html>\n\t`;\n\n\t// Convert HTML string to Base64\n\tconst base64Data = Buffer.from(htmlContent, 'utf-8').toString('base64');\n\n\t// Push result in binary format\n\titems.push({\n\t\tbinary: {\n\t\t\tdata: {\n\t\t\t\tfileName: 'index.html',\n\t\t\t\tmimeType: 'text/html',\n\t\t\t\tdata: base64Data,\n\t\t\t}\n\t\t}\n\t});\n\nreturn items;\n }\nelse if ($input.first().json.error.status) {\n const htmlContent = `\n <!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Status Page</title>\n <style>\n body {\n font-family: Arial, sans-serif;\n background: #f9fafb;\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n margin: 0;\n }\n\n .status-container {\n text-align: center;\n padding: 2rem 3rem;\n }\n\n .status {\n font-size: 2rem;\n font-weight: bold;\n margin: 1rem 0;\n }\n\n .up {\n color: #fff;\n background-color: #16a34a; /* green */\n }\n\n .down {\n color: #fff;\n background-color: #dc2626; /* red */\n }\n\n .label {\n font-size: 1rem;\n color: #fff;\n text-transform: uppercase;\n letter-spacing: 2px;\n }\n </style>\n</head>\n<body class=\"down\">\n <div class=\"status-container down\">\n <div class=\"label\">Server Status</div>\n <div class=\"status down\">Down</div>\n <div class=\"down\">${$input.first().json.error.status}</div>\n <div class=\"down\">${$input.first().json.error.code}</div>\n </div>\n</body>\n</html>\n\t`;\n\n\t// Convert HTML string to Base64\n\tconst base64Data = Buffer.from(htmlContent, 'utf-8').toString('base64');\n\n\t// Push result in binary format\n\titems.push({\n\t\tbinary: {\n\t\t\tdata: {\n\t\t\t\tfileName: 'index.html',\n\t\t\t\tmimeType: 'text/html',\n\t\t\t\tdata: base64Data,\n\t\t\t}\n\t\t}\n\t});\n\nreturn items;\n}\n\t"
},
"typeVersion": 2
},
{
"id": "4423f742-0144-4ffb-b28b-a6d108e3b5ca",
"name": "Get existing index.html file",
"type": "n8n-nodes-base.github",
"position": [
-2160,
-16
],
"webhookId": "8c6e35c4-1460-4620-a736-732f472881bd",
"parameters": {
"owner": {
"__rl": true,
"mode": "url",
"value": "https://github.com/<OWNER_NAME>"
},
"filePath": "index.html",
"resource": "file",
"operation": "get",
"repository": {
"__rl": true,
"mode": "name",
"value": "status"
},
"binaryPropertyName": "github_data",
"additionalParameters": {}
},
"typeVersion": 1.1
},
{
"id": "d9c2a2ee-5698-4a60-8ab9-1ff133d71505",
"name": "Extract from existing File (github)",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-1968,
-16
],
"parameters": {
"options": {},
"operation": "text",
"destinationKey": "github_data",
"binaryPropertyName": "github_data"
},
"typeVersion": 1
},
{
"id": "e310e8e7-ad13-4f9e-a4b6-12f45d33a62a",
"name": "If - Compare existing HTML file with generated HTML",
"type": "n8n-nodes-base.if",
"position": [
-1776,
-16
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ffd5eaf3-0a36-43ac-8529-03b71cf9f1c6",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.github_data }}",
"rightValue": "={{ $('Extract from File - Generated HTML').item.json.data }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "0deafbe1-d715-45b0-9fe4-ea910a6d8f83",
"name": "메모3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4880,
-496
],
"parameters": {
"width": 976,
"height": 2416,
"content": "# 🖥️ Automated Website Uptime Monitor with Email Alerts & GitHub Status Page Update \n\nThis n8n workflow continuously monitors your website’s availability, sends **email alerts** when the server goes down, and automatically updates a **status page (index.html)** in your GitHub repository to reflect the live status. \n\n---\n\n## 📌 Good to Know \n- The workflow checks your website every **2 minutes** (interval configurable). \n- If the website is **down (503, bad response, or error)** → it sends an email alert and updates the GitHub-hosted status page to show **Down**. \n- If the website is **up (200)** → it updates the GitHub-hosted status page to show **Up**. \n- The email notification includes an **HTML-formatted alert page**. \n- You can use GitHub Pages to **host the status page** publicly.\n\n### ℹ️ What is GitHub Pages? \n- GitHub Pages is a free hosting service provided by GitHub that lets you publish **static websites (HTML, CSS, JS)** directly from a GitHub repository. \n- You can use it to make your `index.html` status page publicly accessible with a URL like: \n\n\n### ⚡ How to Set Up GitHub Pages for Your Status Page \n1. Create a **new repository** on GitHub (recommended name: `status`). \n2. Add a blank `index.html` file (n8n workflow will later update this file). \n3. Go to your repository → **Settings** → **Pages**. \n4. Under **Source**, select the branch (`main` or `master`) and folder (`/root`). \n5. Save changes. \n6. Your status page will now be live at: `https://<USERNAME>.github.io/status`\n\n\n## ✅ Prerequisites \n- An **n8n instance** (self-hosted or cloud). \n- A **GitHub account & repository** (to host the status page). \n- A **Gmail account** (or any email service supported by n8n – example uses Gmail). \n- Access to the target **website URL** you want to monitor. \n\n---\n\n## ⚙️ How it Works \n1. **Schedule Trigger** → Runs every 2 minutes. \n2. **HTTP Request** → Pings your website URL. \n3. **Switch Node** → Evaluates the response status (200 OK vs error/503). \n4. **Code Node** → Generates a dynamic **HTML status page** (Up/Down).\n5. **GitHub Repo & File** → Github Repo Name Should be `https://github.com/<OWNER_NAME>/status` (recommended) & Must have(required) a blank file named as `index.html` before triggering this flow.\n5. **GitHub Node** → Updates/commits the `index.html` file in your repository. \n6. **Gmail Node** → Sends an email alert if the site is down. \n\n---\n\n## 🚀 How to Use \n1. Import the workflow JSON into your **n8n instance**. \n2. Configure credentials for: \n - **GitHub** (Personal Access Token with repo permissions). \n - **Gmail** (or your preferred email service). \n3. Replace the following: \n - `https://app.yourdomain.com/health` → with your own website URL. \n - `example@gmail.com` → with your email address (or distribution list). \n - GitHub repo details → with your repository where `index.html` will live. \n4. Deploy the workflow. \n5. (Optional) Enable **GitHub Pages** on your repo to serve `index.html` as a live status page. \n\n---\n\n## 🛠 Requirements \n- n8n v1.0+ \n- GitHub personal access token \n- Gmail API credentials (or SMTP/email service of your choice) \n\n---\n\n## 🎨 Customising this Workflow \n- **Interval** → Change schedule from 2 minutes to any desired frequency. \n- **Email Content** → Modify HTML alert template in the Gmail node. \n- **Status Page Styling** → Edit the HTML/CSS in the Code node to match your branding. \n- **Error Handling** → Extend Switch node for other status codes (e.g., 404, 500). \n- **Multiple Websites** → Duplicate HTTP Request + Switch nodes for multiple URLs. \n\n---\n\n## 👤 Who Can Use It? \n- **DevOps & SRE Engineers** → For automated uptime monitoring. \n- **Freelancers/Developers** → To monitor client websites. \n- **Startups & SMEs** → For a free, lightweight status page without paid tools. \n- **Educators/Students** → As a hands-on learning project with n8n. \n\n---\n\n## 🌟 Key Features \n- 🔄 Automated uptime checks (configurable interval). \n- 📧 Email notifications on downtime. \n- 📝 Dynamic HTML status page generation. \n- 🌍 GitHub Pages integration for public visibility. \n- ⚡ Lightweight & cost-effective (no paid monitoring tool needed). \n\n---\n\n## 🔗 Tools Integration \n- **n8n** – Orchestration & automation. \n- **GitHub** – Version control + hosting of status page. \n- **Gmail** – Email notifications. \n- **HTTP Request** – Website availability check. \n\n---\n\n## 📈 Example Use Cases \n- Personal website monitoring with public status page. \n- Monitoring SaaS apps & notifying support teams. \n- Internal company services uptime dashboard. \n "
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "052ffe26-4ea6-4e74-91db-0076dc880da6",
"connections": {
"HTTP Request": {
"main": [
[
{
"node": "ba9b1eb6-6fcd-4ca8-b308-2b0daad7c299",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"Template HTML Code": {
"main": [
[
{
"node": "ec136a3f-e79d-4480-8c19-893184458928",
"type": "main",
"index": 0
}
]
]
},
"ba9b1eb6-6fcd-4ca8-b308-2b0daad7c299": {
"main": [
[
{
"node": "Template HTML Code",
"type": "main",
"index": 0
},
{
"node": "7d86a237-36e6-4ce8-95cf-19ab8a58581d",
"type": "main",
"index": 0
}
],
[
{
"node": "Template HTML Code",
"type": "main",
"index": 0
}
]
]
},
"4423f742-0144-4ffb-b28b-a6d108e3b5ca": {
"main": [
[
{
"node": "d9c2a2ee-5698-4a60-8ab9-1ff133d71505",
"type": "main",
"index": 0
}
]
]
},
"ec136a3f-e79d-4480-8c19-893184458928": {
"main": [
[
{
"node": "4423f742-0144-4ffb-b28b-a6d108e3b5ca",
"type": "main",
"index": 0
}
]
]
},
"d9c2a2ee-5698-4a60-8ab9-1ff133d71505": {
"main": [
[
{
"node": "e310e8e7-ad13-4f9e-a4b6-12f45d33a62a",
"type": "main",
"index": 0
}
]
]
},
"e310e8e7-ad13-4f9e-a4b6-12f45d33a62a": {
"main": [
[
{
"node": "d4f178ad-6597-4944-aa80-7335f26be23d",
"type": "main",
"index": 0
}
]
]
}
}
}자주 묻는 질문
이 워크플로우를 어떻게 사용하나요?
위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.
이 워크플로우는 어떤 시나리오에 적합한가요?
고급 - 데브옵스
유료인가요?
이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.
관련 워크플로우 추천
자동화된 n8n 워크플로우 백업至 GitHub 및 삭제 추적
삭제 추적이 포함된 GitHub 자동화 n8n 워크플로우 백업
If
N8n
Set
+
If
N8n
Set
31 노드Marcial Ambriz
데브옵스
Typebot 플로우와 GitHub 양방향 동기화, Typebot API 사용
Typebot API를 활용한 Typebot 플로우와 GitHub 양방향 동기화
If
Set
Code
+
If
Set
Code
31 노드Marcial Ambriz
데브옵스
귀하의 워크플로우를 GitHub 저장소에 저장
매일 워크플로우 백업을 GitHub에 저장하고 Slack 알림 전송
If
N8n
Set
+
If
N8n
Set
18 노드Andrew
데브옵스
GitHub 동기화 대시보드 - V2
提交 기록과 롤백 기능을 갖춘 GitHub 워크플로우 버전 관리 대시보드
If
N8n
Set
+
If
N8n
Set
94 노드Eduard
데브옵스
네일 살롱 (미국)
WhatsApp, GPT 및 Google 캘린더를 사용한 살롱 예약 관리 자동화
If
Set
Code
+
If
Set
Code
164 노드Denis
지원
고급 n8n 워크플로우와 GitHub 동기화
GitHub를 활용한 지능형 변경 감지 자동화 워크플로우 백업
If
N8n
Set
+
If
N8n
Set
38 노드Maksym Brashenko
데브옵스