附 · 部署与使用
把它放到网上,或者只放在你自己的电脑里
这个网站是一个纯静态站点:没有后端、没有数据库、没有构建依赖,只有 HTML、CSS 和一点点原生 JavaScript。所以它可以在任何地方跑起来——包括你离线的时候。
1. 它由什么组成
Ways-to-Robot/
├─ index.html 首页:学习地图 + OWL 介绍
├─ glossary.html 术语总表(可搜索、可筛选)
├─ guide.html 你正在读的这一页
├─ 404.html 找不到页面时的引导页
├─ robots.txt / sitemap.xml 搜索引擎用(记得替换 sitemap 里的域名)
├─ _headers 响应头配置(Cloudflare Pages / Netlify 自动读取)
├─ 本地预览.cmd 双击在 8080 端口起一个本地服务器
├─ chapters/
│ └─ ch0.html … ch9.html 十章正文(由构建脚本生成,勿手改)
├─ assets/
│ ├─ css/style.css 全站样式(四色 + 宋体,无第三方框架)
│ └─ js/
│ ├─ chapters.js 章节元数据(导航与地图的唯一真源)
│ ├─ terms.js 术语库(基础卷,约 380 条)
│ ├─ terms-extra-chN.js 各章补充的术语(共约 200 条)
│ └─ site.js 目录、进度、术语弹窗、总表渲染
├─ src/
│ └─ chN.html 各章正文「片段」(真正的写作现场在这里)
├─ tools/
│ ├─ build.mjs 把片段套上外壳,生成 chapters/*.html
│ ├─ _shell.html 章节页外壳模板
│ ├─ check.mjs 全站体检:字数、结构、标签配平、死链、术语一致性
│ ├─ status.mjs 各章统计速览
│ ├─ fix-md.mjs 把小失误(**粗体**)转成 HTML
│ ├─ dedupe-terms.mjs 术语去重(保留信息更全的一条)
│ ├─ add-abilities.mjs 给每章补「学完你会做这些事」(幂等)
│ ├─ package.ps1 打包成 zip(含密钥文件自检)
│ ├─ 写作规范.md 章节写作规范
│ └─ 审校清单.md 独立审校标准
└─ deploy/
├─ nginx.conf.example Nginx 站点配置示例
└─ 部署指南.md 给服务器用的部署步骤
▲ 目录结构。注意 src/ 与 chapters/ 的关系:前者是源,后者是成品。
2. 三种使用方式,从最简到最正式
2.1 直接双击打开(离线可用)
找到 index.html,双击。它会用你的默认浏览器打开,全站内容、术语弹窗、章节目录、进度标记都能正常工作——因为所有资源都是本地文件,没有任何网络请求。
为什么能离线本站的 JavaScript 全部是普通脚本(不是 ES module),不做 fetch 请求,所以不受浏览器对 file:// 协议的限制。这是刻意设计的结果。
2.2 本地起一个服务器(更接近真实环境)
如果你想验证部署后的效果,或者要改代码,建议用本地 HTTP 服务打开。三种任选其一:
# 有 Python 的话(最省事)
python -m http.server 8080
# 有 Node 的话
npx serve .
# 或者用 Node 内置能力写两行
node -e "const h=require('http'),f=require('fs'),p=require('path');h.createServer((q,s)=>{let u=decodeURIComponent(q.url.split('?')[0]);if(u.endsWith('/'))u+='index.html';const fp=p.join(process.cwd(),u);f.readFile(fp,(e,d)=>{if(e){s.writeHead(404);return s.end('404')}const t={'.html':'text/html','.css':'text/css','.js':'text/javascript'};s.writeHead(200,{'Content-Type':(t[p.extname(fp)]||'text/plain')+'; charset=utf-8'});s.end(d)})}).listen(8080,()=>console.log('http://127.0.0.1:8080'))"
然后浏览器访问 http://127.0.0.1:8080。
2.3 部署到公网
见下面第 3、4 节。
3. 部署到 GitHub Pages(免费,五分钟)
- 在 GitHub 上新建一个仓库,例如
ways-to-robot,设为 Public(免费账号的 Pages 需要公开仓库)。 - 在本地进入站点目录(不是它的上级目录),初始化并推送:
cd Ways-to-Robot
git init -b main
git add .
git commit -m "feat: Ways to Robot 学习站点首次发布"
git remote add origin git@github.com:你的用户名/ways-to-robot.git
git push -u origin main
- 在仓库页面进入 Settings → Pages,Source 选
Deploy from a branch,分支选main、目录选/ (root),保存。 - 等一两分钟,访问
https://你的用户名.github.io/ways-to-robot/。
提示推送前请确认仓库里没有任何密钥文件。本站本身不含密钥,但如果你顺手把自己机器人的 llm.local.json 拷进来,就会出事。先写 .gitignore,再 git add .。
.gitignore 建议内容:
# 密钥与本地配置
*.local.json
.env
*.pem
# 系统与编辑器
.DS_Store
Thumbs.db
.vscode/
# 临时文件
*.log
*.tmp
4. 部署到自己的服务器(Nginx + SSH)
如果你已经有一台装了 Nginx 的服务器(第一章与第七章讲过怎么连上它),部署静态站点只需要三步:传文件、配站点、开端口。
4.1 传文件:scp 或 rsync
# 方式一:scp 直接复制整个目录(简单粗暴,覆盖全部)
scp -r ./Ways-to-Robot/* root@你的服务器IP:/var/www/ways-to-robot/
# 方式二:rsync 增量同步(推荐,只传变化的文件,可加 --delete 清理多余文件)
rsync -avz --delete ./Ways-to-Robot/ root@你的服务器IP:/var/www/ways-to-robot/
▲ -a 保留权限与时间、-v 显示过程、-z 传输压缩。--delete 会让服务器上的目标目录与本地完全一致——用之前确认路径没写错。
4.2 配置 Nginx
新建 /etc/nginx/sites-available/ways-to-robot(内容见部署包里的 deploy/nginx.conf.example),然后启用并检查:
sudo ln -s /etc/nginx/sites-available/ways-to-robot /etc/nginx/sites-enabled/
sudo nginx -t # 检查语法,出错会明确告诉你哪一行
sudo systemctl reload nginx
注意永远先 nginx -t 再 reload。配置写错还强行重载,会让整个服务器上所有站点一起挂掉——包括你正在维持的那个机器人(如果它也挂在 Nginx 后面)。
4.3 开端口与上 HTTPS
- 云服务器的安全组放行
80(HTTP)与443(HTTPS)。只放这两个,别顺手把 3001 之类的端口也打开。 - 系统防火墙(如果启用了)同样放行:
sudo ufw allow 80,443/tcp。 - 要 HTTPS 的话,最简单的做法是 Certbot,它会自动申请证书并改写 Nginx 配置:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d 你的域名
HTTPS 不只是"有个小锁",它保证访问者看到的内容没有被中途篡改——对一个讲技术的网站来说,这本身就是一种示范。
5. 其他托管方式(一句话版)
- Cloudflare Pages / Vercel / Netlify:连上 GitHub 仓库即可,自动构建、自动 HTTPS、免费额度足够。纯静态站点最省心的选择。
- 对象存储(OSS / COS / S3):把整个目录上传,开启静态网站托管。适合国内访问速度要求高的场景,但要注意备案与计费细节。
- 放在机器人服务器上:同一个 Nginx 里既托管这个网站、又反代你的服务,是最"顺手"的做法,注意两者别抢同一个端口。
6. 怎么改内容
6.1 改一章的正文
正文写作现场在 src/chN.html(片段,不带 <html> 外壳)。改完之后,回到站点根目录执行:
node tools/build.mjs # 重新生成 chapters/*.html
node tools/build.mjs --check # 只看统计、不写文件
这个脚本会做两件事:把每个片段套上 tools/_shell.html 生成完整页面;扫描所有 terms-extra-*.js,把它们注入到各页面的脚本列表里。输出里会打印每一章的字数与结构统计,可以当"内容体检"用。
6.2 加一条术语
打开 assets/js/terms.js,照着已有条目写一条即可,键名就是页面里会自动链接的那个词:
"无状态": {
full: "Stateless",
zh: "无状态",
cat: "网络与协议", // 必须是已有分类之一
desc: "服务器不记得上一次请求是谁发的……
补充说明。",
rel: ["HTTP", "Token"] // 相关术语,点击可跳转
}
改完刷新页面即可生效,不需要重新构建。注意:不要重复定义已经存在的键,后面的会覆盖前面的(可以用 node -e 一行命令列出所有已有键)。
6.3 加一章
- 在
assets/js/chapters.js里加一条(id / num / title / short / lede / desc / tags / file); - 新建
src/chN.html,按tools/写作规范.md的结构写内容; - 运行
node tools/build.mjs。
导航、上一章/下一章、首页学习地图、进度统计都会自动更新——因为它们全部由 chapters.js 驱动。
7. 常见问题
- 中文显示成乱码:HTTP 响应头缺少
charset=utf-8。Nginx 默认已经有;自己写的服务要显式加上(示例配置里已经写好)。 - 样式没生效:九成是路径问题。章节页在
chapters/目录里,引用资源要带../;如果你把页面挪到别的层级,就要相应调整。 - 术语点了没反应:检查
terms.js是否成功加载(浏览器控制台会报 404),以及data-term的键名是否和术语库里完全一致(区分大小写的前半部分已做兼容,但中文键必须一字不差)。 - 章节页目录是空的:目录由正文里的
<h2>/<h3>自动生成。如果正文片段没有 h2,目录自然为空。 - 想打印或导出 PDF:直接
Ctrl/⌘ + P。样式里写了打印规则,会自动隐藏导航与侧栏,只留正文。
8. 最后:它不是一次性的
这个站点被刻意设计成"可以一直活下去"的形态:没有框架、没有构建链、没有依赖升级的焦虑,只有一个 200 行的构建脚本和几个普通 JS 文件。三年后你依然能打开它、读懂它、修改它。
这本身就是一条工程判断:一个学习工具,不应该比它教的知识更早失效。