Uptime Kuma Docker 自建监控与告警配置
在独立 VPS 上用 Docker 部署 Uptime Kuma,监控网站、端口、DNS 和 cron 任务,并通过邮件或 Telegram 告警。文中提供 Compose 配置、状态页发布及告警测试方法。
构建目标
使用一个小型容器从外部监控其他服务器和网站,并在它们停止响应时立即通过电子邮件、Telegram、Discord 或 webhook 通知您。Uptime Kuma 由一个 Node 进程运行。在本配置中,它使用 SQLite 文件作为后端(v2 也可以使用内置或外部 MariaDB)。它可以在 256-512 MB 内存中稳定运行,并提供实时仪表板、历史图表和公共状态页。安装只需一个包含十行内容的 Compose 文件。真正重要的是运行它的位置,以及是否在测试中确认过告警确实能够触达您。如果从未验证监控告警能否到达您,那么这个监控还不如没有,因为它会让您以为系统受到保护,实际却什么也没有监控。
在故障无法影响的位置运行监控
这个决定会直接影响整个方案,因此必须首先确定。不要将 Uptime Kuma 运行在被监控对象所在的同一台服务器上。 如果监控程序与被监控服务器位于同一台机器上,那么你关心的事件——服务器宕机或内存耗尽——也会同时终止监控程序,导致完全收不到告警:宕机监控程序没有任何响应,与“一切正常”看起来完全相同。即使服务器仍在运行,也存在一个更隐蔽的问题:指向 localhost 的监控程序与业务负载共享 CPU,因此负载突增可能导致监控检查超时,并将目标错误地标记为 down,产生误报,而真实用户仍可正常访问服务。
因此,应将 Uptime Kuma 运行在与被监控服务器不同的 VPS 上,最好还使用不同的服务商或区域,并按照用户访问服务的方式,通过公网和主机名访问这些服务。一台低成本实例即可满足需求,一台小型监控 VPS 就能监控所有服务器。对于托管的重负载应用,这种隔离尤其重要。例如,PhotoPrism 或 Immich 照片库在为新导入的内容建立索引时,可能让 CPU 持续满载数小时;如果监控程序与其共享硬件,就会将仅仅处于繁忙状态的服务错误地判定为 down。若要检测 Kuma 自身是否宕机,可在其他位置通过 cron 添加 push 心跳。
前置条件和资源规格
- 一台全新的 Ubuntu 24.04 VPS,已安装 Docker Engine 和 Compose v2 插件。应从 Docker 自己的 apt 软件源安装,而不是使用更新滞后的
docker.io发行版软件包。 - 256 MB RAM 可运行少量监控项;512 MB 到 1 GB 足以舒适地运行几十个监控项及反向代理。检查之间 CPU 基本处于空闲状态。
- 一个域名和 DNS
A记录(例如status.example.com指向该 VPS),仅当您需要 TLS 和公开状态页时才需要。私有实例可以跳过 DNS,改用 VPN 或 SSH 隧道。 - 到告警目标的出站网络连接:通过 SMTP 连接邮件服务商,或通过 HTTPS 连接 Telegram 和 Discord。
Compose 文件
将以下内容写入 /srv/uptime-kuma/compose.yaml。
services:
uptime-kuma:
image: louislam/uptime-kuma:2
container_name: uptime-kuma
restart: unless-stopped
ports:
- "127.0.0.1:3001:3001"
volumes:
- kuma-data:/app/data
volumes:
kuma-data:启动它并观察首次启动过程:
sudo mkdir -p /srv/uptime-kuma
# save the file above as /srv/uptime-kuma/compose.yaml, then:
cd /srv/uptime-kuma && sudo docker compose up -d
sudo docker compose logs -f uptime-kuma正常启动会记录 Listening on 3001,随后不再输出日志。该文件中有 3 处配置是有意这样设置的。
使用 127.0.0.1:3001:3001,而不是 3001:3001。 Docker 会使用 DNAT 规则发布端口,并在 ufw 处理数据包之前评估这些规则。因此,直接使用 3001:3001 会让仪表板暴露在公网,无论 ufw 规则如何配置;只有添加到 Docker 自己的 DOCKER-USER 链中的规则才能过滤这些流量。绑定到 loopback 可使服务保持私有状态,仅暴露反向代理。这样也意味着只有主机本身可以访问 3001:不使用代理的私有实例应使用下方所示的 SSH 隧道;如果要通过自行托管的 WireGuard VPN访问,则必须将端口发布到服务器的 WireGuard 地址(例如 10.8.0.1:3001:3001),而不是 127.0.0.1。
在 /app/data 上使用命名卷。 Uptime Kuma 保存的所有数据都位于此处,包括 SQLite 数据库、监控项、通知设置和状态页徽标。卷丢失后,管理界面会恢复为空;这是唯一必须备份的内容。
将镜像固定到主版本标签 :2。 这是当前的稳定版本线。复制配置前,请在 Docker Hub 上检查最新主版本。不要跟踪 latest 这类会变化的标签,项目已弃用此类标签。该镜像升级主版本时会执行数据库迁移。应在准备好新备份后主动触发迁移,而不是在例行拉取镜像时意外触发。
还有一点需要注意:/app/data 必须位于支持 POSIX 文件锁的文件系统上。本地 Docker 卷没有问题;在 NFS 上,SQLite 数据库会损坏,并出现 SQLITE_BUSY 和 database disk image is malformed,因此不要使用网络共享。
首次运行:创建管理员帐户
通过代理访问实例,地址为 https://status.example.com;也可以使用 SSH 隧道:运行 ssh -L 3001:127.0.0.1:3001 user@your-vps,然后打开 http://localhost:3001。全新安装 v2 时,初始页面会要求选择数据库。选择 SQLite。它会将所有数据保存在 /app/data 卷中,下面的备份和故障排查步骤也都基于此配置。接下来会显示管理员用户名和密码设置表单;系统没有默认登录凭据。请设置一个强密码:此控制面板可以查看所有受监控对象的内部地址和令牌。之后忘记密码了?请在主机上重置,不要在浏览器中操作:
sudo docker compose exec uptime-kuma npm run reset-password先添加通知渠道并进行测试
先配置告警,再添加监控项。这样创建每个监控项时都可以直接绑定通知渠道。进入 Settings then Notifications then Setup Notification,使用每个渠道的 Test 按钮确认消息能够送达,因为未测试通知是配置静默失败的第二常见原因。
Email (SMTP)。 填写主机、端口、加密方式、用户名、密码、From 和 To。常见组合是使用 465,并将 “Secure” 设置为 TLS/SSL;或者使用 587 和 STARTTLS。部分服务器也在 25 上提供 STARTTLS,因此应使用服务提供商文档中指定的端口和模式。对于 Gmail 以及大多数启用了双因素身份验证的服务提供商,必须生成 app password;使用普通账户密码会返回 Error: Invalid login: 535-5.7.8 Username and Password not accepted。
Telegram。 向 @BotFather 发送消息,发送 /newbot,然后复制 bot token。要获取 chat ID,先向新 bot 发送一条消息,打开 https://api.telegram.org/bot<token>/getUpdates,再从 JSON 中读取 chat.id。如果从未先向 bot 发送消息,getUpdates 会为空,bot 也没有可发送消息的目标。
Discord。 在频道中打开 Edit Channel then Integrations then Webhooks then New Webhook,复制 URL,然后将其粘贴为 Discord 通知。
Generic webhook。 对于其他服务,例如 Slack incoming webhook、自定义端点或家庭自动化 hook,Webhook 类型会将 JSON payload POST 到你提供的 URL。列表中其他约九十种服务大多可通过内置的 Apprise 集成覆盖。如果不希望第三方介于故障和手机之间,请选择内置的 ntfy 类型,并将其指向 自行运行的 ntfy 服务器。它会通过完全由你控制的渠道将消息推送到手机。
逐次添加监控
单击 Add New Monitor,选择类型,然后设置 Friendly Name、Check Interval(60 seconds 是合理值)、Retries(连续失败多少次后判定为“down”;设为 2 或 3,可避免单个丢包就触发告警)以及要触发的通知。以下是你会使用的类型:
- HTTP(s)。 完整 URL。状态码被接受即表示正常(默认范围为 200-299;如果
301或401对你来说是正常响应,可在 Accepted Status Codes 中扩大范围)。这是网站和 API 的主要监控方式。 - HTTP(s) - Keyword。 发送相同请求,但只有响应正文中包含指定字符串,或启用 Invert 后不包含指定字符串,才判定为“up”。它可以发现网站返回
200 OK,但页面显示“Error establishing a database connection”的情况;普通 HTTP 检查会将其误判为正常。对于与独立后端通信的浏览器前端,这也是正确的检查方式,例如 基于 Jellyfin 的 Halcyon 视频商店界面:页面外壳可以正常返回200,但其后端媒体服务器可能无法访问。 - TCP Port。 对主机和端口建立基本 TCP 连接,适用于非 HTTP 服务,例如 22 端口上的 SSH、5432 端口上的 Postgres、25 端口上的 SMTP 服务器以及游戏服务器。
- Ping。 ICMP 回显检查,用于低成本检测可达性和延迟。但许多网络和云防火墙会丢弃 ICMP,因此 Ping 监控变红可能表示“主机宕机”,也可能表示“服务提供商阻止 Ping”;请使用 TCP 监控确认。
- DNS。 使用你指定的解析器解析记录(A、AAAA、MX、TXT 等),并可断言返回结果,从而及早发现注册商或 DNS 故障。
- Push。 由内部向外部报告状态的监控方式,下一节介绍。
使用推送(心跳)监控监控 cron 任务
上面的每个监控都从外部主动访问您的服务。推送监控则相反:Uptime Kuma 等待,然后由您的任务调用它来报告“已运行”。这是监控备份任务或 cron 任务的唯一可靠方式:HTTP 检查只能确认 URL 有响应,只有任务本身知道它是否已完成。
创建一个类型为 Push 的监控。Uptime Kuma 会生成一个唯一 URL,例如:
https://status.example.com/api/push/j8Xa2Kd9Qe?status=up&msg=OK&ping=将 Heartbeat Interval 设置为任务的运行间隔,并预留少量余量。然后在脚本的末尾添加一行,使其仅在任务成功时发送心跳:
#!/usr/bin/env bash
set -euo pipefail
# ... your backup or job runs here; set -e aborts on any failure ...
curl -fsS --retry 3 "https://status.example.com/api/push/j8Xa2Kd9Qe?status=up&msg=backup+ok&ping="如果任务失败,set -e 会在执行 curl 前中止;如果服务器宕机,任务也不会运行。无论哪种情况,心跳都会停止;当间隔加重试的时间窗口结束后,Uptime Kuma 会将监控状态切换为宕机并向您告警。请将该推送令牌视为密钥:任何获得它的人都可以伪造正常心跳。
构建公共状态页
状态页是面向客户的视图:显示哪些服务正常运行及其近期历史记录,但不会公开您的仪表板。进入 Status Pages then New Status Page,设置名称和 slug(公共路径,例如 /status/main),将所需监控项拖入 “Websites” 和 “APIs” 等分组,添加徽标和简短说明,然后点击 Save。您还可以将状态页绑定到独立域名,使 status.example.com 直接提供该页面。
请注意以下两点:只添加您愿意公开的监控项,因为状态页会显示某项服务是否存在以及当前是否正常运行;仪表板仍受登录保护,而状态页是有意公开的,无需身份验证。
将其置于带有 TLS 的反向代理之后,并注意 WebSocket
对于公共实例,请在绑定到回环地址的容器前部署反向代理,以处理 TLS 和主机名。一个容易让人出错的细节是:Uptime Kuma 的 UI 是一个实时的 Socket.IO 应用,因此代理必须支持升级 WebSocket 连接。 如果忽略这一点,页面虽然能加载但无法建立连接;仪表盘会一直显示 “Connecting...”,实时心跳无法更新,浏览器控制台会显示 WebSocket connection to 'wss://.../socket.io/...' failed。
安装 nginx 和 certbot,然后编写将流量代理到回环端口的虚拟主机配置。先将其置于 80 端口,稍后再让 certbot 添加 TLS;关于挑战、续期定时器及其故障模式,请参考 使用 certbot 和 nginx 签发 Let's Encrypt 证书。
sudo apt install -y nginx certbot python3-certbot-nginx将其保存为 /etc/nginx/sites-available/status.example.com;其中两行 WebSocket 配置至关重要:
server {
listen 80;
server_name status.example.com;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
}
}启用站点并测试配置,然后让 certbot 重写该配置块以监听 443 端口,导入证书并添加 HTTP 到 HTTPS 的重定向:
sudo ln -s /etc/nginx/sites-available/status.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d status.example.comUpgrade 和 Connection "upgrade" 这对配置是关键所在,而 proxy_read_timeout 3600s 则防止 nginx 中断长连接;certbot 会将这两项复制到它生成的 443 配置块中。如果你已经在同一个代理后运行了多个容器,通过 Traefik 路由并自动配置 TLS 可以通过容器标签实现同样的效果,且默认会转发 WebSocket 升级请求。
不要对整个虚拟主机设置 basic-auth,因为这会同时锁定公共状态页面和 /api/push 端点。请保留 Uptime Kuma 内置的登录功能,如果该实例面向互联网,请添加 fail2ban 以监控重复的登录失败;如果仪表盘不需要公开访问,请移除代理,通过 SSH 隧道访问,或者通过 VPN 访问(此时端口应发布在 VPN 地址而非回环地址上)。
正确进行证书过期监控
HTTP(s) 监控器也可以在 TLS 证书过期前发出警告:勾选 Certificate Expiry Notification,Uptime Kuma 会在证书到期前指定天数发出告警。两个错误会导致检测结果不准确。请按主机名而非 IP 地址进行监控,否则不带 SNI 的请求会收到服务器的默认证书,并显示 Hostname/IP does not match certificate's altnames。如果希望监控器发出过期警告,请不要勾选 Ignore TLS/SSL Error:该选项用于自签名内部主机(unable to verify the first certificate、DEPTH_ZERO_SELF_SIGNED_CERT),但启用后 Uptime Kuma 会完全跳过证书检查,包括过期检查。
备份:只有一个目录
由于所有数据都存放在 /app/data 中,因此备份就是在容器停止时复制该卷,这样 SQLite 文件处于一致状态:
cd /srv/uptime-kuma
sudo docker compose stop
sudo docker run --rm \
-v uptime-kuma_kuma-data:/data \
-v /var/backups/kuma:/backup \
alpine tar czf /backup/kuma-$(date -u +%Y%m%dT%H%M%SZ).tgz -C /data .
sudo docker compose start先使用 docker volume ls | grep kuma 确认卷的实际名称,因为 Compose 会为其添加项目目录前缀。然后将 tarball 复制到服务器之外,因为 VPS 上的副本只是副本,不算备份。恢复过程相反:停止整个堆栈,将内容解压到空的 /app/data 卷中,然后启动堆栈。
升级
升级就是拉取新镜像:
cd /srv/uptime-kuma
sudo docker compose pull
sudo docker compose up -d新容器首次启动时会执行数据库迁移;请监控 docker compose logs -f。拉取镜像前务必先完成上文的备份,并保持在同一主版本标签内:从 :1 升级到 :2 会迁移数据库。项目的迁移指南说明,迁移中断后需要从备份恢复并重试。因此请先备份,并阅读该指南和发行说明。
故障模式及其对应提示信息
监控指向 localhost,却误报“宕机”。 监控显示红色,并出现 timeout of 48000ms exceeded 或 connect ETIMEDOUT,但服务仍能从您的笔记本电脑访问。如果监控目标与 Uptime Kuma 运行在同一台主机上,通常是 CPU 或内存峰值导致监控检查得不到资源,而不是目标服务故障。将监控迁移到独立 VPS,并监控公网主机名。
connect ECONNREFUSED 127.0.0.1:443(或其他端口)。该端口没有进程监听:服务可能已停止,也可能是您在容器内部监控 localhost,此时 127.0.0.1 指的是容器,而不是您的服务器。请监控公网主机名,而不是回环地址。
邮件测试出现 Invalid login: 535-5.7.8 Username and Password not accepted。 SMTP 凭据错误,或者邮件服务商要求使用应用专用密码,但您填入了账户密码。生成应用专用密码并填入该密码。
邮件测试出现 connect ETIMEDOUT 或 queryA ETIMEDOUT <host>。 端口错误,或者邮件服务商阻止了出站 SMTP。确认 465 或 587 与 Secure/STARTTLS 设置一致,并在主机上使用 nc -vz smtp.example.com 587 测试。许多服务商会阻止出站 25;有些服务商还会在您提出申请前阻止提交端口。
邮件测试出现 self signed certificate 或 unable to verify the first certificate。 SMTP 服务器提供的证书不受 Node 信任。应修复邮件服务器的证书,不要通过绕过证书校验来掩盖问题。
仪表板停留在“正在连接...”,控制台显示 WebSocket connection ... failed。 反向代理未升级 WebSocket。在 nginx 中添加 Upgrade 和 Connection "upgrade" 请求头,或者使用默认转发这些请求头的代理,例如 Traefik 或 Caddy。HTML 可以正常加载,因为它使用普通的 HTTP GET;只有实时套接字需要升级。
证书到期监控始终不告警,或告警不正确。 可能勾选了 忽略 TLS/SSL 错误,导致证书检查被禁用;也可能是监控目标使用 IP,因缺少 SNI 而读取了错误的证书,并显示 Hostname/IP does not match certificate's altnames。取消勾选忽略错误,并按主机名进行监控。
日志中出现 SQLITE_BUSY 或 database disk image is malformed。 /app/data 卷位于不支持正确文件锁定的文件系统上,通常是 NFS。将其迁移到本地 Docker 卷,并从备份恢复。
FAQ
应该在哪里运行 uptime monitor?
应将其运行在与被监控服务器不同的服务器上,最好选择其他服务商或区域,并像用户一样通过主机名从公网访问这些服务器。如果监控服务与目标服务共用一台服务器,导致服务器宕机的故障也会同时终止监控服务;主机负载过高时,还可能让监控服务将实际正常的服务误报为“down”。单独使用一台小型 VPS 可以避免这两种情况。
如何通过 Telegram 或电子邮件接收告警?
在 Settings then Notifications 中添加通知渠道,然后将其关联到每个监控项。对于 Telegram,使用 @BotFather 创建机器人,并从 https://api.telegram.org/bot<token>/getUpdates 读取 chat.id;对于电子邮件,使用 465 配置 SSL,或使用 587 配置 STARTTLS;如果服务商启用了双因素身份验证,还需使用应用专用密码。点击 Test,确认消息能够送达后,再依赖该通知渠道。
Uptime Kuma 能监控 cron 任务或备份脚本吗?
可以,这需要使用 Push 监控项:Uptime Kuma 会提供一个 URL,您在脚本结束时执行 curl,这样只有脚本成功完成时才会发送心跳。如果任务失败或服务器宕机,心跳就不会到达;超过设定间隔后,您会收到告警。这是确认计划任务确实运行的唯一可靠方式,因为外部检查无法查看任务内部的执行情况。
Uptime Kuma 与 Zabbix,应该运行哪个?
Uptime Kuma 可以在十分钟内、几乎不占用资源地回答“服务是否正常、从外部是否可访问,以及是否向我发送了告警”,并提供状态页。它不会收集 CPU、内存和磁盘趋势等深度指标,也不支持面向整个服务器集群的阈值管理;如果需要这些功能,完整的 Zabbix 监控服务器 是功能更重的基于代理的工具,许多人会同时运行两者。如果您还没有决定是否运行监控,我们关于 2026 年自托管项目的总结 可以帮助您了解监控在整体方案中的位置。