如何使用n8n替代uptime-kuma

前言

由于我只有一台内存 2G 的云服务器,上面也部署了一些 Docker 服务,加上近期启用了 n8n 实例,导致内存频繁达到 90% 的告警线:

局部截取_20260130_161851.png

虽说我可以把告警上调至 95% 来避免这个问题,但是内存不足的问题并没有得到实际解决。于是稍微查了下服务器中哪些 Docker 服务比较占内存:

image.png

尽管 n8n 占用的内存是最多的,但是我在上面搭建了一些工作流和接口服务,所以是必要的,无法被替代。其它的服务要么也是不可替代,要么占用内存极低,所以最显眼的就是 uptime-kuma 了。尽管它占用的内存严格来说也不算特别多,但谁叫我服务器内存不够呢😂,而且 uptime-kuma 是一个网络服务健康检测的工具,功能不算很复杂,但内存也是轻松超过 100M(据说是 nodejs 的锅,因为我部署的一些其它自带前后端的 Docker 服务,采用 Go 写的,内存就只有不到 30M)。

image.png

虽然 Uptime Kuma 的界面简洁,用来检测服务和证书的状态也很方便,但是现在也只能说再见了

TLDR

先上结论,使用 Schedule Trigger + Data Table + 邮件通知/飞书通知(或者其它 webhook 类通知)即可完全达到 uptime-kuma 的功能。

局部截取_20260205_161655.png

Data Table

我在社区看到一些类似的 workflow 都是采用 Google sheet 存储数据,实际上现在 n8n 自带的 Data Table 也可以作为简易数据库进行使用,不必额外在其它地方维护数据了。

局部截取_20260205_161224.png

上面就是我针对我的健康检测需求设计的 Data Table:

  • name:用于通知时的服务名称
  • url:服务地址
  • checkSSL:是否检测 SSL 状态(主要是看是否过期)
  • normal:url 本身请求是否正常(根据 response 的 code 是否和设置 normalCode 一致)
  • SSLExpired:SSL 证书是否过期

服务(网站/接口)状态检测

这个就比较简单了,直接采用 HTTP Request 节点请求 url,拿到状态码进行对比即可:

局部截取_20260205_171438.png

需要注意的是该节点默认不会返回状态码,需要在 Response 开启。

SSL 证书状态检测

一开始,我在一个 社区工作流 中发现了 ssl-checker.io 这个网站,该网站传入指定的域名就可以返回该域名对应的 SSL 证书信息。然而实际运行一段时间后,发现该网站服务特别不稳定,很容易触发 504 报错:

局部截取_20260205_172047.png

因此,后面我特地使用 Code 节点,使用 nodejs 自带的 tls 模块来获取 SSL 证书信息:

注:以下代码完全由 AI 生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const tls = require('tls');

// 获取上游节点传来的域名,或在此处硬编码测试
const domain = $input.first().json.domain;

return new Promise((resolve, reject) => {
try {
const socket = tls.connect(443, domain, { servername: domain, timeout: 5000 }, () => {
const cert = socket.getPeerCertificate();

if (!cert || Object.keys(cert).length === 0) {
resolve({ json: { error: "未能获取证书信息" } });
return;
}

const validTo = new Date(cert.valid_to);
const now = new Date();
// 计算剩余天数 (毫秒转天数)
const daysRemaining = Math.floor((validTo - now) / (1000 * 60 * 60 * 24));

resolve({
json: {
domain: domain,
issuer: cert.issuer.O,
valid_from: cert.valid_from,
valid_to: cert.valid_to,
days_remaining: daysRemaining,
is_valid: daysRemaining > 0,
status: daysRemaining < 7 ? "警告:即将过期" : "正常"
}
});

socket.end();
});

socket.on('error', (err) => {
resolve({ json: { domain: domain, error: err.message, status: "连接失败" } });
});

socket.on('timeout', () => {
socket.destroy();
resolve({ json: { domain: domain, error: "连接超时", status: "超时" } });
});

} catch (error) {
resolve({ json: { error: error.message } });
}
});

后续使用一段时间后发现该检测逻辑运行很稳定,没有出现异常。不过需要注意的是,n8n 自部署实例默认是不允许导入任何模块的(包括 nodejs 内置模块),但是可以通过设置 Docker 的环境变量来开启这个功能 [1][2]

1
2
# 单独启用tls模块
NODE_FUNCTION_ALLOW_BUILTIN=tls

然后重启 Docker 实例即可。

依次间隔触发

在使用 Data Table 的 get rows 功能获取表格中所有的数据后,按照 n8n 的默认机制,单个 item 执行一次,多个 item 则会同时触发各自执行一次。因此如果不做间隔触发,可能会导致不必要的并发压力。

一开始我想着 n8n 自带 wait 节点,且看着好像可以传入多个 item 时根据 itemIndex 设置依次增大的延迟时间,于是我就这么做了,哪知道这个设置压根不起作用,实际上设置多个延迟时间也会在第一个延迟时间达到时同时触发所有 item(只能说很不符合直觉了😅)

最后只能使用 loop + wait 的形式实现:

局部截取_20260206_154144.png

异常/恢复通知

至于消息通知,n8n 内置发送邮件的的节点,也可以使用 HTTP Request 节点触发各种基于 webhook 进行触发的推送渠道。这里我推荐一个社区节点——n8n-nodes-feishu-lite:

里面的功能可以说是量大管饱(多达上百个),涵盖飞书开放 API 的各个方面,只要去飞书上申请一个机器人即可:

局部截取_20260206_155051.png

后面我基于此在 n8n 上搭建了飞书助理机器人的 workflow,虽说不如 openClaw 那么智能化,但是够用了(主要是特别省 token🙈)


  1. https://docs.n8n.io/hosting/configuration/configuration-examples/modules-in-code-node/ ↩︎

  2. https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.code/?utm_source=n8n_app&utm_medium=node_settings_modal-credential_link&utm_campaign=n8n-nodes-base.code#built-in-methods-and-variables ↩︎