CodeBuddy 的记忆原本只存在本机用户目录(不进版本控制),换机器即丢失。 把 5 个记忆文件备份进仓库,clone 后让助手「从 .ai-memory/ 导入记忆」即可恢复。 - README 说明用途、导入方法与维护约定 - CODEBUDDY.md 补充同步约定(改完记忆须同步本目录) - 内容仅含基础设施信息(IP/域名/用户名),无任何密码或密钥
10 KiB
name, description, type
| name | description | type |
|---|---|---|
| 生产服务器部署环境 | ethereal-realm.top 的部署拓扑、自建 Git 代码服务器(47.93.46.28:1216,已弃用 GitHub)、MySQL/nginx 实际配置与几个反直觉的坑(pypi 不可达、MySQL 非 Docker、skip_name_resolve、nginx 只代理部分路径) | project |
生产服务器 deploy@ethereal-realm.top(Alibaba Cloud Linux 3,公网 39.107.55.179,内网 172.17.151.49)的实际环境,与 REQUIREMENTS.md 的描述有出入。
部署拓扑
- 应用代码:
/home/deploy/app(git 仓库,remote 指向自建 Git 服务器,见下) - 虚拟环境:
/home/deploy/venv(Python 3.11),不是 项目目录下的 venv - 服务:systemd
wechat-api.service(/etc/systemd/system/),ExecStart=/home/deploy/venv/bin/python /home/deploy/app/run_server.py,Restart=always,监听127.0.0.1:8000 - 入口:systemd
cloudflared-quick.service(cloudflared tunnel --url http://127.0.0.1:80, 快速隧道,无配置文件、无路径限制,Restart=always,User=deploy)→ nginx:80 → 应用。 注意服务名是cloudflared-quick不是cloudflared——查 journal 时用错名字会显示空,误判成裸进程。 - nginx 配置:
/etc/nginx/conf.d/wechat-api.conf,server_name ethereal-realm.top deploy在wheel组,sudo需要密码 → 涉及 sudo 的操作必须让用户手动执行
代码仓库拓扑(2026-09-27 起)
用户自建了一台 Linux 代码服务器 gjm@47.93.46.28:1216(CentOS 7.2,git 1.8.3.1),
裸仓库在 /srv/git/wx-scan-authorize.git(owner gjm)。
本地 d:/wx-scan-authorize ──push──> 代码服务器 47.93.46.28 (唯一远端) ──pull──> 应用服务器 ~/app
- 本地:只有一个远端
origin= 代码服务器。git push/git pull不带参数即可。 - 应用服务器:
origin=ssh://gjm@47.93.46.28:1216/srv/git/wx-scan-authorize.git, 直接git pull。两端读写都已验证。 - GitHub 已弃用(2026-09-27 用户决定):国内访问不稳定,不再作备份。本地 remote
已删除,
origin这个名字改指代码服务器。GitHub 上那个仓库(LittleGuo/wx-scan-authorize) 是否删除由用户决定。 - 代码服务器上
gjm没有免密 sudo,涉及 root 的操作(装软件等)要让用户做。 - 该裸仓库
HEAD曾误指refs/heads/master(git init --bare默认值),已改为refs/heads/main。以后新建裸仓库记得顺手改,否则 clone 会拿到空工作区。
域名被阿里云 ICP 拦截(2026-09-27 确认)
用户已于 2026-09-27 提交 ICP 备案,预计不久下来。因此决定不搞 Cloudflare 命名隧道 (那需要账号 + 把 ethereal-realm.top 的 NS 改到 Cloudflare,代价不值)。隧道只是过渡, 备案通过后应把公众号后台 URL 改回
http://ethereal-realm.top/wechat并撤掉隧道。
http://ethereal-realm.top 在公网访问会返回阿里云的拦截页
(403 Non-compliance ICP Filing),因为备案还没做。直连公网 IP
http://39.107.55.179 一切正常(nginx 的 /auth/、/usage/ 都能打到应用)。
影响面:
- 微信服务器的回调推送也进不来 —— 公众号后台「服务器配置」URL 若指向该域名,
subscribe/SCAN事件永远到不了应用(journal 里完全没有/wechatPOST)。 - 可用的公网入口是 Cloudflare 快速隧道(
cloudflared-quick.service,已 enabled +Restart=always,所以 SSH 断开/进程崩溃/服务器重启都能自动拉起)。隧道 URL 形如https://<随机词>-<随机词>-<随机词>-<随机词>.trycloudflare.com,每次重启都会变 (这是快速隧道的固有行为,不是配置问题),捞当前值:journalctl -u cloudflared-quick | grep -oE "https://[a-z0-9-]+\.trycloudflare\.com" | tail -1。 公众号后台的服务器配置要填<隧道URL>/wechat。若推送突然不来了,先查这个 URL 是否变过。
微信真实推送已打通(2026-09-27 19:12 验证)
绕开 ICP 的办法:把测试号后台的服务器配置 URL 指向 Cloudflare 快速隧道,
https://catering-thumbnails-pirates-workstation.trycloudflare.com/wechat(Token 不变)。
微信随即发来 GET 校验(来源 162.62.81.123,腾讯云网段),签名复算一致、返回 200,
后台配置成功。之后真实扫码产生了第一条非模拟推送:
162.62.80.57 - "POST /wechat?signature=...×tamp=...&nonce=...&openid=ohve625WiuQVosBDGLVwxGT68S4c" 200 OK
整条链路结果(库内):新建 users.id=2(真实 openid ohve625WiuQVosBDGLVwxGT68S4c),
发 7 天免费时间授权(authorizations.id=2,2026-09-27 19:12:43 → 2026-10-04 19:12:43),
auth_scenes.id=9 置 authorized,usage_logs.id=2 记账一条。
- 微信推送 URL 里会带一个
openid=查询参数(官方文档没写)。我们忽略它——verify_signature()只用 token/timestamp/nonce,业务用 XML 正文的FromUserName。 已确认代码里没有任何地方往 query 拼 openid,是微信自己加的。 - 隧道已经是 systemd 服务
cloudflared-quick.service(enabled +Restart=always), 服务器重启/进程崩溃都会自动拉起,公众号后台配置不会因进程死掉而失效。 但快速隧道 URL 每次重启仍会变——所以重启后仍要重新捞 URL 并回填公众号后台。 - 库里的早期手工测试数据(
users.id=1 / openid='oTEST_CLIENT_01',其authorizations.id=1的end_at早于start_at)已于 2026-09-27 20:19 清理干净, 连同 9 条无归属的过期测试场景。清理前整库备份在/home/deploy/backup-cleanup-20260927-201903.sql(11 KB)。 现在库里只剩真实数据:users.id=2(openidohve625WiuQVosBDGLVwxGT68S4c)。 end_at倒挂不是 bug(这条结论仍然成立):生产代码路径 (_grant_free_authorization)在同一条 INSERT 里取NOW()算 start/end,不可能倒挂。- 清理用户数据时注意
auth_scenes的删除规则是SET NULL不是CASCADE(authorizations/usage_logs/sessions才是 CASCADE)。直接删users会在auth_scenes留下一条user_id=NULL的孤儿记录,状态可能还是authorized—— 客户端轮询时可能读到。正确顺序是先删该用户的auth_scenes,再删users。
几个反直觉的坑
-
服务器连不上 pypi.org(超时),但阿里云镜像正常(0.06s)。装包必须加
-i https://mirrors.aliyun.com/pypi/simple/,否则 pip 会长时间挂住。 -
MySQL 是原生安装的 8.0.46,不是 REQUIREMENTS 里写的 Docker。且
skip_name_resolve=ON+bind_address=127.0.0.1,导致root@localhost匹配不了 TCP 连接(报ERROR 1130 Host '127.0.0.1' is not allowed)。 应用用专用账号wechat@127.0.0.1(只授权wechat_api.*),凭据在服务器.env里。 注意:本机 Windows 的.env仍是MYSQL_USER=root,连的是本机 MySQL,两份不一样。 -
nginx 有两个 server 块,访问行为取决于 Host 头(2026-09-27 发现,很反直觉):
入口 匹配的 server 块 行为 Host: ethereal-realm.topwechat-api.conf精确白名单:只放行 /wechat、/auth/、/usage/、/admin,其余落到location /的占位响应return 200 'wechat api ok'Host: 39.107.55.179(IP 直连)app.conf全量代理: listen 80 default_server+location / { proxy_pass http://fastapi; },所有路径都转发到 8000app.conf是 Sep 25 就存在的早期配置(不是本次部署引入)。后果:-
IP 直连会暴露 FastAPI 的
/docs与/openapi.json(实测 200 + 真实 schema); 域名路径下这两个路径返回占位文本,不暴露。 -
MFC 插件当前
-DCADOCR_WX_BASE_URL=http://39.107.55.179正是依赖 IP 直连, 所以不能简单删掉app.conf(删了 IP 访问会落到 nginx.conf 内置的静态 server,/auth/、/usage/全部 404)。要收紧的话,应把wechat-api.conf改成listen 80 default_server并删app.conf,而不是单独删。 -
新增对外接口必须同时在
wechat-api.conf加location块(给域名路径), 否则备案后走域名会落到占位响应。 -
改 nginx 的流程见
user_shell_workflow.md:写成脚本 +sudo bash ~/xxx.sh, 不要给内联长命令。 -
/docs暴露问题用户 2026-09-27 决定暂不处理(原话选了"暂不处理"):判断是 风险低(只泄露接口结构、不含数据,/admin另有强密码),等 ICP 备案通过、插件 切回域名后再一并处理。不要再自作主张去关 docs 或删app.conf——要动先问。
/admin已于 2026-09-27 20:13 上线:wechat-api.conf新增location /admin块(显式透传Authorization头),应用侧ADMIN_USER=admin、密码为 24 位随机串 存于服务器.env(用户已自行保存)。/admin需重启应用才生效——ADMIN_PASSWORD是进程启动时读入的模块级常量。 -
-
GitHub 已弃用,不要再往那儿推(2026-09-27 用户决定)。服务器到 github.com 的连接 本就间歇性失败(
git pull报Empty reply from server或超时;curl -sI探到 200 也不代表 git 协议可用,实测出现过 curl 200 而 pull 仍失败)。国内访问不稳定, 用户明确不要 GitHub 备份了。所有代码走自建 Git 服务器。 若哪天需要从 GitHub 临时取东西(例如查旧仓库),仍可用 bundle 绕: 本地git bundle create /tmp/x.bundle main,ssh deploy@... 'cat > /tmp/x.bundle' < /tmp/x.bundle,服务器上git fetch /tmp/x.bundle main && git merge --ff-only FETCH_HEAD。
Why: 这些都是服务器实际状态,仓库代码和 git 历史里看不出来;REQUIREMENTS.md 的 技术栈描述(Docker MySQL)与实际不符,照着文档操作会踩坑。
How to apply: 涉及服务器操作时,直接用上面的真实路径/账号/镜像;给用户的命令要 考虑他需要手动 sudo;新增对外路由时提醒同步改 nginx。