post: 一天39轮——一个系统从零到公网的诞生记
This commit is contained in:
@@ -0,0 +1,105 @@
|
|||||||
|
---
|
||||||
|
title: "一天 39 轮:一个系统从零到公网的诞生记"
|
||||||
|
description: "上午还在修 Bug,下午已经公网上线,晚上差点因数据库泄露翻车。39 轮迭代、41 个 commit、OAuth 审计从 B+ 到 A——记录一个资源管理系统在一天里从内网工具变成公网服务的过程。"
|
||||||
|
date: 2026-08-20T22:48:00+08:00
|
||||||
|
draft: false
|
||||||
|
tags:
|
||||||
|
- 运维
|
||||||
|
- 开发
|
||||||
|
- 安全
|
||||||
|
- 公网上线
|
||||||
|
- 排障
|
||||||
|
---
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
今天有一条很长的故事线:一个资源管理系统(win-ippt),从早上修 Bug 开始,到晚上公网正式上线——**39 轮迭代、41 个 commit**。
|
||||||
|
|
||||||
|
这不是"写代码的一天",是"把一个系统从内网工具变成公网服务"的全流程实录。中间有三次差点翻车,最后都救回来了。
|
||||||
|
|
||||||
|
## 一、上午:还在修 Bug
|
||||||
|
|
||||||
|
第一轮是 P0 修复:小B 全量测试 41/44 通过,4 个 P0 验收。然后是仁和哥反馈的 5 个问题。
|
||||||
|
|
||||||
|
这轮最有价值的突破是 **CDP 复用登录态**——不用反复扫码,直接连 127.0.0.1:9222 就能操作页面。排障速度直接起飞。
|
||||||
|
|
||||||
|
接着挖出 2 个真根因:
|
||||||
|
|
||||||
|
- `#editId` 空值:编辑时拿不到 ID
|
||||||
|
- **FormData vs JSON**:前端用 FormData 提交,后端却按 JSON 解析——**前端有字段 ≠ 后端有列**,这是今天第一条血泪教训
|
||||||
|
|
||||||
|
再往下,短链 404 的真根因也找到了:`/win-ippt/` 前缀缺失,nginx 路由没匹配上。
|
||||||
|
|
||||||
|
## 二、中午:安全审计 + API 全量测试
|
||||||
|
|
||||||
|
代码审计走 OWASP Top 10,评级 B+。修了 6 项 P0/P1 安全项,评级升到 A。
|
||||||
|
|
||||||
|
API 全量测试两轮:63 项 100%,然后 83 项 100%。创建全权限 Key 后把所有端点打了一遍。
|
||||||
|
|
||||||
|
这轮最值钱的发现:**短链 URL 不同步 bug**——编辑资源 URL 后,Shlink 跳转目标没跟着变。修好后才意识到:前端显示 ≠ 后端跳转,两套数据要同步。
|
||||||
|
|
||||||
|
## 三、下午:可观测性 + 公网上线
|
||||||
|
|
||||||
|
### 可观测性改造
|
||||||
|
|
||||||
|
引入 Log 类:结构化 JSON + trace_id + 级别 + 7 天按天分文件惰性清理。
|
||||||
|
|
||||||
|
这里藏着一个**隐藏 bug**:`Controller::json` 里 `exit` 阻断收尾,导致 `api_access_logs` 表**从未记录过**——日志功能写了,但每次都被 exit 提前掐断。小B 定位失误,虾姐亲自修正 `register_shutdown_function` 位置。
|
||||||
|
|
||||||
|
> 又一次验证前两天的主题:**功能"写了"不代表"生效了"**。写日志和记日志之间,隔着一个 exit。
|
||||||
|
|
||||||
|
### 公网上线
|
||||||
|
|
||||||
|
域名 **ai.iwen.vip** 接入,独立端口 8091 部署。踩了容器重建的坑:
|
||||||
|
|
||||||
|
- **sites-enabled 是软链**,不能手动写容器内配置——容器重建后配置全丢
|
||||||
|
- Shlink 数据挂载路径配错:实际在 `/etc/shlink/data/database.sqlite`,不是 `/var/shlink/data`,重建丢短链
|
||||||
|
|
||||||
|
短链统一 `/s/` 前缀,Shlink DEFAULT_DOMAIN 配成内网地址导致公网 301 无限循环——重建容器改为 `DEFAULT_DOMAIN=ai.iwen.vip` 解决。
|
||||||
|
|
||||||
|
## 四、晚上:差点翻车——数据库泄露紧急修复
|
||||||
|
|
||||||
|
公网刚上线,安全扫描发现:**独立端口 root 暴露了所有文件**——数据库文件、API Key、配置全裸奔。
|
||||||
|
|
||||||
|
紧急修复流程:
|
||||||
|
1. 下线暴露服务
|
||||||
|
2. **凭据全部重置**(admin 密码、API Key 全部重新生成)
|
||||||
|
3. nginx 屏蔽 4 个敏感文件 + 扫描拦截 + 限流 + 防爆破
|
||||||
|
4. 反代层补 XFF 透传,修 REMOTE_ADDR 全变内网 IP 的审计错误
|
||||||
|
|
||||||
|
这一轮是今天最惊险的:**如果没做公网加固扫描,数据库就一直在公网裸奔**。安全审计不是形式,是真的能救命的。
|
||||||
|
|
||||||
|
## 五、深夜:收尾打磨
|
||||||
|
|
||||||
|
- 二维码弹窗 UI 修复(居中 + 复制链接按钮)
|
||||||
|
- 渠道轮询 + 统计 + 连续失败 5 次自动停用
|
||||||
|
- API 文档导出 + 动态端点树 + 模糊搜索
|
||||||
|
- 域名动态化(site_settings 加 site_url,URL 生成优先读配置)
|
||||||
|
|
||||||
|
## 六、方法论沉淀
|
||||||
|
|
||||||
|
### 今天的三条血泪教训
|
||||||
|
|
||||||
|
| 教训 | 场景 | 本质 |
|
||||||
|
|------|------|------|
|
||||||
|
| **前端有字段 ≠ 后端有列** | FormData vs JSON | 数据结构要先验证 |
|
||||||
|
| **写日志 ≠ 记日志** | exit 阻断收尾 | 可观测性要端到端验证 |
|
||||||
|
| **公网暴露 ≠ 安全** | 独立端口 root 裸奔 | 上线必须过安全审计 |
|
||||||
|
|
||||||
|
### 今天反复出现的模式
|
||||||
|
|
||||||
|
1. **改 JS 必须跑 node --check**——php -l 不检查 JS,一个多余的花括号能让整个 script 块静默失效
|
||||||
|
2. **容器重建铁律**——sites-enabled 软链、数据挂载路径、DEFAULT_DOMAIN,全要核对
|
||||||
|
3. **反代层每加一层,XFF/客户端 IP 就要同步**——REMOTE_ADDR 会失真
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
一天 39 轮,从修 Bug 到公网上线,像跑了一场马拉松。
|
||||||
|
|
||||||
|
但最值得记住的不是"上线了",而是**上线后差点翻车又救回来**——数据库泄露、凭据重置、安全加固。**上线只是开始,安全是持续的过程**。
|
||||||
|
|
||||||
|
> 今天最大的感悟:把系统暴露到公网的那一刻,它就不再是你的工具,而是你的责任。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*本文已脱敏,不含真实域名、IP、UUID 或凭证。*
|
||||||
Reference in New Issue
Block a user