<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>董锐</title><description>网络 · 身份 · 企业信息化</description><link>https://dr.cctv15.net/</link><templateTheme>Firefly</templateTheme><templateThemeVersion>6.16.6</templateThemeVersion><templateThemeUrl>https://github.com/CuteLeaf/Firefly</templateThemeUrl><lastBuildDate>2026年11月9日 10:45:08</lastBuildDate><item><title>海外园区宿舍管理系统：给上万人混住的园区做一套住得下、查得清的平台</title><link>https://dr.cctv15.net/posts/dorm-management-system/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/dorm-management-system/</guid><description>印尼工业园区 8 栋楼、近 3,000 床位、上万名中方与印尼籍员工混住。市面上的开源宿舍系统没有一个能用，因为约束根本不同。这是我从建模到上线做完的一套。</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这是我目前做得最完整、也最能说明「我能干什么」的一个系统：面向&lt;strong&gt;印尼中苏拉威西工业园区&lt;/strong&gt;自建宿舍的企业级管理平台。8 栋楼、近 3,000 张床位、上万名中方与印尼籍员工混住，已经上线在跑。&lt;/p&gt;
&lt;blockquote&gt;&lt;section&gt;&lt;h3&gt;🔗 在线演示&lt;a href=&quot;#-在线演示&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;管理端&lt;/strong&gt; — &lt;a href=&quot;https://dm.free--china.com&quot; target=&quot;_blank&quot;&gt;https://dm.free—china.com&lt;/a&gt;　|　&lt;strong&gt;员工自助端&lt;/strong&gt; — &lt;a href=&quot;https://dm.free--china.com/m&quot; target=&quot;_blank&quot;&gt;https://dm.free—china.com/m&lt;/a&gt;（手机打开，或把浏览器调成手机宽度）&lt;/p&gt;&lt;p&gt;演示账号密码统一 &lt;code&gt;dorm@2026&lt;/code&gt;：&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;账号&lt;/th&gt;&lt;th&gt;角色&lt;/th&gt;&lt;th&gt;建议先看&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;admin&lt;/code&gt;&lt;/td&gt;&lt;td&gt;系统管理员&lt;/td&gt;&lt;td&gt;全部功能，含集成对接与批量导入&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;dorm.chief&lt;/code&gt;&lt;/td&gt;&lt;td&gt;宿舍主管&lt;/td&gt;&lt;td&gt;全园区视角、审批、降标&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;warden.a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;A 栋宿管&lt;/td&gt;&lt;td&gt;&lt;strong&gt;只看得到 A 栋&lt;/strong&gt; —— 和 &lt;code&gt;admin&lt;/code&gt; 对比同一张看板的数字差异&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;hr01&lt;/code&gt; / &lt;code&gt;ehs01&lt;/code&gt;&lt;/td&gt;&lt;td&gt;人力资源 / 安全环保&lt;/td&gt;&lt;td&gt;权限收窄后的界面&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;员工自助端不发密码，用&lt;strong&gt;工号 + 手机验证码&lt;/strong&gt;登录（短信渠道未接入时验证码直接回显）。演示工号：&lt;code&gt;CN00001&lt;/code&gt;（中方，中文界面）、&lt;code&gt;ID00003&lt;/code&gt;（印尼籍，Bahasa 界面）。&lt;/p&gt;&lt;p&gt;演示环境数据&lt;strong&gt;全部为程序生成的模拟数据&lt;/strong&gt;，无任何真实人员信息。&lt;/p&gt;&lt;/section&gt;&lt;/blockquote&gt;
&lt;p&gt;它不是练手项目。它要解决的是一组&lt;strong&gt;真实的、错了要出事的&lt;/strong&gt;约束。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;为什么市面上的方案都不能用&lt;a href=&quot;#为什么市面上的方案都不能用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;搜「宿舍管理系统」，开源的基本都是学生宿舍课程设计。海外工业园区的约束和它们完全不是一回事：&lt;/p&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;约束&lt;/th&gt;&lt;th&gt;后果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;上万人且流动快&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;入职、离职、休假、调岗天天发生，人工台账三天就失真&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;多国籍混住&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;中方与印尼籍的作息、饮食、语言、宗教都不同，分区不是”可选功能”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;合规压力是实的&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;消防疏散要的是&lt;strong&gt;此刻&lt;/strong&gt;准确的在住名单；护照 / KITAS 过期等于非法居留&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;数据一旦不准就全废&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;人走了床位没释放，一个月后系统显示满床、实际空着几百张&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;最后一条是最致命的。&lt;strong&gt;宿舍系统的核心竞争力不是功能多，是数据准。&lt;/strong&gt; 整套设计都是围着这一点转的。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;五条地基设计&lt;a href=&quot;#五条地基设计&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这五条是改动代价最高的部分，也是这个系统和”能跑就行”的区别所在。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;1. 最小可分配单位是「床位」，不是房间&lt;a href=&quot;#1-最小可分配单位是床位不是房间&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;上下铺各自独立成一个铺位；夫妻房的双人床也按两个铺位建模，保持「一人一铺位」这个不变量。&lt;/p&gt;&lt;p&gt;把房间当最小单位的系统，三件事全做不了：三班倒排不了班次隔离、事故追溯查不到具体是谁睡哪、空床数永远对不上。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 入住是「带时间区间的记录」，永不覆盖&lt;a href=&quot;#2-入住是带时间区间的记录永不覆盖&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;调宿 = 关掉旧记录 + 新建一条新记录，两条都留着。一张床的历史，就是这张表的多行。&lt;/p&gt;&lt;p&gt;这个决定后来救了很多场景：事故追溯、传染病密接排查、警方与劳工部检查——全靠它。&lt;strong&gt;密接排查功能几乎是免费得来的&lt;/strong&gt;：查某人某时间窗内的同房间 / 同楼层接触者，时间区间模型天生就支持。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 三个「人数」是三件不同的事&lt;a href=&quot;#3-三个人数是三件不同的事&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;园区里「四人间实际住三人」是常态（空调制冷量不够、面积不足、主管批准降标）。所以人数必须拆成三个字段：&lt;/p&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;标称规格&lt;/td&gt;&lt;td&gt;「四人间」就是 4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;核定人数&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;这间实际按几人住，可以是 3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;物理床位&lt;/td&gt;&lt;td&gt;屋里真有几张床&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;降标后多余的床标记为停用并记录原因，不再被排人进去，但仍然留痕。混成一个字段的系统，第一次降标就开始对不上账。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4. 住宿的人不只有员工&lt;a href=&quot;#4-住宿的人不只有员工&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;还有家属随迁（配偶、子女）、长期访客、实习生、承包商工人。消防名单、房间占用、门禁都必须算上他们。这一条决定了人员模型不能直接复用 HR 的员工表。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5. 所有业务口径都在配置表里，不写死在代码&lt;a href=&quot;#5-所有业务口径都在配置表里不写死在代码&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;国籍、部门、职级（含各自的休假周期）、班次、宗教、承包商、18 种房型、17 条排宿规则的松紧——全部在设置页改，改完立即生效，不用改代码、不用重启。&lt;/p&gt;&lt;p&gt;园区的规矩会变，而且是由不写代码的人来定。口径写死在代码里，等于每次调整都要排一次发版。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;排宿规则引擎&lt;a href=&quot;#排宿规则引擎&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;17 条规则，每条三档：&lt;strong&gt;关闭 / 仅提醒 / 强制拦截&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;男女不同房、夫妻房须有配偶关系、家属须与挂靠员工同房、房型职级门槛、上下铺限制（有人不能睡上铺）、无障碍需求、国籍归属、同房同班次、同房同部门、自有与承包商不混住、饮食禁忌一致、吸烟习惯一致、房内语言可沟通……&lt;/p&gt;&lt;p&gt;工程上关键的一点是&lt;strong&gt;硬约束和软约束走不同的返回&lt;/strong&gt;：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;硬约束不通过 → &lt;code&gt;400&lt;/code&gt; 直接拦下，&lt;strong&gt;带 &lt;code&gt;force&lt;/code&gt; 参数也越不过去&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;软约束不通过 → &lt;code&gt;409&lt;/code&gt; 带提醒返回，宿管确认后可以继续&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;这个区分很重要。全做成硬拦截，现场会想尽办法绕过系统；全做成提醒，规则就等于没有。&lt;/p&gt;&lt;p&gt;国籍策略还要&lt;strong&gt;逐级继承&lt;/strong&gt;（房间 &amp;gt; 楼层 &amp;gt; 楼栋），才能表达「一二层印尼籍、三四层中方、五六层不限」这种楼层级混住。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;让宿管真的愿意用&lt;a href=&quot;#让宿管真的愿意用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;系统再严谨，宿管不用也是废的。所以做了几个很”土”但有效的东西：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;楼层平面图&lt;/strong&gt;：走廊两侧排布，房间格子里画出真实床位小方块，哪张床空着一眼看到，可按入住率 / 国籍分区 / 房型三种口径着色&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;楼栋剖面图&lt;/strong&gt;：一屏看完全园区&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;房门二维码&lt;/strong&gt;：管理端可整层批量打印，员工扫码直达自己房间并一键报修&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;夜间查寝自动生成该层在住点名清单&lt;/strong&gt;，不用手抄&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;15 类主动告警&lt;a href=&quot;#15-类主动告警&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这些都是「不主动查就发现不了，但迟早会出事」的地方：&lt;/p&gt;&lt;p&gt;离职未退宿（数据失真头号原因，支持一键批量清退含物品结算）、&lt;strong&gt;证件即将到期&lt;/strong&gt;（护照 / KITAS 过期 = 非法居留）、报修超 SLA、房间超住、夫妻房异常、家属未与员工同房、休假即将到期、违规积分超限、访客超期未离开、物品未归还、已分配超期未入住、状态口径不一致、降标与床位不一致、功能房被占住……&lt;/p&gt;&lt;p&gt;&lt;strong&gt;这一块才是系统的价值所在。&lt;/strong&gt; 录入功能谁都会写，能主动告诉你”哪里已经不对了”的才叫管理系统。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;两拨用户，两种登录&lt;a href=&quot;#两拨用户两种登录&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;管理端几十人，账号密码；员工上万人，&lt;strong&gt;不发密码&lt;/strong&gt;——工号 + 手机验证码，或企业平台扫码。&lt;/p&gt;&lt;p&gt;员工自助端在 &lt;code&gt;/m&lt;/code&gt;，与管理端完全隔离：独立 token、独立路由、独立样式。越权在入口一次堵死——员工 token 只能访问 &lt;code&gt;/api/self/*&lt;/code&gt;，其余一律 403。&lt;/p&gt;&lt;p&gt;权限模型是 &lt;code&gt;模块:动作&lt;/code&gt; 的权限点，外加&lt;strong&gt;楼栋数据范围&lt;/strong&gt;贯穿看板 / 花名册 / 疏散 / 全部告警。A 栋宿管和宿舍主管打开同一张看板，看到的数字是不一样的。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;集成：按能力建模，不按厂商建模&lt;a href=&quot;#集成按能力建模不按厂商建模&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;预留了 15 个集成平台占位（企业微信 / 钉钉 / 飞书 / Teams / 泛微 / 致远 / 用友金蝶 HR / 通用 OA / 海康威视 / 大华 / LDAP / 短信 / 邮件 / WhatsApp / 通用 Webhook），但&lt;strong&gt;不是按厂商写 15 套代码&lt;/strong&gt;，而是抽象成六种能力：SSO、人员同步、消息推送、审批流、&lt;strong&gt;视频接入&lt;/strong&gt;、&lt;strong&gt;门禁联动&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;通知中心同理：业务代码只管”发生了什么”，不管发到哪个平台；按收件人国籍自动选中文 / Bahasa / English；一条事件扇出到多渠道，渠道未启用时&lt;strong&gt;记录原因而不是静默丢弃&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;视频接入这块的边界是刻意划的：楼 / 层 / 房间的空间树上可以挂设备（摄像头、门禁、电表），但主应用只存”空间↔设备”的映射和鉴权，&lt;strong&gt;不碰码流&lt;/strong&gt;——码流走独立网关服务。园区网络有内网限制，监控流不能出园区，这个边界一开始就得留出来。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;技术栈&lt;a href=&quot;#技术栈&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;层&lt;/th&gt;&lt;th&gt;选型&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;后端&lt;/td&gt;&lt;td&gt;Node.js ≥20 · TypeScript · Fastify 5 · Prisma 6（单进程，无外部依赖服务）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;数据库&lt;/td&gt;&lt;td&gt;SQLite / PostgreSQL（schema 按 PG 兼容写法，切换只改 provider）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;前端&lt;/td&gt;&lt;td&gt;React 18 · Vite 6 · Ant Design 5（管理端与移动自助端同一 SPA）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;认证&lt;/td&gt;&lt;td&gt;自实现 JWT（HMAC-SHA256）+ scrypt&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;语言&lt;/td&gt;&lt;td&gt;中文 / Bahasa Indonesia / English 三语，界面与通知模板都是&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;认证有意没用第三方库：JWT 签验和密码哈希用 &lt;code&gt;node:crypto&lt;/code&gt; 手写不到 80 行，行为完全可控，也少一层供应链风险。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;这个项目说明了什么&lt;a href=&quot;#这个项目说明了什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;我的本职是网络、系统和信息化交付。这套系统真正体现的能力，其实和写代码本身关系不大：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;能把现场的模糊需求翻译成不会崩的数据模型&lt;/strong&gt;——床位而不是房间、时间区间而不是覆盖、三个人数字段而不是一个&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;知道合规要求会落到哪张表上&lt;/strong&gt;——消防名单、证件到期、密接排查，都是设计时就想清楚的，不是后来补的&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;懂园区的实际约束&lt;/strong&gt;——内网限制、监控流不出园、多国籍混住、不写代码的人要改口径&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能自己把它交付到上线&lt;/strong&gt;，而不是只画个方案交给集成商&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;这也是我做园区信息化项目十几年攒下来的东西，只不过这一次，是我自己一行行写出来的。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>企业 AD 从 0 到 1：域控、终端、证书、无线和 SSO</title><link>https://dr.cctv15.net/posts/ad-zero-to-one/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/ad-zero-to-one/</guid><description>在一家从没有域的制造企业里，把 Active Directory、DNS、证书、SCCM、RADIUS 和 Entra ID 一次铺起来。这篇写边界怎么划、坑在哪，不写客户内网细节。</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这家公司原来没有域。账号在各处散着：电脑是本地用户，Wi-Fi 是预共享密钥，微软 365 是另一套，业务系统再各自开户。人一多，入职离职、权限回收、无线准入全靠手工。&lt;/p&gt;
&lt;p&gt;我的任务是把身份底座从 0 铺到能日常运转：AD 管人、SCCM 管电脑、RADIUS 管无线、Entra ID 管微软云、LDAP 把其它系统接进同一套登录。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;先定边界&lt;a href=&quot;#先定边界&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;从 0 建域最容易做成「一台 Windows Server 装完 AD 就算完」。那只是目录服务起来了，身份问题一个没解决。&lt;/p&gt;&lt;p&gt;我按四层来拆：&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;层&lt;/th&gt;&lt;th&gt;解决什么&lt;/th&gt;&lt;th&gt;落在哪&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;目录&lt;/td&gt;&lt;td&gt;人、组、OU、GPO&lt;/td&gt;&lt;td&gt;AD DS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;解析&lt;/td&gt;&lt;td&gt;内网名字、公司 DNS 出口&lt;/td&gt;&lt;td&gt;AD 上的 DNS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;终端&lt;/td&gt;&lt;td&gt;加域电脑的清单、远程、补丁、报表&lt;/td&gt;&lt;td&gt;Configuration Manager&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;认证出口&lt;/td&gt;&lt;td&gt;Wi-Fi、门户、业务系统、微软云&lt;/td&gt;&lt;td&gt;NPS / AD CS / Entra ID / LDAP&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;虚拟化平台上先部署操作系统、SQL Server 和报表库，再装角色。SQL 是 SCCM 和报表的前提，不要倒过来装。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;DNS 不只是域的附属&lt;a href=&quot;#dns-不只是域的附属&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;AD 起来之后，DNS 承担了整个公司的解析出口。这件事比「给域控制器加个角色」麻烦：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;内网记录必须权威，不能被公网 DNS 抢走&lt;/li&gt;
&lt;li&gt;出网解析要稳定，还得处理个别&lt;strong&gt;政府网站、厂家站点&lt;/strong&gt;在公共 DNS 上表现异常的情况——有的要指定转发，有的要拆开条件转发器，有的只能写静态记录&lt;/li&gt;
&lt;li&gt;客户端只认这一跳，DNS 一抖，加域、GPO、证书申请会一起抖&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;所以 DNS 是身份底座的一部分，不是网络组顺手代管的服务。&lt;/p&gt;&lt;p&gt;IIS 用来挂门户和部分内部发布，跟证书服务放在同一套身份语境里，避免门户是一套账号、域是另一套。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;SCCM：把「加了域」变成「管得住」&lt;a href=&quot;#sccm把加了域变成管得住&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;电脑加域只说明它认这套账号。真正要的是：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;边界清楚：哪些网段、哪些站点属于哪套管理点&lt;/li&gt;
&lt;li&gt;清单可视化：谁的机器、什么系统、在不在线&lt;/li&gt;
&lt;li&gt;远程：协助而不是让人把电脑抱过来&lt;/li&gt;
&lt;li&gt;报表：领导问「域里有多少台、多少没打补丁」时有数&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Configuration Manager 从边界、发现、客户端推送一路建下来。这一步的工作量不在点安装向导，而在&lt;strong&gt;边界不要画错&lt;/strong&gt;——画错了，客户端会去找一个它到不了的管理点，表现为「加了域但 SCCM 里看不见」。&lt;/p&gt;&lt;p&gt;密码自助（AD Self-Service）是给帮助台减负的：解锁和重置不必每次工单打到 IT。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;证书、RADIUS 和无线 SSO&lt;a href=&quot;#证书radius-和无线-sso&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;无线如果继续用 PSK，域建得再完整也只覆盖到有线电脑。制造企业里手机、笔记本、访客终端都走 Wi-Fi，PSK 等于把内网口子开在空气里。&lt;/p&gt;&lt;p&gt;做法是：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;AD CS&lt;/strong&gt; 签发 NPS 和无线证书，避免自签证书在客户端弹一堆警告&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NPS RADIUS&lt;/strong&gt; 接华为 AC，802.1X / Portal 认证落到域账号&lt;/li&gt;
&lt;li&gt;账号源对齐 &lt;strong&gt;Entra ID&lt;/strong&gt;（Azure AD）：人走一套组织架构，Wi-Fi、Teams、Outlook 认同一套身份&lt;/li&gt;
&lt;li&gt;只允许企业组织账号接入，访客走隔离 VLAN&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;做到这一步，Wi-Fi 登录和办公套件 SSO 是同一件事的两个出口，而不是两套账号。&lt;/p&gt;&lt;p&gt;AD 与 Azure AD / Entra ID 的同步，用来在本地管理员工的微软账号和策略。其它还没云化的系统，走 &lt;strong&gt;LDAP&lt;/strong&gt; 接进同一目录，把 SSO 补齐——不要每个系统再造一遍用户表。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;不做什么&lt;a href=&quot;#不做什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;不在第一期上复杂的条件访问和全员 MFA 强制（先保证加域、无线、解锁能日常运转）&lt;/li&gt;
&lt;li&gt;不把业务系统的权限模型塞进 AD 组里一次性「完美映射」（组可以先粗，权限细了再收）&lt;/li&gt;
&lt;li&gt;不在文章里写网段、主机名和客户内网拓扑&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;结果&lt;a href=&quot;#结果&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;有了这套底座之后，入职是加组，离职是禁用账号，无线和办公套件跟着失效；电脑在 Configuration Manager 里看得见、连得上、报得出。后面的防火墙策略、Zabbix 纳管、保密产线准入，都站在这套身份上面，而不是再各搞一套。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>换核心交换机：不做一次性大割接</title><link>https://dr.cctv15.net/posts/core-switch-ac-migration/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/core-switch-ac-migration/</guid><description>老核心承载 25 个三层接口、下联 21 台接入交换机，独立 AC 管着 24 台 AP。换成华为 CloudEngine 并把无线收进新核心，跨 V200 到 V600 两个大版本。这篇讲怎么拆成可回滚的小步，以及射频诊断查出来的真问题。</description><pubDate>Sat, 12 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;办公楼的老核心交换机是一台 S5735S，VRP V200，32 个电口加 4 个万兆口，&lt;strong&gt;25 个三层接口全在它身上&lt;/strong&gt;，下联 21 台接入交换机，默认路由指向防火墙。无线是另一台独立的 AC6507S，管着 24 台 AirEngine AP。&lt;/p&gt;
&lt;p&gt;新核心是华为 CloudEngine S6730-H24X6C-V2，YunShan V600，24 个 SFP+ 加 6 个 QSFP+——&lt;strong&gt;一个电口都没有&lt;/strong&gt;。目标是新核心接管三层和无线控制器，老核心降级成接入汇聚、补端口用。&lt;/p&gt;
&lt;p&gt;核心交换机一停，整栋楼断网。所以整件事只有一个原则：&lt;strong&gt;不做一次性大割接。&lt;/strong&gt;&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;一、不照抄老配置&lt;a href=&quot;#一不照抄老配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;老机上是 &lt;code&gt;vlan batch 2 to 4094&lt;/code&gt;——4093 个 VLAN 全建着，实际在用的只有 27 个。&lt;/p&gt;&lt;p&gt;照抄最省事，但等于把十年前的历史包袱原样搬进新设备，以后谁也说不清哪个 VLAN 还有用。所以新核心&lt;strong&gt;只建实际在用的 27 个&lt;/strong&gt;，每个都能对上业务。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;二、三层接口先建好、全部关着&lt;a href=&quot;#二三层接口先建好全部关着&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;25 个 Vlanif 在新核心上全部提前建好、地址配好，然后 &lt;strong&gt;全部 &lt;code&gt;shutdown&lt;/code&gt;&lt;/strong&gt;。13 个 DHCP 地址池、ACL、7 个 QoS 对象也一并预配。&lt;/p&gt;&lt;p&gt;割接时按 VLAN 一个一个来：老核心关一个 Vlanif，新核心开同一个，验证这个网段的终端拿地址、能出网，再做下一个。任何一个出问题，只回退这一个 VLAN，其他网段完全不受影响。&lt;/p&gt;&lt;p&gt;生成树也是同样的思路：割接期新核心先用 &lt;code&gt;stp mode stp&lt;/code&gt; 跟现网保持一致，&lt;strong&gt;割接完成后核心和接入一起升 MSTP&lt;/strong&gt;。只升核心的话，和接入之间的边界端口会自动回落成 STP，等于白升。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;三、跨大版本，命令会变&lt;a href=&quot;#三跨大版本命令会变&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;V200 到 V600 是跨大版本，老配置直接粘过去会大面积报错。踩过的几处：&lt;/p&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;V200 写法&lt;/th&gt;&lt;th&gt;V600 的情况&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;vlan batch&lt;/code&gt; 一行塞很多项&lt;/td&gt;&lt;td&gt;一行不能太长，拆成每行 5~6 项&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;traffic classifier X operator or&lt;/code&gt;&lt;/td&gt;&lt;td&gt;去掉 &lt;code&gt;operator or&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;traffic policy X match-order config&lt;/code&gt;&lt;/td&gt;&lt;td&gt;去掉 &lt;code&gt;match-order config&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;display vlan brief&lt;/code&gt;&lt;/td&gt;&lt;td&gt;改成 &lt;code&gt;display vlan summary&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;display wlan ssid-profile all&lt;/code&gt;&lt;/td&gt;&lt;td&gt;WLAN 命令族不带 &lt;code&gt;wlan&lt;/code&gt; 前缀&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;总结出来的规律：&lt;strong&gt;老配置里凡是带可选参数的命令，迁过来先写最短形式&lt;/strong&gt;，报错了再按 &lt;code&gt;?&lt;/code&gt; 补。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;四、无线割接和三层割接拆开&lt;a href=&quot;#四无线割接和三层割接拆开&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这一步是整个方案里最关键的设计。&lt;/p&gt;&lt;p&gt;AP 是靠 VLAN 内的二层广播发现 AC 的（没配 DHCP option 43）。这意味着只要新核心&lt;strong&gt;不配 &lt;code&gt;capwap source interface&lt;/code&gt;&lt;/strong&gt;，它在这个 VLAN 里就完全静默，AP 不会去找它。&lt;/p&gt;&lt;p&gt;于是所有无线配置——10 个 VAP 模板、6 个 AP 组、24 条 AP 白名单——都可以&lt;strong&gt;提前在新核心上建齐、逐条对账&lt;/strong&gt;，现网一点不受影响。真正割接那一刻只动一条配置；回滚也只动这一条。&lt;/p&gt;&lt;p&gt;新核心在无线管理 VLAN 里用一个临时地址就够了，不必去抢原来 AC 的地址。这样&lt;strong&gt;无线割接和三层割接彻底解耦&lt;/strong&gt;，可以分开排期、各自回滚。&lt;/p&gt;&lt;p&gt;几个跨版本迁移时容易翻车的点：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;授权数别看错。&lt;/strong&gt; AP 容量要看 &lt;code&gt;display license resource usage detail&lt;/code&gt;（新核心显示 &lt;code&gt;0/80&lt;/code&gt;）。&lt;code&gt;display license&lt;/code&gt; 里的 &lt;code&gt;Control value : 1&lt;/code&gt; 是&lt;strong&gt;授权包的份数&lt;/strong&gt;，不是 AP 台数，很容易误读成「只授权了 1 台」&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置名字会骗人。&lt;/strong&gt; 老 AC 上有两套 SSID 配置都叫同一个名字，看起来在用的那套其实没被任何 AP 组引用，真正在用的是网页向导遗留的另一套。靠 &lt;code&gt;display station all&lt;/code&gt; 里的射频和 WLAN 编号交叉验证才确认&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wi-Fi 密码的密文跨版本不可信。&lt;/strong&gt; V200 的密文灌进 V600 后会被重新加密，但输出上&lt;strong&gt;分不清是正确解密后重新加密，还是把整串密文当成明文又加密了一遍&lt;/strong&gt;。只能用明文重设，再拿终端实连验证&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ap-id&lt;/code&gt; 不要带 &lt;code&gt;type-id&lt;/code&gt;：那是设备本地型号表的索引，跨版本不保证一致，去掉后 AP 上线会自动填&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;五、射频诊断：真问题和「AP 太密」关系不大&lt;a href=&quot;#五射频诊断真问题和ap-太密关系不大&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;用户反馈是「Wi-Fi 慢」。直觉上会觉得是 AP 太密互相干扰，实际拉 &lt;code&gt;display radio all&lt;/code&gt; 一看，问题是另外几个：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1. 11 台 AP 挤在 2.4G 的信道 1 上。&lt;/strong&gt; 二楼的 8 台全在。根因是二楼那组 AP 的射频上被人关掉了自动选信道。零终端的 AP 空口占用率都有 40%，全是同频互撞。恢复自动选信道。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 244 个终端里 131 个压在两台 AP 上。&lt;/strong&gt; 其中一台的 5G 射频 69% 满载，旁边那台只连了 2 个终端。这是布点和容量问题，&lt;strong&gt;配置解决不了&lt;/strong&gt;，结论是补点 AP。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. 全网功率被手工钉死。&lt;/strong&gt; 发射功率全部手工指定、自动调功关闭。恢复自动调功，同时在射频模板里设上限——&lt;strong&gt;只许往下调，不许往上加&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;另外几个决定：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;V600 很多优化默认就开着&lt;/strong&gt;：频段导航、智能漫游、负载均衡、空间复用都不用再配，老 AC 上这些全没有，迁过来自动就有&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DFS 信道保留&lt;/strong&gt;：查了老 AC 覆盖五天半的日志，零雷达事件。摘掉 DFS 会把 5G 可用信道从 13 个砍到 9 个，没有收益&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2.4G 不能关&lt;/strong&gt;：门禁设备依赖 2.4G，只能做信道和功率优化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;802.11r 快速漫游要求纯 WPA2&lt;/strong&gt;，在 WPA/WPA2 混合模式下直接报错。内部 SSID 改成纯 WPA2 后开启；访客网和仓库扫描枪那两个 SSID 考虑老终端兼容，保持混合模式&lt;/li&gt;
&lt;li&gt;信道负载模式默认是 &lt;code&gt;outdoor&lt;/code&gt;，室内办公楼改成 &lt;code&gt;indoor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;故意没配&lt;/strong&gt;接收灵敏度阈值：它能进一步缩小小区，但取值必须依据实测底噪和 AP 间距，等新 AP 装完再调&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;六、只有 telnet 的设备，怎么批量下发&lt;a href=&quot;#六只有-telnet-的设备怎么批量下发&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;老核心只开了 telnet，22 端口是关的。几千行配置不可能手敲，截图读回显又慢又漏行。&lt;/p&gt;&lt;p&gt;做法是用 PowerShell 的 &lt;code&gt;TcpClient&lt;/code&gt; 直连 23 端口，自己处理 telnet 选项协商，命令逐行发送、回显全量落盘。用户名密码由操作人当场输入，脚本里不存。&lt;/p&gt;&lt;p&gt;两个踩出来的经验：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;配置文件必须纯 ASCII。&lt;/strong&gt; 中文注释在 PowerShell 5.1 里按 GBK 解码时会把行尾换行一起吞掉，下一行就被并进了注释——曾经因此漏发了 &lt;code&gt;system-view&lt;/code&gt;，后面所有命令都跑在用户视图里。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;三条保险缺一不可：&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;下发前校验前几条命令是否符合预期&lt;/li&gt;
&lt;li&gt;每条命令后解析提示符，&lt;strong&gt;一旦从系统视图 &lt;code&gt;[dev]&lt;/code&gt; 掉回用户视图 &lt;code&gt;&amp;lt;dev&amp;gt;&lt;/code&gt; 立即停止&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;进视图类命令（&lt;code&gt;interface&lt;/code&gt;、&lt;code&gt;acl number&lt;/code&gt;、&lt;code&gt;vlan&lt;/code&gt;、&lt;code&gt;traffic&lt;/code&gt;）一报错立即停止&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;没有第 2、3 条会出很隐蔽的事故：进视图的命令失败了，后面那条 &lt;code&gt;quit&lt;/code&gt; 会越级退到用户视图，再一条 &lt;code&gt;quit&lt;/code&gt; 就是&lt;strong&gt;登出&lt;/strong&gt;——而 &lt;code&gt;quit&lt;/code&gt; 本身是执行成功的，「连续报错计数」根本触发不了。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;写在最后&lt;a href=&quot;#写在最后&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;核心割接最怕的不是技术难度，是&lt;strong&gt;一步到位&lt;/strong&gt;。把它拆成「预配全部关着 → 按 VLAN 一个个开 → 无线单独一个开关」，每一步都能单独验证、单独回滚，整件事的风险就从「一次赌整栋楼」变成了「每次只赌一个网段」。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>把 Agent 用在信息化交付里：方案、交底和预算</title><link>https://dr.cctv15.net/posts/ai-agent-ops/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/ai-agent-ops/</guid><description>在镭射沃期间把 GLM、Gemini、Grok、Claude、GPT 用进日常：写建设方案、整理技术文档、做工程预算，以及跟集成商做功能梳理和技术交底。</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;信息化项目里最耗时间的，经常不是敲命令，而是把一件事写清楚：要做什么、谁来做、做到什么程度、花多少钱、风险在哪。以前这些靠一个人熬文档；现在 Agent 可以显著缩短&lt;strong&gt;第一版&lt;/strong&gt;的时间，前提是你知道它哪句能信、哪句必须自己改。&lt;/p&gt;
&lt;p&gt;我日常会同时用 GLM、Gemini、Grok、Claude、GPT（含 Claude Code 这类能碰仓库和命令的 Agent）。不是因为追新，而是不同模型在「中文方案结构 / 英文资料检索 / 代码和配置草稿」上各有长处，交叉看一遍比迷信一家要稳。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;用在哪，不用在哪&lt;a href=&quot;#用在哪不用在哪&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;适合：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;建设方案的目录、现状分析、分阶段目标&lt;/li&gt;
&lt;li&gt;把现场调研纪要收成功能清单&lt;/li&gt;
&lt;li&gt;工程预算的科目框架（设备、实施、维保、培训、预备费）&lt;/li&gt;
&lt;li&gt;给集成商的技术交底提纲：接口、责任面、验收口径&lt;/li&gt;
&lt;li&gt;把厂商文档翻译成「我们这次到底要开哪些功能」&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;不适合直接定稿：&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;最终报价和品牌选型（价格和货期必须问过渠道）&lt;/li&gt;
&lt;li&gt;安全策略的放行清单（模型看不见你的现网）&lt;/li&gt;
&lt;li&gt;合同条款和法律承诺&lt;/li&gt;
&lt;li&gt;任何带客户保密细节的原文外发&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;一句话：Agent 产出的是&lt;strong&gt;可改的草稿和检查清单&lt;/strong&gt;，不是可盖章的文件。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;技术交底怎么用&lt;a href=&quot;#技术交底怎么用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;找第三方集成商时，最怕两边各理解一套。我会先让 Agent 根据调研记录生成一份功能对照表：模块、输入输出、依赖、验收方式、不在范围内的事项。然后自己按现场改，再拿着这张表开会。&lt;/p&gt;&lt;p&gt;好处是会议上吵的是表里的行，而不是「我觉得你应该懂」。交底结束，这张表就能进项目文档，预算也能按行估，而不是拍一个整数。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;和本职的关系&lt;a href=&quot;#和本职的关系&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;网络、身份、防火墙、Zabbix 仍然要自己设计和验收。Agent 把文档和沟通的密度拉开之后，我才能把时间留在现网和产线隔离这种不能写错的地方。智能化建设不是再做一个聊天机器人给领导看，而是让方案、预算、交底这些交付物的质量稳定在可评审的水平。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>跨境 SD-WAN 和多品牌防火墙：一个总部，四地出口</title><link>https://dr.cctv15.net/posts/cross-border-sdwan/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/cross-border-sdwan/</guid><description>深圳总部辐射越南、香港、韩国、苏州。专线混互联网、策略路由、Fortinet 与 AhnLab 的整合，以及用 Zabbix 把设备纳管和报表先跑起来。</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;制造企业一旦在海外设厂，网络就不再是「机房里那几台交换机」。深圳要访问越南的业务系统，韩国要回总部的身份服务，香港有独立的监管和线路习惯，苏州又是另一套园区。每地一个防火墙品牌、一条专线、一套习惯，最后一定会出现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问绕远、专线闲着互联网堵着&lt;/li&gt;
&lt;li&gt;策略在四套设备上各写一遍，改漏一个口子&lt;/li&gt;
&lt;li&gt;监控各看各的，故障要打电话问「你们那边灯是不是红的」&lt;/li&gt;
&lt;/ul&gt;
&lt;section&gt;&lt;h2&gt;骨干怎么铺&lt;a href=&quot;#骨干怎么铺&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;目标很明确：&lt;strong&gt;深圳总部是枢纽&lt;/strong&gt;，越南、香港、韩国、苏州是分支。&lt;/p&gt;&lt;p&gt;SD-WAN 在这里做三件事：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;混合接入&lt;/strong&gt;：专线保关键系统，互联网做备份和办公突增，不要赌单一运营商&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链路优选&lt;/strong&gt;：延迟、丢包、抖动进来当选路依据，而不是静态「这条永远主、那条永远备」&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;策略路由&lt;/strong&gt;：身份、监控、办公、产线走不同路径和隧道，避免所有流量挤一条 Overlay&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;稳定性运维比开局更耗时间。跨境链路的故障经常不在你的设备上：对端运营商、当地防火墙策略、DNS 出口、证书过期，都会表现为「访问总部很慢」。所以骨干要和身份、DNS 一起看，不能只盯隧道状态。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;防火墙：整合，而不是换齐&lt;a href=&quot;#防火墙整合而不是换齐&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;现场已经存在 Fortinet、AhnLab 以及其它品牌。一上来「全部换成同一家」在预算、窗口和当地支持上都走不通。&lt;/p&gt;&lt;p&gt;我做的是&lt;strong&gt;策略层整合&lt;/strong&gt;：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;对象（地址 / 服务 / 时间）命名对齐，四地能对得上「这是同一类东西」&lt;/li&gt;
&lt;li&gt;安全策略按「源区域 → 目的 → 谁 → 干什么」写，禁止在设备里堆编号注释只有原作者能懂的规则&lt;/li&gt;
&lt;li&gt;变更走同一套评审：开端口先问身份和产线分区，再问防火墙&lt;/li&gt;
&lt;li&gt;后期迭代时，能合并的合并，能下沉到 SD-WAN 的不下沉到每台墙&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;香港、越南、韩国的合规和厂商支持半径不一样，AhnLab 在韩系环境里常见，Fortinet 在总部和部分海外出口常见。整合的目标是&lt;strong&gt;运维语言统一&lt;/strong&gt;，不是 Logo 统一。&lt;/p&gt;&lt;p&gt;核心设备升级和集团网络架构规划放在同一条线上：先把出口、核心、汇聚的角色写清楚，再决定哪台该退役。否则升级会变成「新设备按旧逻辑配一遍」。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;Zabbix：先看见，再自动&lt;a href=&quot;#zabbix先看见再自动&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;没有统一监控时，四地故障靠聊天软件。Zabbix 服务端搭起来之后，优先做三件不花哨但每天用得上的事：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;设备纳管&lt;/strong&gt;：防火墙、交换机、关键服务器、隧道对端，先进模板再谈漂亮大屏&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;策略&lt;/strong&gt;：什么该告警、谁收、多久升级，避免凌晨被磁盘 IO 的 Warning 叫醒&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动化报表&lt;/strong&gt;：可用率、流量、故障次数对接出去，给周会一个数而不是截图&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Zabbix 不替代厂商自家的分析器，它解决的是「跨品牌、跨站点，有一个共同的眼睛」。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;和身份的关系&lt;a href=&quot;#和身份的关系&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;跨境网络如果不管身份，就会变成「专线很通，谁都能走」。AD / RADIUS / Entra ID 起来之后，分支访问总部系统可以按组授权，Wi-Fi 和办公套件跟同一套账号。网络提供路，身份提供「谁可以上路」。&lt;/p&gt;&lt;p&gt;具体拓扑、公网地址和隧道参数不在这里展开。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>涉密车间的网络怎么隔离：分区、准入、访客和审计</title><link>https://dr.cctv15.net/posts/secure-line-network/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/secure-line-network/</guid><description>涉密车间的网络合规化改造。只写可公开的方法：办公网与车间网怎么分开、终端怎么准入、访客怎么隔离、审计看什么。不涉及任何具体客户、工艺、产品线和现场细节。</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;涉密车间对「产线网」的要求，和普通办公网不是一回事。客户会把保密条款写进合同和现场审计清单：哪些人能进、哪些设备能插、数据能不能出去、访客手机怎么办。IT 的工作不是写一篇保密承诺，而是把这些要求落到&lt;strong&gt;网络分区、终端、门禁和日志&lt;/strong&gt;上。&lt;/p&gt;
&lt;p&gt;下面只写通用方法。具体客户、现场拓扑、产品线、产量和审计条款均不在本文范围内。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;先把网分开&lt;a href=&quot;#先把网分开&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;最小要分成三张逻辑网，物理上能分更好：&lt;/p&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;网络&lt;/th&gt;&lt;th&gt;谁在上面&lt;/th&gt;&lt;th&gt;默认策略&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;产线网&lt;/td&gt;&lt;td&gt;工控、工位电脑、必要的采集&lt;/td&gt;&lt;td&gt;只允许白名单流向，禁止随意出网&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;办公网&lt;/td&gt;&lt;td&gt;域内电脑、邮件、协作&lt;/td&gt;&lt;td&gt;走身份认证，按组访问&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;访客网&lt;/td&gt;&lt;td&gt;客户、外包、临时人员&lt;/td&gt;&lt;td&gt;隔离，上互联网，进不了产线和办公&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;「隔离」不是 VLAN 号不同就结束。要看三件事：三层能不能互访、无线会不会漂到错误 SSID、运维跳板会不会同时踩两张网。跳板必须受控，不能变成产线网的后门。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;终端准入，而不是信任插口&lt;a href=&quot;#终端准入而不是信任插口&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;产线最常见的口子是「找个空闲网口插上」。应对是：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;只允许加入域、纳入 Configuration Manager 的电脑&lt;/strong&gt;进产线或办公有线&lt;/li&gt;
&lt;li&gt;未注册终端进隔离或直接拒绝&lt;/li&gt;
&lt;li&gt;存储介质、私接热点、个人电脑按客户要求禁用或登记&lt;/li&gt;
&lt;li&gt;无线走 802.1X / Portal，企业账号才关联有权限的 SSID&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;身份底座（AD、证书、RADIUS）在这里不是「IT 内部建设」，而是保密审计能看懂的控制点：人走账号，电脑走清单，网络认这两者。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;人的边界：门禁、监控、访客&lt;a href=&quot;#人的边界门禁监控访客&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;网络策略管的是包，管不了「人已经站在工位旁边」。需要安防系统补上：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;门禁权限最小化，产线区域与办公区域分权，外包和访客单独组&lt;/li&gt;
&lt;li&gt;视频监控覆盖出入口、产线通道和公共区域，权限、录像周期、异常告警要能拿出来给审计看&lt;/li&gt;
&lt;li&gt;访客网络单独 VLAN / SSID，默认只能上网，不能进产线网段，也不能扫到内部打印机和文件共享&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;办公区、公共区域的访问控制经常被当成「无线密码换一下」。在保密项目里，它和产线隔离是同一份答卷。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;审计看什么&lt;a href=&quot;#审计看什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;审计不太关心你用了哪家防火墙的哪条特性名字，关心的是：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;产线网和办公网之间有没有明确的允许列表&lt;/li&gt;
&lt;li&gt;离职和项目结束之后，账号、门禁、终端有没有关掉&lt;/li&gt;
&lt;li&gt;访客有没有单独的网络和停留记录&lt;/li&gt;
&lt;li&gt;变更有没有人审、日志留不留得住&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;所以日志要能对上人：防火墙会话、RADIUS 认证、AD 登录、门禁事件，至少要能在同一时间轴上对得起来。对不起来的隔离，审计会当成没做。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;和日常运维的关系&lt;a href=&quot;#和日常运维的关系&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这套东西一旦上线，就不能靠「熟悉现场的那个人记得」。策略变更走评审，Zabbix 看着关键链路和服务器，SCCM 看着终端是否还在清单里。保密不是一次施工，是之后每次开端口都要再问一遍：这条路是不是产线需要的。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>用 Astro + Firefly 搭这个站，以及 pnpm 装不上的真正原因</title><link>https://dr.cctv15.net/posts/building-this-site/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/building-this-site/</guid><description>选主题的过程、为什么最后选了 Firefly，以及国内装依赖时 npmmirror 会在大包上给你一个 302，把 pnpm 卡死。</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;一直想有个地方把自己做过的项目集中放出来，而不是散在几个 GitHub 仓库里。这周把它搭起来了。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;选型&lt;a href=&quot;#选型&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;候选了一圈，主要在这几个里挑：&lt;/p&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;方案&lt;/th&gt;&lt;th&gt;印象&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Hugo (PaperMod / Stack)&lt;/td&gt;&lt;td&gt;最快最稳，但改 Go template 很难受&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Next.js (tailwind-nextjs-starter-blog)&lt;/td&gt;&lt;td&gt;博客能力最强，但对纯展示站来说重了&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Astro (Fuwari / Firefly)&lt;/td&gt;&lt;td&gt;默认零 JS，组件化改起来最顺手&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;最后选 &lt;strong&gt;&lt;a href=&quot;https://github.com/CuteLeaf/Firefly&quot; target=&quot;_blank&quot;&gt;Firefly&lt;/a&gt;&lt;/strong&gt;，它是 Fuwari 的二次开发版，功能补得很全，而且更新非常勤。&lt;/p&gt;&lt;p&gt;选它主要看中两点：一是&lt;strong&gt;配置驱动&lt;/strong&gt;——绝大部分东西在 &lt;code&gt;src/config/&lt;/code&gt; 下改 TypeScript 文件就行，不用碰组件；二是它自带一个「书签导航」页，那个页面的数据结构（分组 + 卡片 + 图标 + 描述）&lt;strong&gt;正好就是一个项目展示页需要的形状&lt;/strong&gt;，我直接把它改造成了项目页，一行组件代码都没改。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;装依赖卡了半小时&lt;a href=&quot;#装依赖卡了半小时&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这部分值得单独说，因为国内大概率都会遇到。&lt;/p&gt;&lt;p&gt;我的 npm 源是 &lt;code&gt;registry.npmmirror.com&lt;/code&gt;，平时很好用。但 &lt;code&gt;pnpm install&lt;/code&gt; 跑了二十多分钟，1135 个包里有 19 个死活装不上，报的都是同一个错：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[WARN] GET https://registry.npmmirror.com/typescript/-/typescript-6.0.3.tgz error (23)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[WARN] GET https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz error (23)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[WARN] GET https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz error (23)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;✗ Lockfile failed supply-chain policy check&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;[ERR_PNPM_BROKEN_METADATA_JSON] The operation was aborted due to timeout&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;注意失败的&lt;strong&gt;全是大包&lt;/strong&gt;：typescript、sharp、esbuild、wrangler、workerd、biome、pagefind、lightningcss。小包一个没出问题。&lt;/p&gt;&lt;p&gt;直接 curl 一下就看明白了：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-o&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/dev/null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-w&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;%{http_code} %{speed_download}\n&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;https://registry.npmmirror.com/typescript/-/typescript-6.0.3.tgz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 302, 55 B/s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-o&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/dev/null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-w&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;%{http_code} %{speed_download}\n&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 200, 786029 B/s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;npmmirror 对超过一定体积的 tarball 会返回 302 跳到它自己的 CDN，而这个跳转在我这里跟不动。&lt;/strong&gt; pnpm 重试几轮之后连元数据缓存都写坏了，报出一个和真实原因完全无关的 &lt;code&gt;BROKEN_METADATA_JSON&lt;/code&gt;。&lt;/p&gt;&lt;p&gt;解决办法很简单，这一次装换直连官方源：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--registry=https://registry.npmjs.org&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;40 秒装完。之前二十多分钟已经把 1116 个小包缓存进 store 了，换源之后只需要补那 19 个。&lt;/p&gt;&lt;p&gt;顺带一提，克隆仓库本身也慢——Firefly 仓库带历史有 130MB。直接下 tarball 只有 19MB：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-L&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-o&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;firefly.tar.gz&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;https://github.com/CuteLeaf/Firefly/archive/refs/heads/master.tar.gz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;改了什么&lt;a href=&quot;#改了什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;关掉了主题自带的追番、VNDB、AnimeList、相册、友链、留言、打赏页，只留博客 + 项目 + 关于&lt;/li&gt;
&lt;li&gt;把「书签导航」改造成项目页，导航栏提到顶级&lt;/li&gt;
&lt;li&gt;换掉横幅文案、logo、站点信息&lt;/li&gt;
&lt;li&gt;把主题默认引用的作者 CDN 背景视频去掉了——那是别人的带宽&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;还没做的&lt;a href=&quot;#还没做的&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt; 换成履历用的头像和机房横幅&lt;/li&gt;
&lt;li&gt; 把站点改成简历的项目附录，补上企业信息化案例&lt;/li&gt;
&lt;li&gt; 补每个项目的封面图&lt;/li&gt;
&lt;li&gt; 部署到 Cloudflare Pages&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;</content:encoded></item><item><title>用 Rust 写一套直播平台：推流、鉴权、回放，也能当在线教育用</title><link>https://dr.cctv15.net/posts/live-streaming-platform/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/live-streaming-platform/</guid><description>面向个人、私域和小团队的自建直播平台。RTMP 推流、HLS/FLV 拉流、房间权限、录制回放、实时弹幕——把这几样凑齐，它就不只是直播，也是一套能用的在线教育平台。</description><pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这套东西的出发点很朴素：&lt;strong&gt;个人、私域社群和小团队想自己搞直播，现成的选择并不好。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;商业直播云按流量计费，做个几十人的内部培训也要走一遍开通流程；开源方案要么只是个媒体服务器（推流拉流之外什么都没有），要么整套太重，为了一个几十人的场景要部署一堆东西。&lt;/p&gt;
&lt;p&gt;所以自己写了一套，用 Rust。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;做了什么&lt;a href=&quot;#做了什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;四块，凑齐了才算一个能用的平台：&lt;/p&gt;&lt;section&gt;&lt;h3&gt;1. RTMP 推流 + HLS / FLV 拉流&lt;a href=&quot;#1-rtmp-推流--hls--flv-拉流&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;最经典也最稳的一条链路：主播端用 OBS 推 RTMP 上来，服务端转成 HLS 和 HTTP-FLV 两种格式分发。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;为什么两种都要&lt;/strong&gt;：HLS 兼容性最好、能过 CDN，但天生有几秒到十几秒延迟（切片决定的）；HTTP-FLV 延迟能压到一两秒，代价是要浏览器端配合。&lt;strong&gt;让观众按场景选，比强行统一成一种更实用&lt;/strong&gt;——看回放和大规模分发走 HLS，需要互动的走 FLV。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 房间 / 频道与权限控制&lt;a href=&quot;#2-房间--频道与权限控制&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;不是”谁拿到地址谁就能看”。系统里有房间的概念，每个房间有：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;推流密钥&lt;/strong&gt;——没有密钥推不上来，防止别人占用你的频道&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;观看鉴权&lt;/strong&gt;——房间可以是公开的，也可以要求登录、要求在白名单里&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;角色区分&lt;/strong&gt;——主播、管理员、普通观众的权限不一样&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;这一块是它能当教育平台用的关键。&lt;/strong&gt; 公开直播不需要鉴权，但”只有报名的学员能进这堂课”就必须有。没有权限模型的直播系统，做不了教育。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 录制与回放&lt;a href=&quot;#3-录制与回放&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;直播的同时落存档，结束后自动生成可回看的录像。&lt;/p&gt;&lt;p&gt;对教育场景来说这几乎是刚需——&lt;strong&gt;上课的人里总有一部分当时来不了&lt;/strong&gt;。而且录播内容本身会沉淀成资产，一门课录一次能反复用。&lt;/p&gt;&lt;p&gt;工程上要注意的是录制不能拖累直播：转码和写盘走独立的任务，即使存储慢了或者满了，也不能让正在看的人卡住。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4. 聊天 / 弹幕与实时互动&lt;a href=&quot;#4-聊天--弹幕与实时互动&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;WebSocket 长连接做实时消息。直播场景是弹幕，教育场景就是&lt;strong&gt;提问和答疑&lt;/strong&gt;——形式一样，用途不同。&lt;/p&gt;&lt;p&gt;消息要和房间权限打通：能看这个房间的人才能收到消息，能发言的人才能发。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;为什么用 Rust&lt;a href=&quot;#为什么用-rust&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;直播服务端的特点是&lt;strong&gt;长连接多、并发高、单条消息小、要一直跑着不能崩&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;Rust 在这里的好处很直接：没有 GC 停顿，长时间跑内存占用平稳；类型系统和所有权模型逼着你在编译期就把并发和生命周期的问题处理掉，而不是等到线上半夜连接泄漏。&lt;/p&gt;&lt;p&gt;代价是开发速度慢，尤其是异步那套刚开始很折磨人。但&lt;strong&gt;这类”部署上去就要长期无人值守”的服务，我认为值得&lt;/strong&gt;——运维本职的经验告诉我，半夜爬起来重启服务的成本远高于开发时多花的那几天。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;当教育平台用，缺什么&lt;a href=&quot;#当教育平台用缺什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;坦白说，它现在是个&lt;strong&gt;直播平台&lt;/strong&gt;，不是完整的教育系统。直播 + 权限 + 回放 + 互动这四样是在线教育的技术底座，但一个真正的教育平台还需要课程编排、报名与订单、作业与测验、学习进度追踪。&lt;/p&gt;&lt;p&gt;不过对很多小团队来说，够用了——&lt;strong&gt;内部培训、社群课程、小规模教学，需要的恰恰就是”能开课、能控制谁进来、能回看、能提问”这四件事。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;和本职的关系&lt;a href=&quot;#和本职的关系&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;我做网络和信息化交付十几年，很清楚音视频这条链路上哪些地方会出问题：带宽估算、CDN 回源、丢包重传、码率自适应。写这套东西的时候，判断”这里该不该加一层缓存&quot;&quot;这个延迟指标现实不现实”，靠的还是那些经验。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;反过来它也补了我一块&lt;/strong&gt;：以前做 IPTV、做视频监控联网，我是甲方或者集成方，用的是别人的平台；自己从头写一遍之后，再去看厂商方案，能看出哪些是真难点、哪些只是包装。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>实时多人对战服务端：把规则层和网络层彻底拆开</title><link>https://dr.cctv15.net/posts/realtime-game-server/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/realtime-game-server/</guid><description>一个四人实时对局平台的服务端设计。核心决定只有一个——规则引擎不认识 socket，于是测试、AI 和断线重连全都变简单了。</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这是我自己写完并部署上线的一个&lt;strong&gt;四人实时对局平台&lt;/strong&gt;：真人房、AI 补位、房间邀请，H5 和 Android 包都出了，跑在自己的服务器上。&lt;/p&gt;
&lt;p&gt;选这个题目练手是有原因的——它同时具备&lt;strong&gt;强规则&lt;/strong&gt;、&lt;strong&gt;多人实时&lt;/strong&gt;、&lt;strong&gt;状态必须绝对一致&lt;/strong&gt;三个特征。任何一处判断写歪，四个客户端立刻就会吵起来。做完一遍，实时服务端该踩的坑基本踩了一轮。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;一条核心设计决定&lt;a href=&quot;#一条核心设计决定&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;整个项目只有一个决定是真正重要的：&lt;strong&gt;规则引擎和网络层彻底分开&lt;/strong&gt;。&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;server/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;src/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;core/      # 纯函数式的规则与对局状态机，不认识 socket&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;server/    # HTTP + Socket.IO，只负责收发和广播&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;test/        # 直接对 core 做单元测试，不起服务&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;core&lt;/code&gt; 里没有任何网络代码，它就是一个 &lt;code&gt;(状态, 动作) =&amp;gt; 新状态&lt;/code&gt; 的状态机。带来三个直接好处：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;测规则不用起服务器。&lt;/strong&gt; 单元测试几秒跑完，不需要开四个浏览器手动打一局。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;AI 和真人走完全同一条代码路径。&lt;/strong&gt; AI 就是一个「读状态、返回动作」的函数，不是特殊分支。这意味着 AI 能触发的 bug 真人也能触发，反之亦然——不会出现”只有 AI 在的时候才出问题”这种最难查的情况。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;换传输层不用动业务。&lt;/strong&gt; 以后要换成原生 WebSocket 或者 KCP，&lt;code&gt;core&lt;/code&gt; 一行都不用改。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;服务端权威，客户端只负责画&lt;a href=&quot;#服务端权威客户端只负责画&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;客户端不重写任何规则。玩家操作发上去，&lt;strong&gt;所有判定以服务端为准&lt;/strong&gt;，客户端只做渲染和输入。&lt;/p&gt;&lt;p&gt;这条在多人对战里没有商量余地。一旦让客户端参与判定，就要面对两个问题：客户端之间算出不同结果，以及有人改客户端。&lt;/p&gt;&lt;p&gt;代价是每个动作都要一个来回。所以协议设计上把「立刻能确定的反馈」（比如按钮按下的视觉响应）和「需要服务端确认的结果」分开处理，不让网络延迟表现成卡顿。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;动作优先级仲裁&lt;a href=&quot;#动作优先级仲裁&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;实时对局里最容易写错的地方，是&lt;strong&gt;同一个事件多个玩家同时有权响应&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;同一个动作，可能 A 玩家要执行操作甲、B 玩家要执行操作乙，而乙的优先级更高。这时不能谁的包先到就听谁的——那样结果取决于网络抖动，同一局重放两次会不一样。&lt;/p&gt;&lt;p&gt;正确做法是&lt;strong&gt;开一个短暂的响应窗口&lt;/strong&gt;，收齐（或超时）之后按固定优先级仲裁，再广播结果。还要处理同一优先级多人命中的情况。&lt;/p&gt;&lt;p&gt;这类逻辑全部在 &lt;code&gt;core&lt;/code&gt; 里，所以能用单元测试穷举各种组合，而不是靠线上撞。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;玩家中途离场&lt;a href=&quot;#玩家中途离场&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这个平台的规则里，有玩家达成目标后&lt;strong&gt;不是整局结束，而是该玩家离场、其余人继续&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;看起来是个小规则，实际上它否决了一个很自然的建模方式：不能假定「一局 = 固定四个人从头打到尾」。对局状态里必须显式维护「还在场的玩家」这个集合，所有轮转、判定、结算都基于它。&lt;/p&gt;&lt;p&gt;一开始没意识到这点，是后来重构掉的。&lt;strong&gt;能不能在建模阶段就识别出这种”看起来是规则、实际是结构”的需求，很影响后面返工的量。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;一次系统性缺陷排查&lt;a href=&quot;#一次系统性缺陷排查&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;上线跑了一段时间后我做过一轮完整的缺陷审计，整理出 20 条问题，修掉 17 条，剩下 3 条需要改数据结构，排进了后续迭代。&lt;/p&gt;&lt;p&gt;最大的收获不是修了多少 bug，而是印证了一件事：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;凡是能在 &lt;code&gt;core&lt;/code&gt; 层用单元测试复现的问题，修起来都很快；凡是只能靠”开四个浏览器手动打一局”复现的，都很慢。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;后来我把所有能下沉的判断全部往 &lt;code&gt;core&lt;/code&gt; 挪了。这条经验在别的项目上一样成立——&lt;strong&gt;可测试性不是测试的事，是架构的事。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;客户端与打包&lt;a href=&quot;#客户端与打包&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;客户端用 Cocos Creator + TypeScript，一套工程同时出 H5 和 Android。协议完全复用服务端已有的定义。&lt;/p&gt;&lt;p&gt;Android 出包这一步坑最集中，主要是 Gradle 与 NDK 的版本匹配，以及资源压缩后的加载路径问题。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;部署&lt;a href=&quot;#部署&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;服务端直接推到自己的服务器，不走 CI。原因很实际：部署频率不高，而且有几个目录（玩家数据、房间快照）&lt;strong&gt;绝对不能被覆盖&lt;/strong&gt;，走自动化脚本反而容易手滑。涉及数据的变更必须先停服。&lt;/p&gt;&lt;p&gt;这算是本职工作带过来的习惯——&lt;strong&gt;部署方案要匹配变更频率和出错代价，不是越自动化越好。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>云资源自助交付平台：把「申请一台机器」做成不用找人的事</title><link>https://dr.cctv15.net/posts/cloud-provisioning-platform/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/cloud-provisioning-platform/</guid><description>对接 GCP / AWS API 做计算实例的自动开通、回收与生命周期管理，用户在自助控制台就能开关机、重装、重置凭据。做这套的动机来自运维本职——重复劳动应该被消灭。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;做这套东西的动机很直接：&lt;strong&gt;「帮我开台机器」这件事，不应该需要找人。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在园区和企业 IT 里，申请一台测试机、临时环境、演示环境，流程通常是发消息给运维 → 运维手工开 → 记在某个表格里 → 用完没人回收 → 三个月后发现一堆僵尸实例在烧钱。这套平台就是把这条链路自动化掉。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;做了什么&lt;a href=&quot;#做了什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;用户提交申请后，系统&lt;strong&gt;自动调用云厂商 API 创建实例&lt;/strong&gt;，配置完成后把访问信息交付给申请人。之后用户在自助控制台里就能自己完成日常操作：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;开机 / 关机 / 重启&lt;/li&gt;
&lt;li&gt;重装系统（重建实例并保留标识）&lt;/li&gt;
&lt;li&gt;重置访问凭据&lt;/li&gt;
&lt;li&gt;查看配额与到期时间&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;另有一套&lt;strong&gt;库存池模式&lt;/strong&gt;：把已有的存量机器提前录入后台调优好，申请到来时从池子里分配一台，而不是每次都新建。适合那些开通慢、或者需要预先做过环境准备的场景。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;技术上的几个点&lt;a href=&quot;#技术上的几个点&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;云厂商 API 的差异要吃在适配层里&lt;a href=&quot;#云厂商-api-的差异要吃在适配层里&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;GCP 和 AWS 在实例生命周期上的模型不一样——创建是同步还是异步、状态机有哪些中间态、删除后资源多久真正释放、镜像和磁盘怎么关联。&lt;/p&gt;&lt;p&gt;所以不能让业务代码直接调 SDK。中间必须有一层适配，把两家（以后可能更多家）收敛成统一的动作集合：&lt;code&gt;create / start / stop / rebuild / destroy / status&lt;/code&gt;。业务层只认这套动作。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;异步操作必须能对账&lt;a href=&quot;#异步操作必须能对账&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;调云 API 创建实例是异步的：接口返回成功只代表”请求已受理”，机器可能几十秒后才真正 running，也可能失败。&lt;/p&gt;&lt;p&gt;所以每个操作都要有：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本地状态机&lt;/strong&gt;记录”我以为它在什么状态”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轮询或回调&lt;/strong&gt;去核对”它实际在什么状态”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对账任务&lt;/strong&gt;处理两者不一致的情况&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;不做对账的自动化平台，跑一段时间之后本地记录和云上实际情况一定会漂移。这和支付系统必须有查单兜底是同一个道理——&lt;strong&gt;任何跨系统的异步操作，都不能只依赖对方的成功返回。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;凭据不能明文躺着&lt;a href=&quot;#凭据不能明文躺着&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;访问凭据的生成、交付、重置全流程都不能落明文日志。重置操作要走幂等，避免用户连点两次导致机器被改成第二次的密码但界面显示第一次的。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;幂等和防重复&lt;a href=&quot;#幂等和防重复&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;「创建实例」这个动作被重复提交的代价是真金白银。所以请求要带幂等键，重复提交返回同一个结果，而不是开出两台机器。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;技术栈&lt;a href=&quot;#技术栈&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;TypeScript monorepo，前后端同仓；Docker Compose 部署，不同环境的差异显式写在各自的 compose 文件里，而不是靠某个人记得改哪个环境变量。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;为什么一个做网络的人要写这个&lt;a href=&quot;#为什么一个做网络的人要写这个&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;因为&lt;strong&gt;运维本职里最消耗人的，就是这种”每次都一样、但每次都要人做一遍”的事&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;我做了十几年信息化交付，很清楚哪些环节在浪费时间：申请要等审批、开通要等运维、回收永远没人管。这套平台的每一个功能，对应的都是我自己被这些流程卡过的一次经历。&lt;/p&gt;&lt;p&gt;能自己把它写出来，意味着我不用等着别人来解决这类问题——这也是我一直在补开发能力的原因。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>订阅制服务的用量计量和三通道支付</title><link>https://dr.cctv15.net/posts/subscription-billing-system/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/subscription-billing-system/</guid><description>一套跑在 GCP 上的订阅计费：支付宝 / PayPal / USDT 三条通道，重构了原实现里用量统计对不上账的部分。只写计量和通道边界，不写业务名和域名。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;订阅服务看起来是「按月扣一次钱」，真正难的是&lt;strong&gt;用量&lt;/strong&gt;和&lt;strong&gt;通道&lt;/strong&gt;两件事叠在一起：用户用了多少要能说清楚，钱从三条完全不同的通道进来还要对得上同一笔订单。&lt;/p&gt;
&lt;p&gt;这套系统跑在 GCP 上，Laravel + Docker。业务形态不在这里展开，只写计费层怎么拆。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;用量为什么容易错&lt;a href=&quot;#用量为什么容易错&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;原实现把「发生了一次使用」和「账上该记一笔」写在同一条请求路径里。于是会出现：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;重试一次，用量加两次&lt;/li&gt;
&lt;li&gt;通道回调晚到，账期已经切到下个月&lt;/li&gt;
&lt;li&gt;统计用的是缓存里的近似值，对账用的是数据库，两套数永远差一截&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;我把它拆开：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;事件&lt;/strong&gt;：系统里真实发生的使用，只追加，不改历史&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计量&lt;/strong&gt;：按账期把事件聚合成用量，可重算&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;账单&lt;/strong&gt;：计量结果生成应付，和支付通道无关&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支付&lt;/strong&gt;：账单去找通道，通道只认识金额和单号&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;用量对不上时，重算计量即可，不必去改支付流水。支付对不上时，查通道，不必去改事件表。这是从 Jeepay 那条通道经验里带过来的同一条原则：&lt;strong&gt;账本和通道不要写在一个 if 里&lt;/strong&gt;。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;三条通道&lt;a href=&quot;#三条通道&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;支付宝、PayPal、USDT 的对账语言不一样：一个是商户订单号，一个是 Capture，一个是链上确认。对上层账单只暴露「待支付 / 已支付 / 失败 / 关闭」。&lt;/p&gt;&lt;p&gt;USDT 尤其不能只信一次通知。链上确认数、重复支付、少付，都要当成一等公民，而不是「先入账再人工改」。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;部署&lt;a href=&quot;#部署&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Docker Compose 分环境。计量任务和 Web 进程分开跑，避免请求高峰把账期聚合挤掉。密钥和回调地址按环境隔离，文章里不列。&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;业务名、域名、节点和商户号不在公开材料里出现。这篇只说明计费为什么要分层。&lt;/p&gt;&lt;/blockquote&gt;&lt;/section&gt;</content:encoded></item><item><title>给 Jeepay 加一条东南亚支付通道</title><link>https://dr.cctv15.net/posts/jeepay-aba-channel/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/jeepay-aba-channel/</guid><description>Jeepay 是国内比较成熟的开源聚合支付系统，但它内置的通道全是国内的。这篇记录我怎么在不动核心的前提下，给它接一条 ABA Pay。</description><pubDate>Mon, 10 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/jeequan/jeepay&quot; target=&quot;_blank&quot;&gt;Jeepay&lt;/a&gt; 是一套面向互联网企业的开源支付系统，支持普通商户、服务商模式和多应用接入，Java + Spring Boot + Vue 的经典栈。它的通道抽象做得不错，但内置实现全是国内的——微信、支付宝、云闪付。&lt;/p&gt;
&lt;p&gt;我需要的是东南亚的 &lt;strong&gt;ABA Pay&lt;/strong&gt;，所以得自己接一条。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;先想清楚：改哪里，不改哪里&lt;a href=&quot;#先想清楚改哪里不改哪里&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;二开开源项目最容易犯的错，是图省事直接在核心流程里 &lt;code&gt;if (channel == &quot;ABA&quot;)&lt;/code&gt;。这么干第一次很快，但上游一发新版本你就再也合不回去了。&lt;/p&gt;&lt;p&gt;所以第一步是把边界划清楚：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;不动&lt;/strong&gt;：订单状态机、商户/应用体系、对账主流程、管理后台框架&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;只加&lt;/strong&gt;：一个新的通道实现，塞进 Jeepay 已有的通道 SPI 里&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Jeepay 的支付通道是按「一个通道 = 一组实现类」组织的，只要按它的接口把该实现的实现了，上层完全感知不到你是新加的。这就是它抽象做得好的地方。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;要实现的三件事&lt;a href=&quot;#要实现的三件事&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;一条支付通道能跑通，本质上只有三件事：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1. 下单&lt;/strong&gt; — 把 Jeepay 的统一订单参数翻译成渠道要的格式，调渠道接口，拿回一个可以给用户扫的二维码或跳转链接。这一步的难点通常在签名算法，每家都不一样。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 异步回调&lt;/strong&gt; — 渠道支付成功后回调你的服务器。这里有三个点必须做对：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;验签&lt;/strong&gt;：不验签的回调等于把订单状态接口裸奔在公网上&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;幂等&lt;/strong&gt;：渠道会重复推送，同一笔订单收到两次成功通知不能加两次钱&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;金额校验&lt;/strong&gt;：回调里的金额必须和本地订单金额一致才算数&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;3. 查单 / 对账&lt;/strong&gt; — 回调不是可靠的（网络抖动、你的服务重启都可能丢）。所以必须有一条主动查单的兜底路径，以及日终对账。&lt;strong&gt;只依赖回调的支付系统，迟早会丢单。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;关于「测试环境」&lt;a href=&quot;#关于测试环境&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;支付这块最麻烦的不是写代码，是&lt;strong&gt;没法随便测&lt;/strong&gt;。渠道的沙箱环境往往和生产行为不一致，而生产环境每测一笔都是真金白银。&lt;/p&gt;&lt;p&gt;我的做法是在通道实现和真实渠道之间放一层 bridge，本地开发时 bridge 指向一个可以手动构造各种回调（成功、失败、重复推送、金额不符）的桩服务。这样上面那三个必须做对的点，全都能在本地覆盖到。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;部署&lt;a href=&quot;#部署&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Docker Compose 起。仓库里维护了几套 compose 文件对应不同环境，这样本地、测试、生产之间的差异是显式写在文件里的，而不是靠某个人记得改哪个环境变量。&lt;/p&gt;&lt;hr /&gt;&lt;blockquote&gt;&lt;p&gt;支付相关的具体参数、密钥配置和渠道文档细节这里不展开。这篇主要想说的是&lt;strong&gt;二开的边界怎么划&lt;/strong&gt;——这个思路换到任何一个成熟开源项目上都适用。&lt;/p&gt;&lt;/blockquote&gt;&lt;/section&gt;</content:encoded></item><item><title>从 SDH 到 PTN：在新疆铺了四年传输网</title><link>https://dr.cctv15.net/posts/carrier-transmission-network/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/carrier-transmission-network/</guid><description>电子政务网 127 处局端加 889 处远端、1174 处小学的教育四级网、六县 117 处涉密单位、10GE 环网。这四年干的是最基础的活，也是我后来所有网络判断的地基。</description><pubDate>Sat, 01 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;2012 到 2016 年，我在瑞斯康达做有线传输和数据通信工程师，跟着新疆的三家运营商铺网。四年里经手的开通验收大致是这些：&lt;/p&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;类别&lt;/th&gt;&lt;th&gt;规模&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;乌鲁木齐电子政务网&lt;/td&gt;&lt;td&gt;&lt;strong&gt;127 处局端 + 889 处远端&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;阿勒泰电子政务网二期&lt;/td&gt;&lt;td&gt;&lt;strong&gt;六县 117 处涉密单位&lt;/strong&gt;，PTN 分组自组网&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;教育四级网（喀什—阿图什）&lt;/td&gt;&lt;td&gt;&lt;strong&gt;1,174 处小学&lt;/strong&gt;，移动 PTN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;十三冬交警监控&lt;/td&gt;&lt;td&gt;&lt;strong&gt;高点 27 处 + 低点 34 处&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;昌吉华电热力监控&lt;/td&gt;&lt;td&gt;&lt;strong&gt;57 处点位&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;昌吉绿洲路派出所园区监控&lt;/td&gt;&lt;td&gt;&lt;strong&gt;48 处&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;传输环网&lt;/td&gt;&lt;td&gt;米东 10GE PTN 环、乌鲁木齐 SDH 2.5G 环与 10GE 分组接入环、阿勒泰 10G 自组网、昌吉 10GE PTN 接入环&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WLAN&lt;/td&gt;&lt;td&gt;轻工职院 110 台 POE + 锐捷 AP + 三层交换收敛对接 AC；医科大、农大、交通技校、天山学院等；招商银行&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;这些活现在看没什么”技术含量”——没有云、没有容器、没有自动化。但&lt;strong&gt;我后来做企业网、做 SD-WAN、做防火墙迁移时的很多判断，都是这四年攒下来的。&lt;/strong&gt;&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;一、站点数量决定一切&lt;a href=&quot;#一站点数量决定一切&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;127 处局端 + 889 处远端&lt;/code&gt;这种数字，和”一个机房里有 10 台设备”是两种完全不同的工程。&lt;/p&gt;&lt;p&gt;站点一多，几件事立刻变成主要矛盾：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;编址和命名必须先定死。&lt;/strong&gt; 889 个远端如果没有一套能从名字推出位置、层级、上联口的规则，第三个月就没人说得清哪台是哪台。这个习惯我一直带到现在——做企业网 VLAN 规划、做防火墙地址对象命名，第一件事都是先定命名规则，而不是先配设备。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;开通只是开始，验收才是工程。&lt;/strong&gt; 一处站点从加电到业务通，快的十分钟；但要拿到验收，得有配置备份、端口对照表、光功率记录、业务测试记录。&lt;strong&gt;几百个站点的资料，是靠模板和表格堆出来的，不是靠记性。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;批量意味着不能有例外。&lt;/strong&gt; 只要有一处”这个站情况特殊，手工改一下”，交接的时候就一定会漏。这条后来变成我做任何批量操作的原则：宁可花时间把例外收进配置项，也不留特殊处理。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;二、SDH 和 PTN 的分水岭&lt;a href=&quot;#二sdh-和-ptn-的分水岭&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;那几年正好赶上传输网从 SDH 往 PTN 迁的口子上，两种网都在跑。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;SDH&lt;/strong&gt; 是刚性管道：时隙固定、时延确定、保护倒换 50ms 以内。做语音、做专线、做对时延敏感的业务，它到今天都很难被取代。代价是带宽不能超卖，一条 2.5G 环就是 2.5G。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;PTN&lt;/strong&gt; 是分组承载：统计复用、带宽利用率高、天然适配以太业务。视频监控这类突发流量大、对丢包不敏感的业务，走 PTN 划算得多。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;选型不是选新旧，是选业务特性。&lt;/strong&gt; 十三冬交警监控走 PTN，是因为几十路视频突发大、时延容忍高；而涉密单位的电子政务网走分组自组网，看重的是隔离和可管，不是带宽峰值。&lt;/p&gt;&lt;p&gt;这套思路后来直接迁移到了 SD-WAN 上——&lt;strong&gt;专线和互联网混合接入，本质就是当年”哪些业务上 SDH、哪些上 PTN”的同一个问题&lt;/strong&gt;，只不过判据从时隙换成了链路质量探测。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;三、涉密单位的网，从那时候就得分开&lt;a href=&quot;#三涉密单位的网从那时候就得分开&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;阿勒泰那个项目，六县 117 处&lt;strong&gt;涉密单位&lt;/strong&gt;，用的是 PTN 分组自组网。&lt;/p&gt;&lt;p&gt;这类网的要求和普通政务外网不一样：物理链路要能说清楚走哪儿、逻辑上要和互联网彻底断开、每一处接入都要能追溯到具体单位和责任人。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;“隔离”在传输层是拓扑问题，不是配置问题。&lt;/strong&gt; 一条 ACL 写错可以改，一条光缆走错路由要重新施工。所以设计阶段就得把哪些站点归哪个环、环和环之间怎么互通、跨环流量走不走中心节点定清楚。&lt;/p&gt;&lt;p&gt;这个经验后来在两个地方复用了：做等保三级的电子政务外网边界建设，以及做涉密车间的网络合规化改造。&lt;strong&gt;载体从光缆变成了交换机和防火墙，但”先定拓扑边界，再谈策略”的顺序没变。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;四、高校 WLAN：第一次面对”用户”&lt;a href=&quot;#四高校-wlan第一次面对用户&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;轻工职院那个项目，110 台 POE 交换机带锐捷 AP，三层交换做业务收敛再对接 AC。&lt;/p&gt;&lt;p&gt;这是我第一次做&lt;strong&gt;面向大量真实用户&lt;/strong&gt;的网络。和政务网最大的区别是：政务网的终端是固定的、可控的；WLAN 的终端是学生的手机，型号五花八门，行为不可预测。&lt;/p&gt;&lt;p&gt;几个当时踩的坑，现在做企业 Wi-Fi 仍然要处理：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AP 密度和信道规划比 AP 数量重要&lt;/strong&gt;，堆 AP 只会互相干扰&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;收敛比要算清楚&lt;/strong&gt;，接入层堆满了但上联跑不动，用户体验一样差&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;认证要能查&lt;/strong&gt;，出问题时得能回答”这个人几点从哪台 AP 接入的”&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;后来在企业里做华为 AC 对接 NPS、Entra ID 和 Portal 认证，做的还是同一件事——只是把”能上网”提升成了”只有企业账号能上网，并且每一次接入都留痕”。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;五、这四年真正留下的东西&lt;a href=&quot;#五这四年真正留下的东西&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;如果只能总结一条：&lt;strong&gt;我对”网络”的理解是从物理层往上长的，不是从配置命令往下学的。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;知道一条链路的光功率余量还剩多少，知道环网倒换的时候业务会断多久，知道 889 个远端里坏一个该怎么定位——这些东西在后来每一次排障里都在起作用。很多网络问题在上层看是”业务偶尔卡一下”，往下捅到底往往是某一段链路、某一个端口的老问题。&lt;/p&gt;&lt;p&gt;现在我做的是身份、是 SD-WAN、是防火墙自动化，看起来离传输很远。但&lt;strong&gt;判断一个方案能不能落地，靠的还是当年趴在机柜前面数端口攒下来的那点直觉。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>GB/T 28181 视频前置接入：让摄像头进得来，又碰不到内网</title><link>https://dr.cctv15.net/posts/gb28181-video-frontend/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/gb28181-video-frontend/</guid><description>外部摄像头和执法头盔要把视频送进内网平台，但它们一步都不能踏进业务网段。DMZ 前置机 + 媒体强制中继 + 逐条防火墙工单，这是完整的落地方案。</description><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;需求一句话说得清：&lt;strong&gt;外部的摄像头、执法头盔要把实时视频送进内网的视频平台。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;难点也一句话说得清：&lt;strong&gt;这些设备在互联网、4G 和专线上，而内网平台在业务网段里，两者一步都不能直连。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;GB/T 28181 是国标的视频联网协议（SIP 信令 + RTP 媒体）。它解决”怎么互通”，不解决”怎么安全地互通”。后半截是网络工程师的活。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;拓扑&lt;a href=&quot;#拓扑&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;前端监控 / 执法头盔&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;互联网 / 4G / 专线&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;边界防火墙（ACL）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;前置机（DMZ）        ← SIP 信令 + RTP 媒体&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span&gt;视频接入网关          ← 级联 SIP + RTP&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;内网视频平台&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;中间那台 &lt;strong&gt;DMZ 前置机&lt;/strong&gt;是整个方案的核心。它的存在只为一件事：&lt;strong&gt;让两边永远不见面。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;三条隔离原则&lt;a href=&quot;#三条隔离原则&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这三条是不可协商的，其他所有配置都是为了保证它们成立：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;摄像头只能和前置机互通&lt;/strong&gt;——不能直达内网任何业务网段&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内网平台只能和前置机 / 网关互通&lt;/strong&gt;——不能直接去连摄像头&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;媒体必须经前置机中继，不能端到端直通&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;第三条最容易被忽略。有些实现为了省带宽会协商成设备与平台直接传 RTP——那样前面两条隔离就白做了，等于在防火墙上开了一条谁也说不清的路。宁可多一跳中继，也不能让码流绕过前置机。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;前置机的双重身份&lt;a href=&quot;#前置机的双重身份&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这台前置机在国标体系里同时扮演两个角色，这一点是整个方案最容易想错的地方：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;对前端设备（摄像头 / MCU）&lt;/strong&gt;，它是&lt;strong&gt;国标上级平台&lt;/strong&gt;——设备向它注册、向它推流&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对内网视频平台&lt;/strong&gt;，它是&lt;strong&gt;国标下级域&lt;/strong&gt;——它向平台注册、把流级联上去&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;于是媒体要做&lt;strong&gt;两段 RTP 中继&lt;/strong&gt;：设备 → 前置机是一段，前置机 → 平台是另一段，中间由前置机重新做 SDP 协商。这正是”不能端到端直通”在实现层面的样子——前置机不是透传的代理，它是两侧各自的对端。&lt;/p&gt;&lt;p&gt;搞不清这层关系，就会在两边的国标 ID、SIP 端口和媒体端口段上反复配错。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;单网卡还是双网卡&lt;a href=&quot;#单网卡还是双网卡&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;两套都做了方案，取舍如下：&lt;/p&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;单网卡（host 网络）&lt;/th&gt;&lt;th&gt;双网卡&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;部署&lt;/td&gt;&lt;td&gt;简单，一块网卡走 DMZ&lt;/td&gt;&lt;td&gt;eth0 对设备、eth1 对内网网关&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;隔离强度&lt;/td&gt;&lt;td&gt;靠防火墙 ACL 保证&lt;/td&gt;&lt;td&gt;物理链路天然分开&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;适用&lt;/td&gt;&lt;td&gt;成本敏感、边界防火墙可信&lt;/td&gt;&lt;td&gt;&lt;strong&gt;生产首选&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;生产上推荐双网卡：DMZ 侧和内网侧走不同物理口，即使 ACL 配错了，也不至于一条规则就把两张网连通。&lt;/p&gt;&lt;p&gt;网络一律静态配置，不上 DHCP——前置机的地址要写进防火墙工单和平台配置，不能变。方案阶段是按 Ubuntu / netplan 写的，实际落地的机器是 Anolis OS，改用 NetworkManager，配置方式不同但原则一样。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;端口：只开必需的，逐条写清楚&lt;a href=&quot;#端口只开必需的逐条写清楚&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;前置机跑 WVP + ZLMediaKit，Docker 部署用 &lt;code&gt;network_mode: host&lt;/code&gt;，让 SIP 和 RTP 端口直接监听，避免 NAT 端口映射把媒体协商搞乱（这是容器化跑 SIP 类应用最常见的坑）。&lt;/p&gt;







































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;方向&lt;/th&gt;&lt;th&gt;端口&lt;/th&gt;&lt;th&gt;用途&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;设备 → 前置机&lt;/td&gt;&lt;td&gt;24600 UDP/TCP&lt;/td&gt;&lt;td&gt;SIP 注册与信令&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;设备 → 前置机&lt;/td&gt;&lt;td&gt;24601-24624 UDP&lt;/td&gt;&lt;td&gt;实时音视频 RTP/RTCP&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;前置机 → 设备&lt;/td&gt;&lt;td&gt;5060 UDP/TCP&lt;/td&gt;&lt;td&gt;回呼 INVITE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;前置机 → 网关&lt;/td&gt;&lt;td&gt;5060 UDP/TCP&lt;/td&gt;&lt;td&gt;级联 SIP&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;前置机 → 网关&lt;/td&gt;&lt;td&gt;22000-22023 UDP&lt;/td&gt;&lt;td&gt;媒体送网关&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;运维网段 → 前置机&lt;/td&gt;&lt;td&gt;22 / 18080 / 8080 TCP&lt;/td&gt;&lt;td&gt;SSH 与管理界面，&lt;strong&gt;限源&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;媒体端口段的宽度直接决定并发路数。上面这套对应约 12 路并发；要扩容就把设备侧扩成 &lt;code&gt;24601-24700&lt;/code&gt;、网关侧扩成 &lt;code&gt;22000-22100&lt;/code&gt;，&lt;strong&gt;并同步更新防火墙工单&lt;/strong&gt;——不同步的话下次排障没人知道实际开了哪些口。&lt;/p&gt;&lt;p&gt;主机侧 ufw 默认拒绝入站，只放行上表的端口。管理口（WVP Web、ZLM API）绝不对全网开放。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;防火墙工单要写成可审计的样子&lt;a href=&quot;#防火墙工单要写成可审计的样子&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这类项目最后落到边界防火墙上，就是一张工单。写工单有两个原则：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;逐条写源、目的、协议、端口、动作、说明。&lt;/strong&gt; 不要图省事写 &lt;code&gt;any&lt;/code&gt;。工单里我专门加了一行：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;不要&lt;/strong&gt;开通 0-65535 any。&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;这不是废话——现场为了”先通了再说”开全端口，然后就永远没人敢关了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;要有明确的拒绝项。&lt;/strong&gt; 工单不能只写放行什么，还要写清楚禁止什么：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;摄像头 / 公网 不得直达内网业务网段&lt;/li&gt;
&lt;li&gt;内网业务终端 不得直达摄像头&lt;/li&gt;
&lt;li&gt;数据库 3306、Redis 6379 不对非本机开放&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;拒绝项是给后来人看的。半年后有人问”能不能让平台直接连摄像头”，工单上白纸黑字写着不行，就不用重新讨论一遍。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;现场环境比协议更难对付&lt;a href=&quot;#现场环境比协议更难对付&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;真实项目里，协议本身反而是最可控的部分。难的是现场给你什么条件：&lt;/p&gt;
























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;约束&lt;/th&gt;&lt;th&gt;影响&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;服务器无互联网&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;镜像只能离线导出、拷贝、导入，不能 &lt;code&gt;docker pull&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Anolis OS 8.8&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;RHEL 系但不是 CentOS，部分包源和文档对不上&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Docker 19.03（厂商定制版，不允许升级）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;很多新版 compose 语法不能用，只能按老版本写&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Compose v2.12.2 可用&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;唯一的好消息，编排还能正常做&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;服务栈是 &lt;strong&gt;WVP-PRO + ZLMediaKit + MySQL + Redis&lt;/strong&gt;，全部要在这台机器上离线跑起来。所有镜像先在有网的机器上 &lt;code&gt;docker save&lt;/code&gt;，拷进去再 &lt;code&gt;docker load&lt;/code&gt;，版本必须一次选对——&lt;strong&gt;进去之后没有第二次机会拉包。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;还有一个容易忽略的点：&lt;strong&gt;时间必须准。&lt;/strong&gt; SIP 鉴权对时间敏感，机器时钟偏了，注册就会莫名其妙失败，而报错信息不会告诉你是时间问题。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;后续：MCU 会议 SIP 中继&lt;a href=&quot;#后续mcu-会议-sip-中继&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;国标这套跑通之后，接着做的是 MCU 会议系统的 SIP 中继，要支持&lt;strong&gt;双向主叫&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;这一段没有继续用 WVP，而是换成 &lt;strong&gt;Kamailio + rtpengine&lt;/strong&gt;——因为需求从”视频监控联网”变成了”会议信令路由与媒体中继”，前者的国标栈在这里是多余的。选型跟着需求走，不跟着”上次用了什么”走。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;交付物&lt;a href=&quot;#交付物&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这个项目最后交付的不只是一台能跑的机器：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定稿方案&lt;/strong&gt;（拓扑、选型、单/双网卡对比、端口互通表）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置交付文档&lt;/strong&gt;（逐步骤，含 netplan、Docker Compose、WVP 配置样例）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;前置机完整配置手册&lt;/strong&gt;（从裸系统到服务可用；方案版基于 Ubuntu，现场版按 Anolis OS 调整）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防火墙开通工单&lt;/strong&gt;（可直接提交给网信 / 安全部门审批）&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;做集成项目十几年下来的经验是：&lt;strong&gt;方案能不能落地，一半取决于文档能不能让别人照着做。&lt;/strong&gt; 只有你自己能维护的系统，等于埋了个雷。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;这套东西能迁移到哪&lt;a href=&quot;#这套东西能迁移到哪&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;同一套思路适用于所有”外部设备要进内网”的场景：园区监控联网、门禁平台对接、工业采集设备上云。变的是协议和端口，不变的是&lt;strong&gt;前置机 + 强制中继 + 逐条 ACL + 明确拒绝项&lt;/strong&gt;这个骨架。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>整墙迁移：用 API 脚本把一台华为防火墙搬到奇安信</title><link>https://dr.cctv15.net/posts/firewall-migration-by-api/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/firewall-migration-by-api/</guid><description>42 个地址对象、77 条服务、31 条路由、12 条策略路由、19 条 DNAT、44 条安全策略，外加双 ISP 和 SSL VPN。手点要三天还容易漏，写脚本调 API 一晚上搬完，还顺手做了迁移后审计。</description><pubDate>Sat, 18 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;换防火墙这件事，配置量一上来就变成体力活：&lt;strong&gt;华为 USG6309E 上跑着的所有东西，要一条不漏地搬到新的奇安信 NGFW 上。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;清点了一下工作量：&lt;/p&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;类别&lt;/th&gt;&lt;th&gt;数量&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;地址对象&lt;/td&gt;&lt;td&gt;约 42 个&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;自定义服务&lt;/td&gt;&lt;td&gt;77 个&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;静态路由&lt;/td&gt;&lt;td&gt;31 条&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;策略路由 PBR&lt;/td&gt;&lt;td&gt;12 条&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;目的 NAT（DNAT）&lt;/td&gt;&lt;td&gt;19 条&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;源 NAT（SNAT）&lt;/td&gt;&lt;td&gt;4 条&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;安全策略&lt;/td&gt;&lt;td&gt;44 条&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SSL VPN 虚拟网关&lt;/td&gt;&lt;td&gt;2 个&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;外加双 ISP（电信 + 联通）和一条 SD-WAN 出口。&lt;/p&gt;
&lt;p&gt;在 Web 界面上手点，乐观估计两三天，而且&lt;strong&gt;一定会漏&lt;/strong&gt;——漏的还偏偏是平时没人用、季度末才跑一次的那条策略。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;决定：写脚本调 API&lt;a href=&quot;#决定写脚本调-api&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;奇安信的 Web 管理界面背后是一套 HTTP API。既然界面能做的事 API 都能做，那就不该用手点。&lt;/p&gt;&lt;p&gt;整个迁移拆成了几个独立脚本，每类对象一个：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;qax_login.py          # 登录、拿 token、维持会话&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;qax_migrate.py        # 地址对象、服务对象&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;qax_migrate_routes.py # 静态路由&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;qax_migrate_policy.py # 安全策略&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;qax_migrate_nat_sec.py# DNAT / SNAT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;qax_pbr_schedule.py   # 策略路由与时间对象&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;qax_full_audit.py     # 迁移后全量审计&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这么拆有个直接好处：&lt;strong&gt;每一类都能单独重跑。&lt;/strong&gt; 迁移不是一次成功的，是跑 → 看报错 → 改 → 重跑。如果写成一个大脚本，每次都要从头来。&lt;/p&gt;&lt;p&gt;数据源是从华为侧导出的配置（&lt;code&gt;display current-configuration&lt;/code&gt; 的各个分段），脚本负责把华为的语法翻译成奇安信 API 的 JSON。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;最花时间的不是搬，是对账&lt;a href=&quot;#最花时间的不是搬是对账&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;真正的难点是&lt;strong&gt;怎么确认搬完了、搬对了&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;所以写了 &lt;code&gt;qax_full_audit.py&lt;/code&gt;——它不做任何修改，只把新墙上的实际配置全量拉下来，逐项对照检查，输出一份审计报告：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;### 关键业务地址检查&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[OK]   telecom_ip: 183.x.x.x 在 ge7, type=static, zone=untrust&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[WARN] 183.x.x.x 类型为 static，SSL VPN 通常需要 float&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[OK]   unicom_ip:  202.x.x.x 在 ge5, type=static, zone=untrust&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[FAIL] 缺少关键地址 trust_ip=10.x.x.x&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;[OK] / [WARN] / [FAIL]&lt;/code&gt; 三级，跑完一眼就知道还差什么。&lt;/p&gt;&lt;p&gt;DNAT 另外单独出了一张 CSV 对照表，19 条逐条列出：名称、协议、公网 IP、公网端口、内网 IP、内网端口、入接口、状态。&lt;strong&gt;这张表是交付物&lt;/strong&gt;——之后谁来接手，看这张表就知道每条映射对应哪个业务（qms、mes、NAS、AI-server、FTP、回调接口……），而不是对着一堆端口号猜。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;踩到的坑&lt;a href=&quot;#踩到的坑&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;接口地址类型 float vs static。&lt;/strong&gt; SSL VPN 要求承载接口的地址类型是 &lt;code&gt;float&lt;/code&gt;，而迁移脚本按华为侧的静态配置写成了 &lt;code&gt;static&lt;/code&gt;，结果隧道死活建不起来。这种约束不在文档显眼处，是审计脚本的 &lt;code&gt;[WARN]&lt;/code&gt; 提示出来的——&lt;strong&gt;这就是写审计脚本的价值，它会告诉你”能通但不对”的地方。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;API 也有边界。&lt;/strong&gt; 证书上传接口 &lt;code&gt;/upload&lt;/code&gt; 一直返回 403，试了几种方式都不行。最后认了：SSL VPN 的服务器证书在 Web 界面上手动传，两分钟的事。&lt;/p&gt;&lt;p&gt;自动化不是目的。&lt;strong&gt;能自动的自动掉，剩下的老老实实手工做完并记录下来&lt;/strong&gt;，比死磕一个接口划算得多。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;管理口不能动。&lt;/strong&gt; 迁移全程 &lt;code&gt;ge1&lt;/code&gt; 管理口保持原样不改——这是唯一一条退路。改了它，一旦配置出错就只能去机房。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;双 ISP 与策略路由&lt;a href=&quot;#双-isp-与策略路由&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;新墙上电信、联通各一个 untrust 接口，各带一条默认路由；12 条 PBR 按源地址指定出接口，把不同网段、不同业务分流到不同运营商。SNAT 四条分别对应电信、联通、SD-WAN 和默认。&lt;/p&gt;&lt;p&gt;这套东西的正确性没法靠”能上网”验证——&lt;strong&gt;得逐条源地址去 traceroute 看走的是哪个口。&lt;/strong&gt; 审计脚本把 PBR 表和路由表一起打出来，比在 Web 界面上翻页对照快得多。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;SSL VPN 迁移&lt;a href=&quot;#ssl-vpn-迁移&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;老墙上两个虚拟网关：一个走电信口 1443 端口、network-extension 模式、地址池 &lt;code&gt;10.10.80.0/24&lt;/code&gt;，通到内网；另一个走联通口 9443、split 模式。角色分三种权限。&lt;/p&gt;&lt;p&gt;新墙上对应重建了地址池、本地用户和放行策略（VPN 客户端网段 → trust 区）。&lt;/p&gt;&lt;p&gt;VPN 这块的教训是：&lt;strong&gt;先确认接口地址类型，再建隧道。&lt;/strong&gt; 顺序反了就得把隧道删了重来。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;值不值&lt;a href=&quot;#值不值&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;从”决定写脚本”到”审计报告全绿”，比手点省了大概两天，但真正的收益不在这里：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可重复&lt;/strong&gt;：中途配置错了，改脚本重跑一遍就行，不用回忆刚才在界面上点了什么&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有据可查&lt;/strong&gt;：迁移日志是 JSONL 的，每条操作的请求和响应都留着&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;交付物是文档不是记忆&lt;/strong&gt;：审计报告 + DNAT 对照表 + 完整清单，接手的人不用来问我&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;做了这么多年网络，越来越觉得&lt;strong&gt;会写点代码对网络工程师的意义，不是转行去做开发，而是把这类”量大、重复、易漏”的活变成可重复执行的东西。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>在柬埔寨做 OTT：拿 IPTV 面板当后端，前端自己写 APK</title><link>https://dr.cctv15.net/posts/ott-iptv-platform/</link><guid isPermaLink="true">https://dr.cctv15.net/posts/ott-iptv-platform/</guid><description>柬埔寨数字电视的 OTT 业务。后端用成熟的 IPTV 管理面板做频道、转码和用户订阅，前端自研 Android APK。这篇讲为什么后端不自研、前端不能不自研。</description><pubDate>Wed, 10 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在柬埔寨数字电视（CDTV）做 IT 技术经理那段时间，主线业务之一是 OTT——把电视频道送到手机和机顶盒上。&lt;/p&gt;
&lt;p&gt;做法是：&lt;strong&gt;后端用成熟的 IPTV 管理面板，前端自己写 Android APK。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个组合不是随便定的，两边的取舍正好相反。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;后端为什么不自研&lt;a href=&quot;#后端为什么不自研&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;成熟的 IPTV 管理面板，把 OTT 后端该有的东西基本都有了：&lt;/p&gt;




























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;能力&lt;/th&gt;&lt;th&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;频道管理&lt;/td&gt;&lt;td&gt;直播源接入、频道分组、EPG 节目单&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;转码&lt;/td&gt;&lt;td&gt;一路源转多个码率档位，适配不同网络&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;用户与订阅&lt;/td&gt;&lt;td&gt;账号、套餐、有效期、并发数限制&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;分发与负载&lt;/td&gt;&lt;td&gt;多台边缘节点负载分担&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;统计&lt;/td&gt;&lt;td&gt;在线人数、观看时长、频道热度&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;这些没有一样是有创新空间的，全是”行业里早就定型”的功能。&lt;strong&gt;自研的唯一结果是用两年时间做一个更差的版本。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;真正需要投入的是&lt;strong&gt;运维&lt;/strong&gt;：直播源不稳定要能自动切备源、转码机 CPU 打满要能扩容、边缘节点挂了要能摘掉。这些是配置和监控的活，不是写代码的活。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;前端为什么必须自研&lt;a href=&quot;#前端为什么必须自研&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;面板自带的播放页可以用，但&lt;strong&gt;不能拿来当产品&lt;/strong&gt;。原因有三个：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1. 品牌是电视台的核心资产。&lt;/strong&gt; CDTV 是有牌照的持牌电视机构，APP 上打谁的 logo、用什么配色、频道怎么排序，这些不能交给一个通用面板决定。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 本地化不是翻译。&lt;/strong&gt; 柬埔寨用户的使用习惯、高棉语字体渲染、当地支付方式，通用模板全都覆盖不到。高棉文的字形和换行规则跟拉丁文差别很大，字体没选对整个界面就是乱的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. 电视端和手机端是两种交互。&lt;/strong&gt; 手机是触摸，机顶盒和电视是遥控器——焦点怎么移动、返回键怎么处理、大屏上字号多大能看清，这些必须自己控制。&lt;/p&gt;&lt;p&gt;所以前端是自己做的 Android APK，通过面板的接口拿频道列表、鉴权和播放地址，播放器和整个交互层自己实现。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;踩过的地方&lt;a href=&quot;#踩过的地方&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;转码档位不能贪多。&lt;/strong&gt; 每多一档就多一份 CPU 和存储。柬埔寨的移动网络质量参差，一开始想多切几档覆盖全，结果转码机先扛不住。后来收敛到三档，按实际用户网络分布定，够用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;直播源比想象中脆弱。&lt;/strong&gt; 卫星接收、编码器、上联链路，任何一环抖动都会表现成”用户说卡”。所以必须有源侧监控——不能等用户投诉才知道某个频道已经黑屏半小时了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;并发数限制要真的执行。&lt;/strong&gt; 一个账号被全家甚至全楼共用，是这类业务的常态。面板支持并发限制，但要结合实际调——卡太死用户骂，放太松收入漏。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;APK 分发是个独立问题。&lt;/strong&gt; 不是所有用户都能上 Google Play。要准备好官网直接下载 APK、以及版本升级提示的通道。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;同期的另外一条线&lt;a href=&quot;#同期的另外一条线&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;OTT 之外还维护着一带一路的 DTMB 平台（地面数字电视），以及和柬埔寨新闻部合建的机房——UPS、发射机、服务器、卫星接收器、转码器、冷循环系统。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;OTT 和 DTMB 是同一批内容的两种送达方式&lt;/strong&gt;：一个走互联网，一个走地面广播。同时管这两条线，好处是对”内容从演播室到用户屏幕”的完整链路有了体感——哪一段是带宽问题、哪一段是编码问题、哪一段是设备问题，判断起来快很多。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;这段经历给我留下的&lt;a href=&quot;#这段经历给我留下的&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;在成熟领域，“用现成的”往往是更专业的判断，而不是偷懒。&lt;/strong&gt; 关键是分清哪部分是通用能力（后端面板），哪部分是你的差异化（品牌、本地化、终端体验）——前者用现成的成熟方案，后者必须自己攥在手里。&lt;/p&gt;&lt;p&gt;这个判断方法后来一直在用：在 Jeepay 上接支付通道是同一个思路，在 Xboard 上做二次开发也是。&lt;strong&gt;不动核心、只加自己要的能力，上游升级还能跟。&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;</content:encoded></item></channel></rss>