workbuddy.xpcool.com/.workbuddy/memory/DEPLOY.md

61 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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 调用可能被沙箱拦截/用户误拒而中断,重跑不能出错。
## 站点与容器清单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 新增)** |
| —(暂无域名) | `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 --memory 512m`。服务器内存仅 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`