
先说我为什么要写这篇东西。前阵子朋友的小网站凌晨挂了第二天早上用户来问才知道。那段时间我一直在想难道每次都要等用户当哨兵吗后来我在自己一台吃灰的本地服务器上搭了 Uptime Kuma才发现这套流程比我想象的简单太多。如果你也有一台本地跑着 Docker 的机器哪怕只是树莓派或者旧笔记本完全可以自己搞一套网站监控服务数据全在自己手里免费还没有那么多限制。Uptime Kuma 是 GitHub 上一个挺火的开源监控工具界面清爽功能不输商业的监控 SaaS。它能帮你盯网站是否在线、接口是否正常、SSL 证书还有多少天过期、域名能不能解析等等支持 Telegram、邮件、Webhook 等几十种通知渠道还能生成一个漂亮的状态页。关键是它只用 SQLite 存数据资源占用极小放到本地服务器上就能跑。下面对我整个搭建过程做一个完整复盘包括部署、配置、踩坑、通知、备份和进阶玩法。全程基于我自己的实操尽量把你可能遇到的问题都指出来。1. 为什么要自己本地搭一套监控服务而不是用免费 SaaS1.1 免费监控服务的隐藏天花板很多人第一反应是用 Uptime Robot、StatusCake 这类在线监控不行吗免费版确实能用但限制很明确监控间隔通常被锁在 5 分钟监控数量有上限比如 50 个历史数据只保留一段时间。对于个人博客来说或许够用但等你维护了多个站点、多个 API、多台设备之后免费额度很快就不够看了。另外还有一个隐私角度的问题。你所有站点的在线状态、响应时间、故障记录都会经过第三方平台。虽然这些数据算不上什么核心机密但放在别人服务器上总归不太踏实。自建的话数据就在你自己的硬盘里备份也好迁移也好全由自己控制。1.2 Uptime Kuma 到底能帮你盯住什么很多人以为 Uptime Kuma 只能“Ping 一下网站”实际远不止如此。我自己现在就用它监控了这些网站首页是否返回 200响应时间有没有超过阈值登录接口的 POST 请求是否还能正常返回 JSON页面里是否包含指定的关键字防止被篡改或者出现异常占位MySQL 的 3306 端口是否还能连上家里 NAS 的 Web 界面是否活着域名解析是否正常SSL 证书剩余天数是否充足定时任务通过主动 Push 心跳上报超过多久没收到心跳就告警这意味着它不只是“网站监控”更像一个通用的心跳检测中心。凡是能从网络层面探测到的东西基本都能纳入监控范围。1.3 本地部署的门槛到底有多低Uptime Kuma 的部署门槛低得有点夸张。官方推荐 Docker 部署不依赖外部数据库一条命令就能起来。它对硬件的要求也非常低容器运行时内存占用通常在 50 到 100MB 左右CPU 平时几乎不动因为就是定时发 HTTP 请求的事。我实跑的机器是一台 N100 小主机同时跑了 Uptime Kuma、GitLab Runner、Nginx 等四五个容器Kuma 的负载可以忽略不计。如果你家里有 NAS群晖、威联通都支持 Docker有软路由或者有一台长期开机的旧笔记本都能跑。提示部署前确认机器上 Docker 已经装好。如果是群晖直接在 Container Manager 里搜索 uptime-kuma 安装也可以本质相同。2. Docker 部署全过程十分钟跑起第一台监控2.1 最省事的部署方式一条 docker run 命令我推荐用 docker compose 管理因为后续升级方便。先创建一个目录比如 /opt/uptime-kuma然后新建 docker-compose.ymlservices: uptime-kuma: image: louislam/uptime-kuma:1 container_name: uptime-kuma restart: always ports: - 3001:3001 volumes: - ./data:/app/data然后执行cd /opt/uptime-kuma docker compose up -d等容器起来后浏览器访问 http://服务器IP:3001第一次打开会让你创建管理员账号和密码。创建完就能进入主界面语言可以在右上角设置里切成中文官方内置了简体中文对国内用户很友好。如果非要用 docker run 写一行命令也可以docker run -d --restartalways -p 3001:3001 -v /opt/uptime-kuma/data:/app/data --name uptime-kuma louislam/uptime-kuma:1两种方式效果一样唯一关键点是 volume 一定要映射出来。数据全在 /app/data 里不映射的话容器一删数据全没。2.2 用反向代理套上 HTTPS 和域名默认情况下面板只能用 IP 加端口访问而且没有 HTTPS密码明文传输说实话不太安全。我自己习惯用 Nginx 反代再加上一个域名这样地址好看也能省去每次输端口号。因为 Uptime Kuma 的实时更新依赖 WebSocket所以反代配置里必须放行 Upgrade 头否则页面会一直转圈。Nginx 配置文件核心部分如下server { listen 443 ssl; server_name kuma.example.com; ssl_certificate /etc/nginx/ssl/example.com.pem; ssl_certificate_key /etc/nginx/ssl/example.com.key; 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; } }配置完后建议在 Uptime Kuma 的设置里把 “Base URL” 改成你的域名避免回调链接不对。注意如果你只在局域网内访问不需要公网暴露那么完全可以不设反代直接 IP:3001 用。只要能保证内网访问方便即可。若是从公网访问不要裸奔至少加个 Basic Auth 或者限定 IP 白名单。2.3 升级和数据备份volume 映射必须从一开始就做好Uptime Kuma 更新很频繁功能迭代也快。升级操作在我看来是所有后续维护里最容易出问题的一步但只要遵循一个原则就没事永远不要动 ./data 目录。升级前先备份docker compose stop cp -r /opt/uptime-kuma/data /backup/uptime-kuma-data-$(date %F) docker compose pull docker compose up -d我的实际经验是升级前老老实实先停容器再备份。虽然 SQLite 支持在线备份但直接拷贝数据目录属于最稳妥的做法恢复的时候也最简单把整个 data 目录放回去重新启动容器所有监控项、通知配置、历史记录全部回来。对于偏执一点的人可以再加一个定时备份任务。把 data 目录打包扔到另一块磁盘或者对象存储里完全没问题。3. 配置第一个监控项HTTP 监听不是填个网址那么简单3.1 监控间隔、超时、重试三个默认值都有讲究在 Uptime Kuma 里添加监控项很简单但有几个配置项值得认真对待直接决定你收到的告警是“有效告警”还是“噪音”。第一是监控间隔。默认是 60 秒对大多数网站来说足够了。有些人喜欢把间隔调到 10 秒甚至 5 秒其实没必要。因为探测间隔太短一方面会白白增加源站压力另一方面可能触发目标服务器的反爬、WAF 规则反而导致高误报率。我自己生产环境的做法是公网站点设 60 秒内网关键服务设 30 秒个别想要快速感知的接口设 20 秒。如果监控目标本身就是你自己控制的服务器调短些问题不大如果是别人的网站建议保守一点。第二是超时时间。默认 30 秒偏长。我的建议是设 5 到 10 秒——如果一个网页 10 秒还没响应对用户来说已经算故障了没必要等 30 秒才触发告警。第三是重试次数。默认 0 次表示一次失败就告警这很容易被网络抖动误伤。配合“失败重试”机制把重试次数设成 1 或 2意思是连续失败 1 或 2 次才判定为故障可以过滤掉大部分瞬时抖动。代价是告警会有一定延迟但这个延迟对绝大多数场景都能接受。3.2 关键字监控最容易踩的编码坑HTTP 监控除了检查状态码还可以做关键字匹配监控页面内容是否包含、或者是否不包含某个关键字。我第一次用这个功能就踩了坑页面返回的 HTML 是 UTF-8 编码我在 Kuma 里填了中文关键字结果一直误报“找不到关键字”。后来才发现问题的根源是目标页面的响应头没有声明 charset而 Kuma 默认按 UTF-8 解码正常情况下不会出错但如果你监控的页面使用了 GBK/GB2312 编码中文关键字很可能匹配不上。规避方法有两个。一是尽量用 ASCII 关键字比如页面上稳定的标识符、版本号字符串二是确保目标页面响应头里明确写了 charsetutf-8并且在关键字设置里勾选或去掉“区分大小写”选项。如果你实在需要监控中文关键字记得先确认页面的编码格式。另外关键字监控匹配的是响应体的原始内容不是渲染后的 DOM。如果目标网站是前后端分离的 SPAVue/React页面内容靠 JS 动态渲染那么 HTTP 请求拿到的 HTML 里往往没有关键字关键字监控会失效。这种情况下更好的方案是监控背后的 API 接口而不是监控首页。3.3 除了 HTTP还有哪些监控类型值得顺手配上Uptime Kuma 支持二十多种监控类型我实际用下来以下几个配合起来体验最好Ping 监控看设备通不通适合判断内网服务器是否在线。注意部分云厂商的 IP 会禁 ICMP那就会误报。TCP 端口监控非常实用比如检查 MySQL 3306、SSH 22、Redis 6379。TCP 能连上说明端口在监听连不上服务大概率挂了或者被防火墙拦了。DNS 监控监控域名解析是否还能正常返回记录适合用来自建 DNS 或托管了大量域名的场景。Push 监控不是被动探测而是由被监控方主动请求一个带 Token 的 URL。适合定时任务、备份脚本这类场景比如每天凌晨备份备份完成后请求一次 Kuma如果哪天没收到请求Kuma 判定“未上报”触发告警。这个机制非常巧妙后面专门讲。证书监控SSL 证书过期前 N 天提醒。Uptime Kuma 对每个 HTTPS 监控项都会记录证书信息可以单独配置“证书过期剩余天数”作为通知条件。我现在的监控列表里一个站点的完整配置通常是三层HTTP 检查首页、TCP 检查数据库端口、Push 检查后台定时任务。三层各司其职覆盖了从用户入口到服务端核心的链路。4. 把报警送出去Telegram、邮件、Webhook 都跑一遍4.1 Telegram 通知的完整配置链路监控搭好了没人通知等于白搭。Uptime Kuma 支持 80 多种通知服务国内能用、体验又好的方案其实就那么几个。我用 Telegram Bot 作为主力推送通道。配置步骤虽然多但设一次就一劳永逸。大致流程Telegram 里搜 BotFather发 /newbot得到一串 Bot Token。把你的 Bot 拉进一个群或者在 BotFather 建的频道。给自己的 Bot 发一条任意消息然后请求https://api.telegram.org/bot你的Token/getUpdates从返回 JSON 里找到 chat id。回到 Uptime Kuma“通知”里选 Telegram填入 Token 和 chat id保存并发送测试消息。如果测试消息没收到多数情况是 chat id 拿错了。注意私人对话和群组对话的 chat id 格式不一样群组通常是负数。还有一种情况是 Bot 被群管理员限制了发言权限需要在群设置里把 Bot 提升为管理员。测试成功之后再到监控项编辑里把“通知”勾上这个 Telegram 通道。提示Telegram 默认的推送通知里会带监控名称、URL、当前状态和错误信息。如果你不想在消息里暴露完整 URL 或敏感信息可以自定义消息模板只保留监控名称和状态。4.2 邮件通知本地服务器要自己解决发信问题邮件通知适合作为正式告警记录因为它天然有留档、可追溯的优势。但自建监控服务用邮件通知最容易忽略一个问题你的服务器是靠什么发邮件如果是本地服务器没有企业邮局的 SMTP 授权那邮件要么直接发给本地 postfix 然后被各大邮箱拒收要么根本发不出去。所以我建议直接用第三方 SMTP 服务比如 QQ 邮箱、网易邮箱或者企业微信邮箱。以 QQ 邮箱为例设置思路是在 QQ 邮箱设置里开启 SMTP 服务生成授权码注意是授权码不是登录密码。在 Uptime Kuma 邮件设置里填 SMTP 服务器 smtp.qq.com、端口 465、账号和授权码。发件地址填你自己的 QQ 邮箱收件地址填接收告警的邮箱。用第三方 SMTP 的缺点是存在发送频率限制但对告警通知来说一天也发不了几封完全够用。4.3 通知风暴怎么避免第一次真正故障时如果你的 10 个监控项同时挂了Kuma 会给每个监控项都发一条通知瞬间你的 Telegram 和邮箱会被刷屏。这就是典型的通知风暴。我的经验是在通知设置里开启“仅发送一次”同一次故障期间不要重复轰炸。把关联服务归到同一组比如“Web 集群”“数据库集群”或者利用监控项的标签功能做分组过滤。在“通知”里设置静默时间段比如凌晨 2 点到 7 点只发紧急通道不发普通提醒。记住一个原则告警要让人重视但不要让人麻木。通知风暴和狼来了类似一旦用户习惯性忽略提醒真正的大故障反而会被淹掉。5. 本地部署最容易翻车的六个场景及排查思路5.1 本地探测内网服务和公网服务的网络视野差异这是本地部署最隐蔽的一个坑。Uptime Kuma 是主动探测型监控它从自己所在的网络出发发起请求。如果你的本地服务器在办公室或家里它能否访问某个监控目标取决于当前网络的路由策略。比如你想监控一台云服务器的 80 端口但办公室所在网络屏蔽了公网 80 端口那么 Uptime Kuma 会一直显示 down即使网站从用户视角是完全正常的。反过来也一样云服务器上的网站可能要经过 CDNCDN 对来自某些 IP 段的请求会做拦截那么从本地探测的结果和你站在用户角度访问的结果可能不一致。解决方案监控目标尽量选择用户访问的真实入口比如带 CDN 的域名而不是绕过 CDN 的源站 IP。如果条件允许可以把 Kuma 部署到多个点或者用第三方云监控做交叉验证。单纯依赖一个本地探测点视野是有盲区的这一点心里要有数。5.2 Docker 网络模式选错容器看不见你的服务Docker 部署 Uptime Kuma 时默认会创建一个桥接网络。容器内部访问宿主机服务时不能直接用 localhost而要用宿主机局域网 IP或者用 Docker 内部的网关地址。我见过很多人在本地部署后监控宿主机上的 Nginx 和 MySQL结果一直显示无法连接就是这个原因。如果你 monitoring 的容器和被监控的服务都在同一台机器上最简单的做法在监控项 URL 里填宿主机 IP比如http://192.168.1.10:8080或者启动时加参数--network host让容器直接用宿主机的网络栈这样 localhost 就能访问宿主机上的服务network host模式在 Linux 下可用但 macOS 和 Windows 的 Docker Desktop 支持不完整这种情况下建议用宿主机 IP。还有一点容器通过网络去访问局域网内其他设备通常没问题但被监控设备如果有防火墙比如 Windows 防火墙或 iptables要注意放行 Docker 容器的网段。5.3 Nginx 反代后页面转圈WebSocket 没放行Kuma 主界面有实时日志、实时状态更新这些功能走 WebSocket。如果只用普通的proxy_pass页面能打开但监控状态死活不刷新日志区域一直转圈。刚才的 nginx 配置里我已经写了关键的三行proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_http_version 1.1;升级请求和连接放行缺一不可。如果你用的是 Caddy 或 Traefik它们对 WebSocket 通常是默认支持的基本不用额外配置。我自己初次用 Nginx 配置时就漏了proxy_set_header Connection upgrade结果面板看起来正常但动态状态就是不更新排查了半天才发现是这里的问题。5.4 监控稳定性本身Kuma 挂了自己不知道自建监控服务有个天然的悖论监控服务自己挂了怎么办如果是云服务器出故障Kuma 跟着挂那你什么都收不到。如果是本地服务器宕机报警一样发不出去。要解决这个问题思路有两个把 Kuma 容器设置为restart: always宿主机一重启 Docker 就自动拉起它。但宿主机本身挂了这招也没用。对 Kuma 自己的面板做一个外部存活检查可以是另一个轻量监控服务比如云厂商的免费拨测或者另一个机房里的 Kuma 实例互相监控。我现在的做法是本地 Kuma 监控所有业务站点同时用一个免费的第三方可用性检查服务只监控我的 Kuma 面板域名。如果面板挂了就发一封邮件到备用邮箱。这样既保留了数据自主又避免了自己挂掉变成盲区。5.5 备份恢复时SQLite 文件别直接拷到运行中的容器里数据库备份这件事看似简单但有一个细节很重要恢复的时候不要直接把备份文件覆盖到正在运行的容器数据目录里否则 SQLite 可能损坏。最稳的操作流程是docker compose stop # 把备份的 data 目录整体覆盖回 /opt/uptime-kuma/data docker compose up -d如果你担心停机时间可以用在线备份方式docker exec uptime-kuma sqlite3 /app/data/kuma.db .backup /app/data/kuma-backup.db docker cp uptime-kuma:/app/data/kuma-backup.db ./kuma-backup.db这样备份出来的文件是 SQLite 的一致性快照不会出现复制一半被写入的问题。我平时周三和周日各做一次备份保留最近 10 份完全够用。5.6 用 Push 监控做主动心跳比探测更可靠被动探测有一个短板它只能探测那些网络可达的服务。对于定时任务、批处理脚本、备份程序这类“过程型任务”被动探测根本不知道任务有没有执行成功。Push 监控正好弥补了这个空缺。用法很简单在 Kuma 添加“Push”监控类型会生成一个唯一 URL形如https://你的Kuma域名/api/push/token?statusupmsgOK然后你在定时任务脚本里任务完成后curl一下这个 URL。Kuma 会记录上次收到 Push 的时间如果超过你设定的周期阈值比如每天一次还没收到就判定为故障触发通知。我用它监控每日数据库备份任务效果非常好。以前每早都要看一眼备份日志现在只在没收到心跳时才会收到告警省心太多。6. 进阶玩法状态页、多用户与团队协作6.1 状态页公开给用户看比发通告更省事如果你的服务是开放给用户使用的与其等用户来问“是不是挂了”不如主动提供一个状态页。Uptime Kuma 自带 Status Page 功能可以把你选择的监控项展示在一个公开页面上显示绿点红点、响应时间、历史可用性还能自定义标题和说明文字。我实际使用感受这个功能特别适合小程序、独立开发者、SaaS 创业团队。故障发生时运维只需在群里说一声用户能看到状态页上变红自然会理解客服压力小很多。状态页还可以设置密码或者只在指定时间段公开。如果不想用默认域名可以绑定自己的子域名为了可访问性建议开启 HTTPS配合反向代理很容易实现。6.2 多用户与权限配置Uptime Kuma 的新版本已经支持多用户和身份验证。你可以在设置里创建新用户并分配不同的角色权限。比如团队里面管理员可以新增监控项、修改配置、管理通知普通用户只能查看状态页和监控列表不能改配置只读用户适合挂在值班大屏上只展示状态多用户场景下我建议用独立账号而不是共享管理员账号避免误操作。日志里也会记录操作人排查问题时能知道是谁改的配置。6.3 和 Prometheus、探针类工具怎么分工可能有朋友会问我都有 Prometheus Grafana 了还要 Uptime Kuma 干嘛这里要理清两类工具的定位。Prometheus 擅长内部指标采集比如 CPU、内存、请求数、延迟百分位它解决的问题是“服务到底卡在哪”。Uptime Kuma 擅长外部可用性探测它的问题视角是“从用户端还能不能访问我的服务”。两者一个从内往外看一个从外往里看互补而非替代。类似地市面上常见的探针类工具包括一些监控面板重点在于服务器资源、在线状态的上报。如果你已经有一套探针系统再加一个 Uptime Kuma 作为外部视角和告警中心是不冲突的。我自己的分工是Kuma 负责“客户能不能打开网站”和“证书还有几天到期”Prometheus 负责“接口响应为什么慢”“哪台机器 CPU 爆了”。各管一摊非常清晰。6.4 资源占用实测与配置建议最后给一份我在实际生产环境里的资源占用数据。这台 N100 小主机内存 16GB同时跑了 Uptime Kuma、Nginx、GitLab Runner 和一个内网穿透客户端。Kuma 侧的资源开销大致如下指标数值容器内存占用60 到 100MB 浮动CPU 日常占用几乎为 0告警时瞬时升高50 个监控项、间隔 60 秒完全无压力100 个以上监控项建议适当调大间隔注意日志增长所有监控的历史记录都存在 SQLite 里时间长了数据文件会膨胀但一般一个季度也就几十到一两百 MB不用过度担心。如果你监控项特别多可以打开设置里的“定期清理日志”或者“设置日志保留天数”。硬件配置建议2 核 1GB 内存以上的机器都能带得动树莓派 4B、各种软路由、NAS、老笔记本都可以。千万别为了跑 Uptime Kuma 单独买云服务器没有那个必要。用了一段时间之后我自己最大的感受是监控工具的价值不在于装了之后一直看着它而在于它能在你不在意的时候帮你盯着那些容易忽略的角落。SSL 证书过期这种坑谁忘谁知道提前一个月开始提醒真是省心太多。如果你家里已经有一台常开的机器真心推荐试一试这套组合拳打下来晚上睡觉都能踏实不少。