自动化网站正常运行时间监控与邮件警报及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": "## 为什么选择 4o 模型?👆",
"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 Code",
"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": "Switch - status code",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"Template HTML Code": {
"main": [
[
{
"node": "Extract from File - Generated HTML",
"type": "main",
"index": 0
}
]
]
},
"Switch - status code": {
"main": [
[
{
"node": "Template HTML Code",
"type": "main",
"index": 0
},
{
"node": "Send a notification mail",
"type": "main",
"index": 0
}
],
[
{
"node": "Template HTML Code",
"type": "main",
"index": 0
}
]
]
},
"Get existing index.html file": {
"main": [
[
{
"node": "Extract from existing File (github)",
"type": "main",
"index": 0
}
]
]
},
"Extract from File - Generated HTML": {
"main": [
[
{
"node": "Get existing index.html file",
"type": "main",
"index": 0
}
]
]
},
"Extract from existing File (github)": {
"main": [
[
{
"node": "If - Compare existing HTML file with generated HTML",
"type": "main",
"index": 0
}
]
]
},
"If - Compare existing HTML file with generated HTML": {
"main": [
[
{
"node": "Update Index.html file",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 开发运维
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
自动化n8n工作流备份至GitHub并追踪删除
自动化n8n工作流备份至GitHub并追踪删除
If
N8n
Set
+13
31 节点Marcial Ambriz
开发运维
Typebot 流程与 GitHub 双向同步,使用 Typebot API
Typebot 流程与 GitHub 双向同步,使用 Typebot API
If
Set
Code
+12
31 节点Marcial Ambriz
开发运维
将您的工作流保存到 GitHub 仓库
每日工作流备份至 GitHub 并发送 Slack 通知
If
N8n
Set
+10
18 节点Andrew
开发运维
GitHub 同步仪表板 - V2
具有提交历史和回滚功能的 GitHub 工作流版本控制仪表板
If
N8n
Set
+20
94 节点Eduard
开发运维
美甲沙龙(美国)
使用WhatsApp、GPT和Google日历自动化沙龙预约管理
If
Set
Code
+20
164 节点Denis
客户支持
高级 n8n 工作流与 GitHub 同步
使用 GitHub 的智能变更检测自动化工作流备份
If
N8n
Set
+10
38 节点Maksym Brashenko
开发运维