workbuddy.xpcool.com/.workbuddy/memory/DEPLOY.md
夏犀麟 0cf48dc1cb docs: home.xpcool.com 上线完成 + Kuma 状态页建成
- 2026-09-13.md:追加 4 条(部署完成、Kuma 状态页建成、
  灌库脚本静默失败根因、SSH 被拒时的公网旁路验证法)
- DEPLOY.md:站点清单更新 home.xpcool.com 上线状态;
  新增「公开状态页」小节(三表配合、send_url 必为 1、
  两个验证端点、同源反代写法、回滚方式);
  工具链坑位新增「$LASTEXITCODE 不能穿透 ssh」与
  「set -e + 写死路径 = 静默失败」
- 技能 uptime-kuma-sqlite-ops 同步补齐状态页建法
2026-09-13 19:30:22 +08:00

105 lines
24 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# xpcool.com 生产环境 · 部署与运维手册
> 从 MEMORY.md 拆出2026-09-13存放服务器、容器、站点、安全加固与本机工具链坑位等细节。
> MEMORY.md 只保留规则与索引。
## 生产部署(腾讯云 193.112.118.168SSH 22025/xxcoolDocker+宿主机 Nginx
- 站点落点:前端静态 → `/data/www/<域名>/`nginx 配置 → `/data/nginx/conf.d/<域名>.conf`80→301→443 + 反代/静态);证书 → `/data/nginx/ssl/<域名>/<域名>_bundle.crt|.key`**本地源:`E:\CentOS\ssl\<域名>_nginx/`**2026-09-13 核对;证书只放 `_bundle.crt`+`.key``.csr`/`.pem` 一并留存便于比对)。
- service 后端容器:`service.xpcool.com:new``127.0.0.1:10100:10100`,网络 `xpcool-net`env`GF_GCFG_ENV=prod` + `DB_DSN=mysql:service:xxx@tcp(xpcool-mysql:3306)/service?...`**必须带 mysql: 类型前缀**+ `JWT_SECRET`;容器内必须有 `manifest/config/config.yaml`(基础配置),否则 GF 启动报「找不到 config」构建目录 `/data/deploy/projects/service.xpcool.com/`main + manifest/config + resourceDockerfile 用 COPY manifest/config 整体拷贝)。
- DB`xpcool-mysql` 容器root 密码见该容器 env库名 `service`,种子执行顺序 003→004→004b→007服务器表结构旧必须先 003 加列;导入用 `sudo sh -c 'docker exec -i xpcool-mysql mysql ... < file'` 宿主机重定向)。
- 权限映射admin_menu type=2 行的 path 必须匹配实际路由(现为 `POST /api/service/admin/...`,见 manifest/sql/007_menu_permissions_v3.sql
- 文件下载站2026-09-03 上线,当晚迁移):`file.xpcool.com` = **FileBrowser Quantum** 容器 `fbq``gtstef/filebrowser:stable` v1.5.5`127.0.0.1:10881→80`restart unless-stopped`/data/share:/srv:ro` **只读挂载**,数据卷 `/data/filebrowser-q`config.yaml+database.db+tmp属主=镜像 uid1000+ nginx 反代。**要点**:初始凭据 **admin/admin**(首登后立即改密);配置走 `config.yaml`sources/cacheDir管理走网页 UIAPI 与原版不兼容(需用户建 long-live token/swagger 亦需);镜像默认非 root(uid1000);原版 filebrowser(容器 `filebrowser`/10880/db `/data/filebrowser/database`)已于 2026-09-01 归档、现已停用**保留回滚**Quantum v2.0 beta 权限模型改 per-source(view/download/modify/create/delete)。改密/建只读账号/临时分享(过期+密码+匿名)均在网页 UI。
- SSH 凭据/密码不入库,需要时询问用户或查对话记忆;远程批量命令用 paramiko 脚本(`%TEMP%\wb_deploy\ssh_exec.py`,支持第 2 参数超时秒数docker build 用服务器端 nohup+日志轮询防超时。**2026-09-11 密钥轮换后更新)**:当前登录 = 本地 `~/.ssh/xpcool_ed25519`ed25519注释 xpcool-server-20260904`xxcool@193.112.118.168:22025`root 被拒;密码登录已禁);旧 `CentOS.pem`(RSA对应服务器公钥 `skey-q6pq6jb3`)**已作废并从 authorized_keys 移除**(因私钥误提交 Gitea 事件而轮换),服务器 authorized_keys 另存 2 把钥(`mcp-server-manager@local`、`xxcoolwork@gmail.com`)为其他用途、保留不动;安全组按出口 IP 限放 22025本机出口 1.204.105.116 曾因未放行连不上80/443 可达);本机旧记录 `~/.ssh/id_ed25519` 与 wb_deploy 脚本**在当前设备不存在**。
- **服务器安全加固2026-08-27 完成)**firewalld 已启用(放行 22025/80/443/3000/2222cockpit/rpcbind 已停fail2ban 保护 sshd(port=22025, maxretry5/bantime1h);监控脚本 `/usr/local/bin/server-monitor.sh` + cron 每 10 分钟(调度在 **xxcool 的 crontab**`*/10 * * * * sudo /usr/local/bin/server-monitor.sh`;日志 `/var/log/server-monitor.log`Bark 推送配 `/etc/server-monitor.conf``BARK_URL`**告警去重终版2026-09-11**:状态目录 `/var/lib/server-monitor/` —— `banned-ips.state`(已提醒过的封禁 IP**只增不减 → 同一 IP 永不重复提醒**)、`ssh-src-ips.state`(已提醒过的登录来源 IP**仅新 IP 首次登录**才提醒)、`ports.state`(当前已告警的未登记端口,消失后清除)、`ssh-brute.state`(爆破告警状态机:`attacking`=本轮已提醒 / `idle`=已复位;攻击持续不刷屏,攻击停止静默复位,**再犯视为新一波才重新提醒**);完整审计仍在 fail2ban.log + journald 且已上报 admin 后台(脚本备份 `server-monitor.sh.bak.20260911`);另有安全日志上报器 `/usr/local/bin/server-security-collector.sh`cron **每 5 分钟**xxcool crontab→ POST 到 `127.0.0.1:10100/api/service/open/security/log/report`,配置 `/etc/server-security.conf`INTERNAL_TOKEN、状态 `/var/lib/server-security/last.ts`dnf-automatic 每天 06:00 自动安全补丁SSH 密钥登录已部署(现用 `~/.ssh/xpcool_ed25519`)、密码登录已禁。**2026-09-11 加固**:已关闭 `X11Forwarding`**生效位置是 drop-in `/etc/ssh/sshd_config.d/50-redhat.conf:17`,主配置里那行是注释、改了无效**;改前备份 `.bak.20260911``sshd -t` 预检 + `sshd -T` 核对 + `systemctl reload sshd` 不断连nginx 遗留垃圾已清理(`.code.xpcool.com.conf.swo`、`tool.xpcool.com.conf.download.0` → 移入 `/data/nginx/_junk_backup_20260911/`,未直接删、可回滚)。**nginx 配置目录约定**`include /data/nginx/conf.d/*.conf;`,故 conf.d 下非 `.conf` 后缀文件不会被加载。**遗留待办**`lighthouse` 账号(腾讯云自带 uid1000NOPASSWD ALL是否锁定待用户决策。**坑**:① 腾讯云安全组未放行 3000/2222/8081Gitea 走 nginx 反代 80/443② 改 sshd 前必须先 `sshd -t` 预检+备份(曾因脏行导致 SSH 断开);③ EPEL 源需腾讯云镜像(`mirrors.cloud.tencent.com/epel`)且 baseurl 必须手动写全;④ CentOS9 的 fail2ban 在 EPEL。**⑤2026-09-04 新坑)腾讯云改带宽若切计费模式会触发实例冷重启,重启后 firewalld 自定义端口规则曾丢失致 SSH 22025 失联80/443 正常——firewall-cmd 放行务必带 `--permanent`,且实例冷重启后要复查 22025 放行**。另:带宽 3M→5M 已升级2026-09-04实测 619KB/s 满速)。**⑥2026-09-11 溯源新坑)本机出口 IP `1.204.105.116` 曾于 09-03 23:00 被自己的 fail2ban 封禁、09-04 23:00 才解封——这正是当时「SSH 22025 超时」的真因当时误判为安全组未放行绕了远路。SSH 突然不通时,排查顺序应为:先 `fail2ban-client status sshd` + `grep Ban /var/log/fail2ban.log`,再怀疑安全组**。**⑦2026-09-11 体检结论)服务器未发现被入侵迹象**UID0 仅 root、无空密码账号、无异常 SUID/后门/劫持、无特权容器、系统目录近 30 天无改动;外网暴露面实测仅 **22025/80/443**3000/2222/8081 等均被安全组挡住firewalld 虽放行 3000/2222 但安全组是第二道闸)。
- 本地 pnpm 修复2026-08-27 升级为 wrapper 方案):根因=本环境 MSYS 路径转换故障,把 `/c/...` 参数转成 `E:\c\...`(多 `E:\c\` 前缀)致 corepack shim 与 node 都找不到 pnpm.js。**已建持久 wrapper**`~/.workbuddy/binaries/node/bin/pnpm`(内容:`export NODE_OPTIONS=--experimental-sqlite; exec "<托管node.exe>" "C:/Users/ybtdevxxl/.workbuddy/binaries/node/workspace/node_modules/pnpm/bin/pnpm.cjs" "$@"`,关键=给 node 传 Windows 风格路径 `C:/...` 规避 MSYS 转换)。**提交/构建前需 `PATH="~/.workbuddy/binaries/node/bin:$PATH"` 前置**pre-commit 钩子(lefthook oxlint/oxfmt/eslint/stylelint/checkType)即可正常运行;否则钩子崩 → 只能 --no-verify。已验证 pnpm 11.16.0 + `pnpm exec oxlint` 1.79.0。
## 日常同步习惯(建议)
- 每次工作结束:在各改动项目 `git add + commit`,本工作空间同样提交(规则/日志变化时)。**只 commit、不要 push**2026-09-01 用户明确推送由用户自行完成AI 无需代为 push避免凭据交互失败
- **验证分工2026-09-01 用户明确)**AI 能做的验证(类型检查、构建、单元/二进制测试、自动化冒烟)照做;**AI 不方便验证的部分(真实浏览器交互体验、视觉效果、下载弹窗等)直接交给用户手动验证**,不要反复折腾自动化工具。
- 换设备开工前:先 `git pull` 各仓库,保证规则与记录最新。
## 本机 Windows/PowerShell 工具链坑位2026-09-10 实测,写脚本必看)
- **PowerShell 工具不回显 stdout**exit code 正常但看不到输出;必须把结果 `Out-File` 落盘,再用 Read 读取。Bash 里调 `powershell.exe` 会被安全策略拒绝。
- **`[byte] -shl 8` 会溢出归零**(结果仍是 byte 宽度)。字节拼 16 位整数必须先 `[int]` 转换,否则高位丢失(剪贴板/协议解析类代码的高频坑)。
- **给 .ps1 加 BOM 绝不能用 `Get-Content -Raw` + `Out-File`**:本机默认按 GBK 解码 UTF-8 文件,中文会被永久破坏且不可逆。正确做法是字节级前置 `EF BB BF``[System.IO.File]::WriteAllBytes`)。
- **PATH 被裁剪**:脚本里直接写 `ping` / `netsh` 会报"无法识别",须用 `$env:SystemRoot\System32\xxx.exe` 绝对路径;且不要写 `& $exe args 2>$null | Out-String`(会报"无法在管道中间运行文档"),改用 `$out = & $exe args``@($out) -join ' '`
- **PowerShell 变量名不区分大小写**`$R` 与循环变量 `$r` 是同一个变量,会导致集合被静默覆盖。
- **后台监听的进程可能杀不掉**Stop-Process / taskkill 均无效),换端口重新起更省事。
- **防火墙规则按可执行文件路径匹配**:一批 node.exe 规则指向已不存在的路径(失效);目前 `C:\Users\xxl\AppData\Roaming\nvm\v23.0.0\node.exe` 有有效的 Public 档「TCP+UDP 任意端口」入站放行规则——需要做**免提权的入站可达性测试**时就用它监听。
- 测入站**不要用 ping**Windows 默认拦 ICMPv6/ICMP 入站,必须用 TCP 端口测试。
- 国内测速Cloudflare 端点不可用;用 **Ookla 官方 CLI**`install.speedtest.net` 可直连下载)。
- 本机网络备注:家里的宽带是**运营商级 NATCGNAT第 2 跳 100.64.0.1**,无公网 IPv4但有**公网 IPv6**`240e:338:263:3600::/64`)。以太网被判定为 Public 网络档。
- **经 `ssh.exe` 执行多行脚本会踩转义坑2026-09-13 实测)**:把多行 here-string 直接当参数传给 `ssh.exe`,远程 bash 解析到 `(` 等字符会报 `syntax error near unexpected token '('`**而且报错前的行已经执行了**,导致状态半途而废(证书只搬了一半)。**可靠做法**:本地写 `.sh` 文件(用 `-replace "`r`n","`n"` 强制 LF + `WriteAllText` UTF-8 无 BOM**单独** `scp` 上传 → `ssh "chmod +x /tmp/x.sh && /tmp/x.sh"` 执行。注意 `echo <b64> | base64 -d | bash` 会被 PowerShell 工具安全策略直接拦截("Spawning a non-PowerShell shell")。
- **多源文件 `scp` 不可靠2026-09-13 实测)**:一次 `scp a b c d e host:/tmp/` 只落地了其中 2 个,且**没有任何报错**。**每次只 scp 一个文件**;脚本内用 `for` + `[ -f ]` 判断做幂等补齐,避免重复上传。
- **远程脚本一律写成幂等**`if [ -f ]` 判断后再 `mv -f`),因为 SSH 调用可能被沙箱拦截/用户误拒而中断,重跑不能出错。
- **别用 `echo $LASTEXITCODE` 穿透 ssh 取远端退出码2026-09-13 实测踩坑)**`$LASTEXITCODE` 是 PowerShell 自动变量,在**本地**双引号字符串里就被展开成空串,远端实际收到的是 `echo DONE`,于是「脚本明明失败了却看到一个成功的回声」。**可靠做法**:远端 `sh /tmp/x.sh > /tmp/x.log 2>&1`,再 `base64 -w0 /tmp/x.log` 回传、本地解码落盘后用 Read 看base64 还能顺带规避 Windows 控制台按 GBK 解 UTF-8 造成的乱码)。
- **`set -e` + 写死的路径 = 静默失败**`kuma-statuspage.sh` 曾把来源文件写死成 `/tmp/wb_kuma_statuspage.sql`,而上传的是 `/tmp/kuma-statuspage.sql`,脚本在第一步就退出,**日志只有一行「缺少 …」,看起来像什么都没发生**。远程脚本内部一律用 `$(dirname "$0")/<同名文件>` 推导,再退到 `/tmp/<同名文件>` 兜底;且上传时保证「脚本名.sh ↔ 同名.sql」成对。
- **SSH 被沙箱拦截时不一定要重试**:先找**公网可达的旁路**做验证。例如 Kuma 的 `/api/status-page/<slug>``status.xpcool.com` 上匿名可达,直接 HTTPS 查就能判断状态页是否建成,省一次权限弹窗。真的需要读远端日志时,再向用户说明并请求重新授权(授权后原命令即可重跑)。
- **无头 Chrome 截图/量视口有三个坑2026-09-13 实测,做前端移动端验收必看)**
① Windows 下窗口宽度有 **500px 下限**`--window-size=390` 会被撑到 500
`--force-device-scale-factor` **只改渲染倍率、不改 CSS 视口宽度**(给 dsf=2 + window 780拿到的仍是 764 CSS px不是 390
③ 用**iframe 凑窄视口**也不可靠——滚动条槽位会让内层 `clientWidth` 少 15px390 → 375恰好把 390px 下真实存在的横向溢出「藏」起来,导致误判「无溢出」。
**正解**:走 CDP `Emulation.setDeviceMetricsOverride``{width:390,height:844,deviceScaleFactor:2,mobile:true}`。Node 22 自带全局 `WebSocket`**零依赖**即可手写极简 CDP 客户端。整页截图用 `Page.captureScreenshot{captureBeyondViewport:true}`,布局高度仍保持视口高度、不会把 `100dvh` 的 hero 拉长。参考实现:`home.xpcool.com/scripts/shoot-mobile.mjs`。
另:**无头 Chrome 复用 profile 会导致截到旧产物**,每次截图前删掉 `$env:TEMP\wb_chrome_*`**`--dump-dom` 里搜标记串会撞到脚本源码自身**(把结果写进 `<title>` 再正则取 `<title>` 才稳)。
## 站点与容器清单2026-09-13 核对)
> 服务器 193.112.118.168,容器均为 `restart unless-stopped`;除特别标注外只监听 `127.0.0.1`,由宿主机 nginx 反代。
| 域名 | 容器 | 监听 | 说明 |
|------|------|------|------|
| admin.xpcool.com | —(静态 `/data/www/` | — | 管理后台前端 |
| service.xpcool.com | `service.xpcool.com:new` | 127.0.0.1:10100 | Go 后端xpcool-net连 xpcool-mysql |
| tool.xpcool.com | —(静态) | — | 前端工具站 |
| file.xpcool.com | `fbq` | 127.0.0.1:10881 | FileBrowser Quantum 只读下载 |
| read.xpcool.com | `qread` | 127.0.0.1:8082 | 阅读 legado 自托管 |
| git.xpcool.com | `gitea` + `gitea-runner` | 0.0.0.0:3000 / 0.0.0.0:2222 | 代码托管与 CI |
| sub2api.xpcool.com | `sub2api` + postgres + redis | 127.0.0.1:18080 | — |
| code.xpcool.com | `code-server` | 127.0.0.1:8080 | 网页版 VS Code |
| **status.xpcool.com** | **`uptime-kuma`** | **127.0.0.1:3001** | **服务监控面板2026-09-13 新增)** |
| **home.xpcool.com** | **—(静态)** | **—** | **xpcool 服务台9 站统一入口 + 存活状态。2026-09-13 站点/证书/nginx 已全部上线,`/api/kuma/` 同源反代到 Kuma 仅剩 DNSPod `home` A 记录未加,公网暂不可访问** |
| —(暂无域名) | `bark` | 0.0.0.0:8081 | Bark 推送服务端 |
| — | `xpcool-mysql` | 127.0.0.1:3306 | MySQL 8.0(库 `service` |
### Uptime Kumastatus.xpcool.com2026-09-13 部署)
- 镜像 `louislam/uptime-kuma:2.5.3`2.x 稳定线1.x 已停维护v2 有破坏性变更,跨大版本需迁移数据库)。
- 启动参数:`--restart unless-stopped -p 127.0.0.1:3001:3001 -e TZ=Asia/Shanghai -v /data/uptime-kuma:/app/data -v /data/uptime-kuma-patch/bark.js:/app/server/notification-providers/bark.js:ro --memory 512m`**最后一个 -v 是 Bark 增强补丁挂载2026-09-13 加**;没部署前可省略)。服务器内存仅 3.7G 且 **swap=0**,必须限内存,避免 OOM 波及同机其他容器。
- **v2 首次启动是「选择数据库」引导页**(逻辑在 `/app/server/setup-database.js`,读 `data/db-config.json`),选 SQLite 即可之后进入创建管理员账号页。Uptime Kuma **没有找回密码入口**,密码丢失只能改数据库/清 2FA务必记牢。
- nginx 反代**必须透传 WebSocket**`proxy_http_version 1.1` + `Upgrade`/`Connection` 头),否则面板无限重连、状态刷不出来。
- **证书**:腾讯云免费 DVCN/SAN 均为 `status.xpcool.com`**有效期仅 3 个月(至 2026-12-12到期必须重新申请并替换**;落点 `/data/nginx/ssl/status.xpcool.com/`crt/pem/csr 644、key 600本地源 `E:\CentOS\ssl\status.xpcool.com_nginx\`。部署时用 `openssl x509 -pubkey | md5``openssl pkey -pubout | md5` 比对,确认证书与私钥配套。
- 访问形态:`http:// → 301 → https://`;公网实测 `ssl_verify=0`、响应约 0.45s2026-09-13
- nginx 配置模板见 `.workbuddy/tmp/status.xpcool.com.conf`
- **监控的添加方式2026-09-13 实测)**Uptime Kuma 官方 REST API **不支持创建监控**(只能读/暂停/恢复),只能走 Socket.IO需面板账号密码社区库 `uptime-kuma-api`)或**直接写 SQLite**。本项目采用后者:向 `monitor` 表 INSERT字段均有默认值只需给 `name/type/url/interval/retry_interval/maxretries/weight/description/accepted_statuscodes_json``user_id=1` 即 `xpcool`),再 `docker restart uptime-kuma` 让服务端重新加载并开始探测。脚本:`.workbuddy/tmp/add-monitors.sh`(幂等,按 name 去重);**改库前先备份** `/tmp/kuma.db.backup.<时间戳>`
- **heartbeat.status 含义**`0=DOWN`、`1=UP`、`2=PENDING`、`3=MAINTENANCE``monitor_tls_info` 表会自动填充各站点证书信息(可用于证书到期监控)。
- **第一批监控9 个,均 HTTP(s)、`accepted_statuscodes_json=["200-399"]`、开启证书到期通知)**
| 站点 | 间隔 | 重试 | 权重 |
|---|---|---|---|
| admin / service / git | 60s | 3 | 1000 |
| file / read / tool / sub2api | 120s | 2 | 2000 |
| code / status | 300s | 2 | 3000 |
- **`service.xpcool.com` 单独放宽为 `["200-399","404"]`**:该后端是纯 POST 接口(遵循本项目"接口全 POST"规范),任何 GET 都 404返回 404 说明 nginx + GoFrame 存活,**后端进程真挂时 nginx 返回 502仍会判 DOWN**。
- **公开状态页2026-09-13 建,首页状态格的唯一数据源)**`status.xpcool.com` 本身只是 Kuma 面板,**状态页是另一回事**,必须单独建,否则 `/api/status-page/<slug>` 恒 404。
- 三张表配合:`status_page`slug/title/published/theme…`group`**需 `public=1``status_page_id` 指向该页**)→ `monitor_group`(监控与分组的关联)。
- **必须置 `monitor_group.send_url = 1`**。Kuma 的 `Monitor.toPublicJSON()``if (this.sendUrl) obj.url = this.customUrl ?? this.url;` —— 不开 `send_url` 时 API **不返回 `url` 字段**。而前端就是靠 `url` 里的主机名把监控和卡片对齐的,不返回就等于状态全「未接入」。
- 当前实例slug `xpcool`(与 `home.xpcool.com/src/composables/useStatus.ts``STATUS_PAGE_SLUG` 一致、title「xpcool 服务台」、theme dark、`search_engine_index=0`(内部站不收录)、`show_certificate_expiry=1`、`auto_refresh_interval=60`分组「自建服务」9 个监控全挂且 `send_url=1`
- 建页脚本(幂等,含 DB 备份):`E:\CentOS\deploy-home\kuma-statuspage.{sql,sh}`。**改库后必须 `docker restart uptime-kuma`** 才生效。
- 验证端点:`/api/status-page/<slug>`(分组+监控列表)与 `/api/status-page/heartbeat/<slug>``heartbeatList`/`uptimeList`,键形如 `"3_24"`,前缀是监控 id。**这两个端点在 status.xpcool.com 上公网匿名可达**SSH 被拦时可直接用 HTTPS 验证状态页是否建成。
- 回滚:`sudo cp /tmp/kuma.db.backup.<时间戳> /data/uptime-kuma/kuma.db && sudo docker restart uptime-kuma`。
- **通知渠道 = Bark2026-09-13 已配置并验证)**Kuma 2.5.3 原生支持 Bark`/app/server/notification-providers/bark.js`)。`notification` 表:`id/name/active/user_id/is_default/config`**`config` 是整条通知对象的 JSON 字符串(含 `type`Kuma 用 `providerList[notification.type]` 派发,靠 `item.name` 索引**。
- **最大的坑:`type` 必须写 `Bark`(首字母大写)**,不是 `bark`。前端 `NotificationDialog.vue:257` 就是 `Bark: "Bark"`;写成小写则查不到 provider**静默不发通知**。
- 当前配置:`id=1 / name='Bark 手机推送' / is_default=1``config` = `{"type":"Bark","barkEndpoint":"http://172.17.0.1:8081/sm5WnyANWx89GgLtFnRXhk","barkGroup":"Uptime-Kuma","apiVersion":"v1"}`
- **端点必须用容器网关 `172.17.0.1:8081`**kuma 在默认 `bridge` 网络(网关 172.17.0.1),容器内的 `127.0.0.1` 不是宿主机Bark 容器端口发布在宿主机 `0.0.0.0:8081`,故走网关可达(实测 200
- `apiVersion:"v1"` → 走 GET `{endpoint}/{title}/{body}?icon=…&group=…&sound=…`bark-server 支持);不填也默认 v1。Bark key 就是 `/etc/server-monitor.conf``BARK_URL` 那个(`sm5WnyANWx89GgLtFnRXhk`),手机端就是 `https://service.xpcool.com/bark/<key>/`
- 挂到监控:`monitor_notification(monitor_id, notification_id)`**等价于 UI 的 `applyExisting`**。已为 9 个监控全部关联(共 9 行)。
- 脚本:`.workbuddy/tmp/kuma-bark-setup.sh`(幂等写入)、`.workbuddy/tmp/kuma-bark-verify.sh`(端到端验证 + 自清理);改库前必备份 `/tmp/kuma.db.backup.<时间戳>`
- **端到端验证方法(推荐复用)**:临时插一个指向 `http://127.0.0.1:9/` 的监控(`interval=20/retry_interval=20/maxretries=0`)→ 重启容器 → 十几秒即 DOWN 并推送 → 查 `docker logs bark` 确认真的收到 GET 推送200→ 删掉临时监控与其 heartbeat 再重启。全程不清真站点,可靠性最高。
- 全部 9 个监控 `expiry_notification=1`(证书到期通知已开),当前均 UP。
- **Bark 通知增强2026-09-13 · 自定义图标/分组/重要警告/图片/角标)**:⏳ **补丁与素材已备好,待执行部署**(沙箱连续拦截 SSH改由 `.workbuddy/tmp/deploy-bark-custom.ps1` 由用户本机一键执行)。官方 provider 只支持 `barkEndpoint/barkGroup/barkSound`,且图标写死 GitHub 上的 Kuma logo。扩展办法 = **用只读挂载覆盖 provider 单文件**
- 宿主机 `/data/uptime-kuma-patch/bark.js` ←→ 容器 `/app/server/notification-providers/bark.js``:ro`)。补丁源码在 `.workbuddy/tmp/bark.js`,改动点集中在 `statusParams()``additionalParameters()`均以中文注释标了「xpcool 定制」。
- 行为DOWN → `level=critical`(重要警告,穿透静音/专注)+ `volume=5` + `badge=auto`(角标自增)+ `isArchive=1` + 异常配图UP → `badge=0`(清角标)+ 恢复配图。`call=1`(持续响铃 30s**默认关闭**,要开就在 config 里加 `"barkCall": true`
- 所有项都可用通知 `config` 里的同名字段覆盖:`barkIcon / barkGroup / barkSound / barkLevel / barkVolume / barkCall / barkBadge / barkImageDown / barkImageUp / barkBadgeReset`。**但 UI 里保存通知会重写 config、丢掉这些额外字段** —— 保持默认行为即可(补丁有兜底默认值),要改就走 SQL。
- 素材自托管在 `https://status.xpcool.com/bark-assets/{icon,down,up}.png`(落点 `/data/www/bark-assets/`nginx 新增 `location /bark-assets/``alias + default_type image/png + expires 7d`)。**必须公网 HTTPS 可匿名访问**:图是手机端收到通知后自己去拉的。
- 素材由 `.workbuddy/tmp/make-bark-assets.py`Pillow 手绘)生成,纯几何 + 微软雅黑文字,体积 22~78 KB。
- **⚠️ 升级 uptime-kuma 镜像后**`bark.js` 会被挂载覆盖成旧版实现,必须重新对照新版官方 `bark.js` 更新补丁(或临时去掉挂载)。
- **⚠️ 重建容器必须带回挂载**,否则补丁失效(表现为:通知还发,但图标/重要警告/配图/角标全没了)。完整启动参数见上。
- 部署脚本:`.workbuddy/tmp/deploy-bark-custom.sh`(远端执行,幂等)+ `.workbuddy/tmp/deploy-bark-custom.ps1`(本机一键:上传 → 部署 → 端到端验证,日志写 `.workbuddy/tmp/logs/`)。