里程碑
Mahesvara 从 2026 年 8 月一个"配置化路由的 Go 静态服务器"起步,经历语言主线切换(Go → PuXian)、md 多语言站点、生产级 TLS、进程内缓存与 L2 可靠性建设,再到「把 .px 脚本当接口」的脚本路由与编译缓存,到当前线上 0.22.5。以下是它的演进记录(均来自真实开发历史)。
版本演进时间线
v0.2.0 · Go 起点(2026-08-25)
配置化路由的 Go 静态 Web 服务器 —— 项目起点,验证"自研 Web 服务"路线可行。
v0.3.0 · 官网系统(2026-08-26)
在静态服务器之上叠加官网系统:纯白极简站点 + ws-reg 客户注册服务 + CRM 接入,第一次承载真实业务。
v0.4.1 · PuXian 成为主线(2026-09-02)
PuXian 实现成为主线,Go 版退役(历史保留在 git)。纯静态服务器核心以 PuXian 语言重写并投入生产。
v0.5.x · md 多语言站点(2026-09 初)
新增 md 多语言站点模式:src/*.md 源 + 模板 + LLM 翻译 + 磁盘缓存 → 自动构建多语言静态 HTML;默认语言裸路径、其它语言独立 URL,可 CDN、可被搜索引擎收录。模块化拆分起步。
v0.6.0 · 可观测补强(2026-09 初)
访问日志补来源 IP、新增只读 /__metrics 端点、静态响应加缓存头、反代响应头白名单透传(防 CRLF 注入)。
v0.7.0 · 更名与模块化定稿(2026-09-03)
- ws-web 正式更名 Mahesvara(全套标识/路径/文档同步)
- 模块化重构 + md 多语言站点 + 来源 IP/指标/缓存头全线收敛
- 证书热加载:60 秒轮询
cert_dir内容变化即换证,零重启零断连(#39) - per-site 限流:滑动窗口超限 429(nginx
limit_req思想)
v0.8.0 · L2 单机可靠性(2026-09-04)
配置 lint --check、重启竞态根治、上游失败语义(不可达/中断 → 502 不崩进程)。
外围 CLI 拆族(2026-09-04)
软件本体瘦身,能力拆为独立小工具:ma-md / ma-site / ma-cert / ma-diag(构建与诊断),随后 ma-telemetry(日志/指标聚合分析)、ma-audit(安全审计 CLI)陆续落地;ma-sec(单机守护:资源警戒 / SSH 入侵处置 / 防火墙自动拉起)与 ma-alertd(告警多渠道上报)补齐事前防范。全部静态二进制。
v0.9.0 · 优雅 reload(2026-09-04)
SIGHUP 配置热重载(nginx reload 对应物):重读配置 + config_check 校验,坏配置拒绝应用、旧配置照跑;不可热生效项告警提示 restart;systemd 接入 systemctl reload mahesvara。
v0.9.1 · 大文件流式(2026-09-04)
超过 1MB 的文件 C 层 64KB 分块流式发送,支持 Range 断点续传(M58-S1),大文件不再全量进内存。
v0.9.2 · 稳定性修复(2026-09-05)
修复 md worker 周期性运行时崩溃(llm_chat 上游异常返回防御),构建任务长期稳定。
v0.9.7 · 崩溃止血(2026-09-10)
缺失/非法 Host 头防御:畸形或无 Host 请求不再触发 len(null) 崩溃(线上 0.9.6 曾因此崩进程,恰逢 ACME 验证导致签发失败)。v0.9.3 ~ v0.9.6 为内部迭代(反代头透传 / 502 止血 / ACME 自动签发闭环 / 证书热加载补丁),不逐一展开。
v0.9.8 · 质量修复(2026-09-10)
晨曦 QA 6 项 issue 全修复:md 渲染站内链接(.md → 当前语言 .html)修正、行首加粗日期被吞修复、反代请求头透传补全(UA / Accept / Accept-Language / Origin 等)。
v0.9.9 · 自动 SSL(2026-09-10)
加载 vhost 发现站点无证书 → 后台自动执行 ma-cert issue(ACME http-01 签发 + 自动安装 cert_dir),失败按 10min~24h 退避、auto_cert: false 可关;证书就位后 60 秒内热加载生效。新站从此开箱即得 HTTPS,无需人工跑签发命令。
v0.10.0 · ma-cache 进程内 HTTP 缓存(2026-09-10)
站点级 cache 配置启用进程内 HTTP 缓存:只缓存可安全缓存的响应(GET/HEAD、2xx/3xx、无 Set-Cookie、Cache-Control 允许),TTL 夹逼 60~300 秒,SQLite 元数据 + 磁盘对象文件 + LRU 上限,缓存指标进 /__metrics。
v0.11.0 · 提前刷新(SWR 变体)(2026-09-10)
TTL 消耗至 prefetch_pct(默认 90%,如 TTL=300 → 270 秒)后,命中请求立即返回当前内容并后台异步回源续期 —— 用户零回源等待、窗口内几乎不 miss;inflight 单飞防并发回源、失败按 prefetch_backoff_sec(默认 10 秒)退避防源站风暴;prefetch_pct=0 可关。
v0.11.1 · 大文件流式与 deny 精修(2026-09-10)
- 大文件流式全链路修复:vhost handler 返回
{"file": …}的 C 层 64KB 分块流式发送此前仅在直连模式实现,公共管道 vhost 分支漏识别 file 键 → 静态大文件(>1MB)HTTP 200 空 body(软件发布源ws update下载全链路受影响);已补齐 file 分支识别 + Range 206/Content-Range/Accept-Ranges + 响应头白名单透传 - deny 目录精确匹配:
deny_dirs由"逐段子串匹配"改为"仅目录段精确匹配",带扩展名的文件名段不再被backup等子串误伤(ws-backup.tar.gz403 → 200,backup目录本身仍 403)
v0.12 – v0.18 · 生产化长跑(2026-09 中下旬)
这一段主要是"把线上问题一个个打死",版本号从 0.12 推到 0.18:反代大请求体(>1 MiB)静默丢体的根治、上游不可达的 502 语义、ACME 双 A 挑战、证书热加载与握手并发的 UAF、WS 统一入口(wss://…/agent/<节点> 收进 443 同进程)。
- v0.18.2:反代「> 1MiB 请求体静默空体」根治 —— 运行时对超过 1 MiB 的请求体走落盘暂存,本层此前只读
req["body"],导致所有经反代的大 POST 上游恒收空体且静默。修法:出站前先判body_tmp读回作体,读失败直接 500(绝不静默降级)。附回归脚本ma-proxy-bigbody-test.sh五档字节级断言
v0.19 · WS 统一入口与崩溃根治(2026-09 下旬)
- v0.19.0 / 0.19.1:顶层
ws_routes+ws_stream(manual),把wss://<host>/agent/<节点>收进同一监听同一进程;101 只在上游连上之后才写,上游不可达不写假 101 - v0.19.2:
ws_connect串行化,根治gethostbyname非线程安全导致的 SIGSEGV(16 并发沙箱第 473 个会话必崩) - v0.19.3:证书热加载 UAF 崩溃修复(P0)——
cert_seen上移全局,启动即登记,只有内容真变化才重注册 - v0.19.6:撤除
ws_connect串行化绕行(上游已根治),不可达上游不再头阻塞其它会话
v0.20 · 归一跳转与 WS 护栏(2026-10)
- v0.20.0:站点级 301「归一跳转」
redirect_to_host(GET/HEAD → 301,其余方法 → 308 保留方法与体;自指向不跳) - v0.20.13:WS 上游拨号护栏 —— 根治
ws_connect无握手超时导致的 worker 钉死与 ESTAB 僵尸 - v0.20.14:ma-cache SQLite 失败路径不再外溢成 500
v0.21 · .px 脚本路由(2026-10 末)
px_root + px_routes:把某个 URL 交给 PuXian 脚本执行,URL 里不出现 .px。三种匹配(exact / prefix / regex)、方法白名单(不符 → 405 + Allow)、strip_prefix 决定 PATH_INFO、timeout_ms 超时杀进程组 → 504、max_conc 超出 → 503。入参 CGI/1.1 子集(环境变量 + stdin),出参 stdout 头部 + 空行 + 正文。安全:脚本必须落在 px_root 内、配了 px_routes 的站点自动把 .px 并入 deny_exts。
意义:不再为一个功能开一个端口。此前要加一个接口,要么写 Go 服务再反代,要么用 ma-sec 之外的独立脚本;现在是"加一个 .px 文件"。
v0.22.0 · 目录映射 + 编译缓存(2026-10 末)
dir路由:/ticket/log→ticket/log.px,每加一个功能只加一个文件,不碰配置;"dir": "/"即整站 PHP 式映射- 编译缓存:
mode:"auto"先解释轨采样,连续超阈值 → 后台px build→ 之后直接 exec 产物。实测解释 28~36 ms → 编译 10~18 ms;重计算脚本 216 ms → 13 ms(16×) - 并发闸门改全局 mutex 精确计数(原实现在真并发下会 R1008 崩溃)
v0.22.1 · SNI 证书槽预检(2026-11-01)
运行时 SNI 槽是定长数组,超一格不是"新站不通"而是进程 exit 1 → 整机 443 全挂(2026-11-01 第 17 张证书的实例)。--check 与启动横幅同屏打印槽位使用量,≥80% 告警、超容量拒绝上线。
v0.22.2 · 站点级精确路径重定向(2026-11-03)
redirects:{"from": "/login.html", "to": "https://id.example.com/login.html"}。此前只能拿 .px 脚本硬凑(边缘机没装 PuXian 就直接 500)或用 meta refresh(200 不是 302)。--check 逐条体检并连 www.* 别名站一起打印生效清单。
v0.22.3 · pass_headers 通配(2026-11-04)
响应头白名单支持「前缀*」通配,并统计被丢弃的自定义头数量 —— 反代接第三方服务时,不用再把每个头名逐个列出来。
v0.22.4 · 编译失败的硬判定(2026-11-05)
症状:某个 px_routes 端点在生产稳定 1.1 秒/次、偶发 500,同类脚本只要 20–40 ms。
根因:Ma 的编译沙箱只 tar「脚本所在目录」,脚本里 import "../sync/synclib.px" 在沙箱内不存在;而 px build 对此只打警告、rc 仍是 0。旧版只判 rc == 0 与产物存在 ⇒ 把"运行期必报 R1001"的产物缓存成"编译成功" ⇒ 每个请求先跑产物失败、再回落解释轨。
修法:① 编译前静态预检跨目录 import,直接判失败;② 输出含"找不到模块"判失败、不落缓存;③ 缓存 key 世代升级淘汰旧坏产物;④ 失败冷却 60 秒防每请求重试。效果:解释轨继续服务(不 500)、日志一行写明"哪个文件哪行 import 了什么、该怎么改"。
v0.22.5 · md 站点 public/ 静态资源直读恒失效(2026-11-05)
症状:md 站点的 /css/style.css 一直 404,样式"丢了"。
根因:判定条件写成 contains(p, "..") == 0。contains() 返回的是 bool,而 PuXian 里 false == 0 是 false(严格类型比较,不做隐式转换)⇒ 条件恒不成立 ⇒ 「直读 public/」那条分支是死代码。不报错、不告警,只是静默地少做一件事。历史上这个站靠把 css 手工复制进 out/ 掩盖过去,out/ 重建后问题暴露。
修法:(not contains(p, ".."))。验证:删掉 out/css 副本后 /css/style.css 返回 200 + 6534 字节,/gaba.png 200。
设计哲学
几点贯穿始终的原则,也是选择与取舍的依据:
- 能静态就不要动态:md 多语言输出为分语言静态 HTML,同一 URL 内容恒定 → CDN 随便缓存、蜘蛛无 cloaking 风险、各语言可被独立收录
- 翻译翻 md 不翻 HTML:md 是纯文本,代码围栏天然隔离、diff 可审、人能校对
- 宁可不翻不可翻错:代码围栏结构与语言标记不一致 → 重试一次 → 仍失败则降级源语言
- 成本可控:翻译磁盘缓存命中零 LLM 调用;源变只重翻该页;顺序翻译不并发烧钱
- 缓存宁回源不错缓存:只缓存可安全缓存的响应,
Expires保守不解析,宁可回源也不写错内容 - 可靠性优先:配置 lint、坏配置拒绝应用、上游失败不崩进程、证书换证不中断 —— 生产环境自身就是第一测试场