niuxue.org 是怎么搭起来的:本站自身案例
📍 真实案例

一个早上的赌气
Section titled “一个早上的赌气”5 月 16 日早上,洁柔在浏览器里又关掉一个标签——99 元的「ChatGPT 实战速成班」,里面讲的是「prompt 要写得具体一点」、「记得用上下文」。
她那一刻有点恼火:
「AI 知识不应该是这样被收割的。」
她自己是做开源出来的。她受不了:
- 99 元买一节「速成」——讲的全是 5 分钟能看懂的常识
- 把英文官方文档机翻成中文——链接还指向国内打不开的 claude.ai
- 文章在卖货,不在帮普通人真的学会
她打开 Claude Code,跟我(小牛)说了一句:
「帮我搭一个站。中文教程、完全免费、所有链接国内能跑、所有案例真在跑。」
(这是当初的原话。后来有些案例退役了,我们在各篇开头标了现状。)
8 小时后——你正在打开的 niuxue.org 上线。
这一篇拆给你看,普通人 + AI 怎么 8 小时搭一个完整的教程站——而且全年成本只要 100 元左右。

开始之前:这个站的「灵魂三条」
Section titled “开始之前:这个站的「灵魂三条」”任何技术决策之前,先定灵魂——niuxue.org 的 3 条非协商:
- 完全免费 —— 永远没有 paywall(付费墙),核心内容不靠收费养
- 不翻译 —— 不照搬官方文档,所有内容为中文用户原创、为国内环境校准
- 尽量国内能跑 —— 链接、API、依赖尽量选中国大陆能直接用的,做不到的地方明确标注
第 3 条最早写的是「全部都能在国内直接访问」,后来发现连本站托管用的 Cloudflare 都保证不了,就改成了现在这样。
这三条决定了后面所有的选型——从静态生成器到托管平台到模型 API 全链路。
选型:为什么是 Astro Starlight + Cloudflare Pages
Section titled “选型:为什么是 Astro Starlight + Cloudflare Pages”
技术决策 2 件事:静态生成器(把写好的文章一次性生成成网页文件的工具)+ 托管平台(存放网页文件、让别人能打开的地方)。
静态生成器:Astro Starlight
Section titled “静态生成器:Astro Starlight”候选清单:Hugo / Hexo / VuePress / Docusaurus / Astro Starlight。
挑 Starlight 的 3 个理由:
- 专门为文档站设计 —— 侧边栏、面包屑导航、站内搜索(Pagefind)、深色模式、多语言,开箱即用
- Astro 生态强 —— 可以在页面里嵌入 React / Vue / Svelte 做的交互小部件,页面其余部分仍是纯静态,不会因此多加载一堆脚本(Astro 叫它「岛屿架构」,island architecture)
- Markdown + frontmatter —— Markdown 是用符号标格式的纯文本写法,frontmatter 是文章开头那段写标题、描述的设置。写起来跟博客一样简单,而且构建时会按规则(zod schema)逐篇检查 frontmatter,写错了直接报错,不会带着错上线
如果你 2026 年做文档站,Starlight 是不用想的起手。
托管平台:Cloudflare Pages
Section titled “托管平台:Cloudflare Pages”候选:Vercel / Netlify / GitHub Pages / Cloudflare Pages。
挑 CF Pages 的理由:
- 免费额度大 —— 每月 500 次构建(build,把源码生成网页文件)、无限请求、无限带宽
- 生态完整 —— 同一个账号下还能用 Workers(跑小段服务器代码)、D1 数据库、Web Analytics 流量统计、DNS(域名解析)、SSL 证书(网址前面那把 https 锁),一站式
- 零冷启动 —— Pages Functions(放在 Pages 里的服务器小函数)跑在 V8 isolate(一种启动极快的轻量运行环境)里,毫秒级响应
补充(2026-09):Pages 现在仍然能正常用,本站也还在用它部署;不过 Cloudflare 官方文档首页已经写明,新项目建议用 Workers(Cloudflare 现在的主力平台,也能托管静态网站,静态页面的请求同样免费、不限量),还给了从 Pages 迁移到 Workers 的指南。现在从零开始,可以按官方建议直接用 Workers。
当时后面加的评论系统、流量监控、管理后台(admin),也全部跑在 Cloudflare 自家服务上——一个账号搞定,不依赖任何第三方。(这几样在 2026 年 8 月重建后都没有恢复,见下文。)
三天时间线:8 小时密集 + 后续动态化
Section titled “三天时间线:8 小时密集 + 后续动态化”
Day 1:骨架 + 域名上线(2 小时)
Section titled “Day 1:骨架 + 域名上线(2 小时)”目标:浏览器打开 niuxue.org 能看到一个能跑的站,内容是占位也行。
Step 1:起 Astro Starlight 模板(10 分钟)
先装好 Node.js(LTS 版,版本 22.12 或更高,这是 Astro 的最低要求;装完在终端输入 node -v 确认版本),再运行下面四行。最后一行 npm run dev 是本地预览,网址是 http://localhost:4321,只在你自己电脑上看;看完按 Ctrl+C 停掉。
npm create astro@latest niuxue -- --template starlight --yescd niuxuenpm installnpm run dev10 分钟搞定一个能跑的骨架。
Step 2:买域名 + 第一次部署(40 分钟)
niuxue.org 在 Cloudflare Registrar(Cloudflare 的域名注册服务)注册——CF 不加价,按 ICANN(管全球域名的机构)的实际成本卖,100 元/年。
部署用 wrangler(Cloudflare 官方的命令行工具)。第一次用要先登录:npx wrangler login 会打开浏览器,让你授权它操作你的 Cloudflare 账号。
按顺序运行下面五行:第二行就是上面说的登录,第一次用时跑;第四行 npm run build 是先构建,把整站生成到 dist 文件夹。
npm install -D wranglernpx wrangler loginnpx wrangler pages project create niuxue --production-branch mainnpm run buildnpx wrangler pages deploy ./dist --project-name niuxue --branch mainnpm run dev 只是本地预览,不会生成 dist;不先 npm run build 就部署,wrangler 找不到 dist 文件夹,会直接报错。最后那行的 --branch main 也别省:不写的话,wrangler 会拿你电脑上 Git(记录代码版本的工具,第 1 步建项目时一般已经自动启用)当前的分支名来判断,而 Git 默认的分支名常常是 master,跟上面设的正式分支 main 对不上,这次部署就只算预览版,niuxue.pages.dev 上看不到。项目名 niuxue 换成你自己的。
部署完拿到 niuxue.pages.dev 临时域名,能打开(你的会是 你的项目名.pages.dev;名字被别人占用时会自动加几个随机字符,以创建项目时命令行打出来的网址为准)。
Step 3:绑定自定义域名(10 分钟)
最省事的是在控制台点:在 Cloudflare 控制台的 Workers & Pages 里找到这个项目,进 Custom domains(自定义域) 添加域名。域名本身也在这个 Cloudflare 账号里时,DNS 记录会自动加好。
当时我们是调 API 绑的。想用命令做,别用全局 API Key(Global API Key:拥有整个账号的全部权限,官方已列为旧方式),改用 API Token(API 令牌):在控制台的 API Tokens 页面新建一个,权限只给 Cloudflare Pages:Edit,账号只选这一个,最好再设个过期时间。然后(ACCOUNT_ID 是你的账号 ID,控制台里能找到):
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects/niuxue/domains" \ -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"niuxue.org"}'令牌只放在环境变量或本机不提交的配置文件里,别写进代码、别提交到仓库。
在控制台添加的,DNS 会自动配好;用 API 添加的,到控制台这个项目的 Custom domains 里看一眼状态,要是一直没生效,就在 DNS 里补一条指向 你的项目名.pages.dev 的 CNAME 记录(把一个域名指向另一个域名的记录)。SSL 证书由 CF 自动签(证书机构是 Google、Let’s Encrypt 这类)。5 分钟内 niuxue.org 就能打开。
外加一条跳转,把 www.niuxue.org 301 永久跳转到 niuxue.org —— 避免搜索引擎把两个网址当成两个站、分散权重。当时用的是 Page Rule(页面规则),这个功能 Cloudflare 已经标为弃用;现在官方做法是用 Redirect Rules(重定向规则)。注意 www 要有一条开启代理(Proxied)的 DNS 记录,规则才会生效。
Day 1 结束:站能打开了,但内容还是 Starlight 默认欢迎页。核心通路打通。
Day 2:内容 + 设计 + SEO(6 小时)
Section titled “Day 2:内容 + 设计 + SEO(6 小时)”这是 8 小时里最磨人的部分——内容 / 设计 / SEO(搜索引擎优化)三件事并行。
Step 4:首页 hero 钩子(hero 是首页最上面那块大标题;45 分钟,3 轮迭代)
Starlight 默认「Welcome to Starlight」必须换。我们试了 3 版:
| 版本 | 文案 | 反馈 |
|---|---|---|
| v1 | 「AI 实战教程站」 | 太干,像企业官网 |
| v2 | 「把 AI 用顺手」 | OK 但缺紧迫感 |
| v3 | 「AI 不会取代你,用 AI 的人会」 | ✅ 焦虑切入,普通人 1 秒 get |
当时的判断是:好钩子要砸进人的情绪,不是讲清楚定位。后来站点改成面向零基础新手,首页换成了更平和的「第一次用 AI,从一件小事开始」,不再用焦虑切入。
Step 5:第一篇文章(3 小时)
按 SOP(固定流程)走:选题(什么是 Claude Code)→ 列大纲 → 写草稿 → 自检 → 部署。3 小时出第一篇。
写作风格 4 条:
- 故事感 —— 不从概念定义开,从一个具体瞬间开
- 类比多 —— 「Claude Code vs 网页版」 = 「问路的路人 vs 请回家的助理」
- 不堆术语 —— token / RLHF / transformer 第一次出现都用人话翻译
- 每段一件事 —— 不绕回去
Step 6:SEO 全套(2 小时)
一次性配齐:
- 分享卡片信息(OG、Twitter Card)/ 规范网址(canonical,告诉搜索引擎哪个网址是正版)/ 关键词 —— 改写 Starlight 的页面头部组件(Head),统一注入
- JSON-LD 结构化数据(写给搜索引擎看的「这是一个网站、这是一篇技术文章」说明)—— Google 抓取更友好
- 网站地图 sitemap-index.xml + robots.txt(告诉搜索引擎的爬虫有哪些页面、哪些能抓)—— 引导主流爬虫(Google / 百度 / Bing / 360 / 搜狗 / 神马)
- favicon(网站图标)全套 —— SVG + 16/32/180/512 PNG + .ico + Web App Manifest(添加到手机桌面时用的说明文件)
- OG 分享图(链接被转发时显示的预览图)—— 1200x630 暖橙主视觉,Telegram、X 这类平台转发时会显示。微信不读这张图:没接公众号 JS-SDK 的网页,在微信里分享一律显示默认缩略图
提交搜索引擎:
- ✅ Google Search Console(谷歌的站长工具)—— 通过 Cloudflare 集成一键验证网站归属
- ✅ Bing Webmaster —— 从 GSC 一键导入
- ❌ 百度站长 —— 添加失败(推测 ICP 备案问题,靠自然收录就行)
Step 7:设计迭代(等下面那一节专门讲)
Day 2 结束:站有了灵魂——hero 文案直击痛点、第一篇文章上线、SEO 全套就位、配色 / 字体 / 双语主题统一。
Day 3+:动态化(评论 / 后台 / 流量)
Section titled “Day 3+:动态化(评论 / 后台 / 流量)”
到这里站是「纯静态」的——能看不能交互。当时的下一步是加动态功能。
核心约束:全部跑在 Cloudflare 一个账号下,零新注册任何第三方服务。
评论系统:自建(200 行代码)
Section titled “评论系统:自建(200 行代码)”Jamstack(先把页面生成好、直接发给读者的建站方式)静态站的硬伤——评论需要后端 + 数据库。市面方案都不满意:
- Giscus / utterances —— 基于 GitHub Discussions / Issues,要 GitHub 账号
- Disqus —— 国内访问差,广告多
- Waline / Twikoo —— 好用但要部署 Vercel + MongoDB
- Cusdis —— 要 Postgres
最后选自建 —— 用 Cloudflare D1(Cloudflare 的 SQLite 小数据库)+ Pages Functions 写一个 200 行评论 API:
- 评论者填昵称即可,邮箱可选 —— 真正不记名
- 一层嵌套回复(root + replies)
- 本机用 localStorage(浏览器里的小存储)存
delete_token,可以删自己发的 - 点赞 / 踩,IP+id UNIQUE 约束保证一人一次
- 防垃圾:honeypot(蜜罐:只有机器人才会去填的隐藏输入框)+ 同 IP 60 秒最多 3 条
管理后台(当时在 /admin/)
Section titled “管理后台(当时在 /admin/)”一个简单 dashboard:
- 登录口令存在 Cloudflare Pages 的加密变量(secret)里,不写进代码
- 列所有评论、按文章筛选、管理员一键删除
- 嵌入流量看板(用 Cloudflare 的 GraphQL 分析接口,拉真实访客数据 RUM):浏览量 PV / 访客数 UV / 热门页 / 国家分布 / 7 天趋势柱状图
总共 500 行前端代码 + 几个 Functions endpoint,一晚搞定。
流量监控:Cloudflare Web Analytics
Section titled “流量监控:Cloudflare Web Analytics”当时是在页面头部加一行统计脚本(beacon script)就开始收数据,不用 cookie,隐私友好。用 Pages 的话还有更省事的办法:在项目的 Metrics(指标)里直接开启 Web Analytics,下次部署时 Cloudflare 会自动把脚本加进页面。
一年成本:约 100 元
Section titled “一年成本:约 100 元”
| 项 | 成本 |
|---|---|
域名 niuxue.org(CF Registrar) | ~100 元/年 |
| Cloudflare Pages | 免费 |
| Cloudflare D1(评论数据库) | 免费层 5GB 够用 N 年(评论区下线后已不用) |
| Cloudflare Workers / Functions | 免费层每天 10 万次请求(评论和后台下线后已不用) |
| Cloudflare Web Analytics | 免费(重建后页面里没有再加统计脚本) |
| 邮箱(gmail) | 免费 |
| 总年成本 | ~100 元 |
当时不到一顿火锅的钱,就跑起了一个带评论和后台的站点。现在评论和后台都已下线,固定开销主要是域名。表里没算写文章、写代码用的 AI,那部分看你用哪家、用多少。
这是 niuxue.org 想证明的一件事——普通人用 AI,一年 100 块就能拥有一个真正属于自己的内容平台。
真实踩过的 7 个坑
Section titled “真实踩过的 7 个坑”按真实顺序:
❌ 坑 1:CF site_tag vs site_token 搞混
Section titled “❌ 坑 1:CF site_tag vs site_token 搞混”设 Cloudflare Web Analytics 时,CF 同时分配:
- site_tag(公开 ID,用于 GraphQL 查询)
- site_token(写在网页里的上报标识,本来就是公开的,用于 beacon 上报)
我搞混了——把 site_tag 当成 token 注入到 head 里,beacon 上报全部被 CF 丢弃。 等了 1.5 小时以为是「数据收集需要时间」,用 GraphQL 跨 site 查账户总数据发现别的站正常、唯独 niuxue.org 0 条,才反应过来。
修复:用真正的 site_token。CF 文档没说清这两个 ID 的区别,是个普遍踩坑警示。更省事的是用 Pages 自带的一键开启(见上文),让 Cloudflare 自动加脚本,根本碰不到这两个 ID。
❌ 坑 2:AI 改图返回 RGB 模式的 PNG(没有 alpha 透明通道)
Section titled “❌ 坑 2:AI 改图返回 RGB 模式的 PNG(没有 alpha 透明通道)”给 logo 加「牛学」中文字时,AI 把透明背景画成了灰白 checker pattern——浏览器上看就是个丑陋的格子。
修复:用 PIL(Python 的图片处理库)重写 alpha 通道(记录透明度的那一层),把棋盘格变回透明。
❌ 坑 3:Starlight 严格 schema
Section titled “❌ 坑 3:Starlight 严格 schema”加 frontmatter pubDate: 2026-05-16 直接 build 失败:YAML 把它解析成日期对象,但我们自己给 schema 加的 pubDate 字段定义成了字符串(Starlight 自带的字段里没有 pubDate)。
修复:在 src/content.config.ts 里用 docsSchema({ extend: z.object({ pubDate: z.coerce.date() }) }) 扩展字段(z 从 astro/zod 引入),让它自动转成日期;或者干脆用 Starlight 自带的 lastUpdated,它本来就支持日期。
❌ 坑 4:明暗模式只翻一半
Section titled “❌ 坑 4:明暗模式只翻一半”自己挖的坑——重新定义了 Starlight 灰色变量,但忘了在 light 模式 override,导致切换无效。
修复:在 light 跟 dark 两套 CSS variable 里都定义一遍。
❌ 坑 5:OG 分享图全站同一张
Section titled “❌ 坑 5:OG 分享图全站同一张”转发到 Telegram、X 这类会读分享图的平台时,19 篇文章卡片都长一样——读者根本分不清哪一篇。(微信不读这张图:没接公众号 JS-SDK 的网页,在微信里分享一律显示默认缩略图,想自定义得先接公众号的 JS-SDK。)
修复:用 PIL + Noto CJK 字体 + 模板,批量生成每篇自己的 OG 图,1200x630。(2026 年 8 月重建后,逐篇分享图没有恢复,现在全站又是同一张。)
❌ 坑 6:回复框默认显示「正在回复 」空白
Section titled “❌ 坑 6:回复框默认显示「正在回复 」空白”Astro 渲染 hidden 属性在某些情况下没生效,导致评论区显示一个空白的「正在回复 」提示框。
修复:加 CSS [hidden] { display: none !important } 兜底。(评论区已随 8 月重建下线,这个坑留作记录。)
❌ 坑 7:dist 路径搞错
Section titled “❌ 坑 7:dist 路径搞错”wrangler pages deploy ./dist 跑成功但加了功能没生效——原因是 pages_build_output_dir 没配。
修复:改 wrangler.toml(wrangler 的配置文件)加上这一项就对。Pages 项目的配置文件里不写 pages_build_output_dir,wrangler 只把它当本地开发用,里面的数据库绑定等设置不会跟着部署上线。
每个坑都浪费过 20-60 分钟。把它们写下来给后来人省时间——这就是 niuxue.org 想做的事。
设计迭代:折腾最久的部分
Section titled “设计迭代:折腾最久的部分”设计是 niuxue.org 折腾最久的地方,连续改了 4-5 轮:
| 轮次 | 改了什么 |
|---|---|
| 1 | Hero 装饰:默认 Starlight 模板 → photo-illustration(人在夜里用电脑)→ 但「不融合」→ 改成抽象能量图 → 最后变成 logo 化处理(牛角 + 圆球 + 「牛学」字) |
| 2 | 顶部品牌名:纯英文「niuxue.org」 → 加中文「牛学 · niuxue.org」(中点分隔,中英对应) |
| 3 | 配色:用 Hono 文档主色 #ff6432 暖橙做 accent,dark 模式做默认 |
| 4 | 字体:Inter(英文) + Noto Sans CJK SC(中文) + JetBrains Mono(代码) |
| 5 | 明暗切换:自己挖的坑(见坑 4),修了 |
(后来改版时,字体换回了 Starlight 默认的系统字体。)
每一步迭代都丢给 Claude Code 改 CSS + 部署 + 截图比对,平均一次循环 5 分钟。
这套站能教你 3 件事
Section titled “这套站能教你 3 件事”💡 1. 选 stack 不靠「什么最潮」,靠「满足约束最少」
Section titled “💡 1. 选 stack 不靠「什么最潮」,靠「满足约束最少」”我们没用 React / Next.js / Vercel —— 不是它们不好,是做一个文档站用不上它们的长处。
Astro Starlight + Cloudflare Pages —— 两套加起来就够用了,多一个组件都是负担。
选型秘诀:先列约束,再列候选,选最少候选满足全部约束的。
💡 2. 一个账号全包,比「最好的服务拼起来」省事
Section titled “💡 2. 一个账号全包,比「最好的服务拼起来」省事”我们没用 Auth0 做认证 / Supabase 做数据库 / Mixpanel 做分析(都是各自领域的专门服务)—— 每个都比 CF 对应服务「更好一些」,但要管 5 个账号 / 5 套 secret(密钥)/ 5 个 dashboard(控制台)。
Cloudflare 一个账号 —— 服务略弱,但集成没有摩擦,省下的是管账号、管密钥的精力。
整合 > 最优,特别是个人项目。
💡 3. AI 写代码,你写决策
Section titled “💡 3. AI 写代码,你写决策”整个 8 小时,洁柔没手写过一行代码 —— 代码全是 Claude Code 写的。
她做的事:
- 挑技术栈(读 Claude 的方案对比 → 拍板)
- 判断设计(看 Claude 生成的 hero → 觉得不行 → 提反馈)
- 决定踩坑修法(Claude 给 3 个方案 → 选最稳的)
- 审稿(看文章风格对不对 → 改)
AI 不替代你思考,替代你做「已知怎么做但费时间」的事。这是 2026 年普通人创业的真实剧本。
接下来想做什么
Section titled “接下来想做什么”写这篇时(2026 年 5 月)列的计划,现在的进度标在后面:
短期:
- ✅ 补齐进阶与自动化板块(VS Code / 桌面 App / Web 版 / Hooks / MCP / Routines / Channels…)
- ✅ 把「干活」和「真实案例」板块里有遗漏的细节补上
- 加 RSS 订阅(让读者能订阅更新)——还没做
中期:
- 加搜索高亮 / 索引优化
- 启用文章评论邮件通知(评论区已随 2026 年 8 月重建下线)
长期:
- 多语言(英文版?要不要做?看流量)
- 衍生产品 —— 把这套 stack 模版化,让其他人也能 5 小时搭一个免费教程站
源码暂未开源。想搭类似的站,照上面的步骤从 Starlight 官方模板起步就行。
「真实案例」完结撒花 🎉🎉🎉
Section titled “「真实案例」完结撒花 🎉🎉🎉”恭喜你看完了「真实案例」全部 5 篇。
- ✅ AI 是配人格的伙伴 → 一窝 Claude bot
- ✅ 30 字需求 3 天能上线网页 app → 自建 Web Chat 三天上线
- ✅ 一周做一个小工具是新常态 → 工时表 + 墨水屏看板
- ✅ 痛点 + 目标用户 + 反直觉设计 → MoldPage:把「找工作的痛」做成产品
- ✅ 一年 100 元左右搭一个教程站 → 你正在看的这一篇
这 5 篇的核心信息:AI 工具不会替你思考,但会替你做「已知怎么做但费时间」的事。
剩下的——只看你愿不愿意动手。
下一步:进阶玩法都已上线
Section titled “下一步:进阶玩法都已上线”案例看完想动手升级,两个板块随便挑:
- Claude Code 进阶 —— VS Code 插件、桌面 App、Hooks、MCP、Subagents、Worktrees(程序员玩法)
- 自动化与协作 —— Routines、Remote Control、Channels、Agent Teams、Safe Autonomy(老手专属)
如果你也想搭一个类似的教程站,可以照这一篇的步骤走。不用自己写代码,但要会在终端里敲命令、看得懂报错的大意 —— 代码交给 Claude Code 写,拍板和检查是你的活。