Learn network by enabling public domain
本文最后更新于 2026年8月16日 晚上
我之前什么自顶向下看了3遍,图解HTTP看了5遍,还没今天干一遍印象来得深刻。
前言
我之前写的电纸书阅读方案里有提到,我把大模型的思考过程和结果都放电子书上,然后通过 飞牛Nas 提供 FN Connect 飞牛远程访问服务 进行访问。
原理是我先在 飞牛Nas 中部署了一个可以正常在局域网中访问的特定端口的 Docker 服务,接下来 FN Connect 飞牛远程访问服务 会把这个端口映射到公网可访问的自行维护的域名上的一个 子域名 中,比如 example-subdomain.fnos.net。
用了一段之后发现想要访问这个页面,必须先登录 飞牛Nas 的系统,且登录态一段时间后就会过期。同时由于这个登录态的缘故,也没法直接开放一个优雅地上传 .md 文件的接口。
因此才会有本文。在实践完本文提到的流程,并且就各环节进行延展资料学习后,觉此法效果甚好,特此记录。
最终成本
仅从腾讯云 5元 购入一个 http://ink-md.asia/ 域名,使用的首年优惠价,次年过期换一个即可,又不是对外提供服务的,就我自己用,不必考虑一致性。
常规考虑: VPS + Public IP + DNS
以前从事一些网络运维的工作,自然就会想到预先需要一个 公网IP,组成如下的访问流程:
浏览器 → DNS 查到 VPS IP → 直接访问 VPS 的 443 端口
flowchart TB
Reader["手机 / 电子书 / 电脑浏览器"]
Domain["ink-md.asia<br/>固定域名"]
DNS["DNS 服务商<br/>把域名解析到公网 IP"]
PublicIP["VPS 公网 IP<br/>例如 203.0.113.10"]
VPS["VPS<br/>云服务器"]
Caddy["Caddy<br/>HTTPS + 网页 Basic Auth"]
App["Go Markdown Server<br/>阅读 + PUT / POST 追加 API"]
Files["VPS 磁盘文件夹<br/>/srv/markdown/content"]
Tencent["腾讯云<br/>域名注册商"]
Tencent -. "注册域名;在 DNS 服务商<br/>配置解析权限" .-> Domain
Reader -->|"https://ink-md.asia"| Domain
Domain --> DNS
DNS -->|"A 记录:203.0.113.10"| PublicIP
PublicIP -->|"公网 443 端口"| VPS
VPS --> Caddy
Caddy --> App
App --> Files
但后来在 AI大人 的教育下,直接建立了本地服务到 DNS 的隧道,连 VPS 的钱都省下来了。
AI的知识点总结得很好,但是现在是我的了。
这份说明记录 https://ink-md.asia/ 是怎样从家里的 NAS 公开到互联网,同时仍保留密码保护的。
它适合把 NAS 想成“家里的小图书馆”:书实际放在家里,但我们在互联网给它挂了一个固定、好记、能上锁的门牌。
最终效果
- 读者访问固定地址:https://ink-md.asia/
- NAS 不需要开放路由器端口,也不需要公网 IP。
- 网页阅读要输入用户名和密码。
- 写入 Markdown 除了网页密码,还要额外提供写入 Token。
- NAS 或 Cloudflared 重启后,网址不会改变。
一张总览图
flowchart TB
Reader["手机 / 电子书 / 电脑浏览器"]
Domain["ink-md.asia\n固定域名"]
CF["Cloudflare\nDNS + HTTPS + Tunnel 入口"]
Tunnel["Cloudflared 容器\nNAS 主动连向 Cloudflare"]
Auth["Caddy\n网页 Basic Auth"]
App["Go Markdown Server\n阅读 + PUT / POST 追加 API"]
Files["NAS 文件夹\n/srv/Markdown-reader/content"]
Tencent["腾讯云\n域名注册商"]
Reader -->|"https://ink-md.asia"| Domain
Domain --> CF
CF --> Tunnel
Tunnel --> Auth
Auth --> App
App --> Files
Tencent -. "注册域名;名称服务器\n改为 Cloudflare" .-> Domain
各部分分别做什么
1. 腾讯云:域名注册商
腾讯云的作用是“登记 ink-md.asia 归谁管理”。这相当于在全世界通用的域名登记系统中保留这个名字。
它不负责运行 Markdown 服务,也不负责把网页内容从 NAS 传给浏览器。我们没有购买腾讯云服务器,也没有让腾讯云保存 Markdown。
后续把域名的**名称服务器(Name Server)**改成 Cloudflare 提供的两条地址后,域名仍然是你在腾讯云注册的,只是“这个名字该指向哪里”的日常查询改由 Cloudflare 回答。
推荐阅读:
2. Cloudflare:公网门厅、DNS 和加密通道的运营者
Cloudflare 在这里承担三个工作:
- DNS:当浏览器询问“
ink-md.asia在哪里?”时,Cloudflare 返回正确的路线。 - HTTPS:浏览器和 Cloudflare 之间使用 HTTPS。地址栏的锁,表示传输过程被 TLS 加密。
- Cloudflare Tunnel:Cloudflare 接到请求后,通过一条已经建立好的加密隧道把请求送回 NAS。
Cloudflare 并不保存你的 Markdown 文件,也不会直接从互联网连接 NAS 的 8090 端口。它只接收公众请求,再转交给 NAS 主动建立的 Tunnel。
推荐阅读:
3. NAS:真正保存文件、渲染 Markdown 的地方
NAS 运行了几个 Docker 容器:
| 容器 | 职责 |
|---|---|
md-reader |
Go 程序。读取和渲染 Markdown,也提供写入 API。 |
markdown-auth |
Caddy 反向代理。在把请求交给 Go 程序前检查网页用户名与密码。 |
markdown-named-tunnel |
Cloudflared。主动连接 Cloudflare,保持固定隧道。 |
Markdown 内容仍在 NAS 的:
1 | |
因此它是“服务的源头(origin)”。Cloudflare 是入口和转发站,NAS 才是放书、改书的地方。
推荐阅读:
访问一次网页时,网络上发生什么
当电子书打开 https://ink-md.asia/,大致经历以下步骤:
sequenceDiagram
participant B as 浏览器
participant D as Cloudflare DNS
participant C as Cloudflare
participant T as NAS Cloudflared
participant A as Caddy 认证层
participant G as Go Markdown 服务
B->>D: 查询 ink-md.asia 的地址
D-->>B: 返回 Cloudflare 的路线
B->>C: HTTPS 请求网页
C->>T: 通过已建立的 Tunnel 转发
T->>A: 转给 NAS 的本机认证层
A-->>B: 未认证时返回 401 和登录提示
B->>A: 发送 Basic Auth 用户名与密码
A->>G: 认证成功后转发请求
G-->>B: 返回 HTML、CSS、Mermaid JavaScript
DNS:先找“门牌”
DNS 可以类比为互联网电话簿。浏览器不会天然知道 ink-md.asia 在哪里,所以先查询 DNS。
这里 DNS 不会返回 NAS 的家庭 IP,而是把访问导向 Cloudflare。这样家庭网络的真实入口不需要暴露给读者。
HTTPS:浏览器到 Cloudflare 的加密段
https:// 意味着浏览器会先校验证书,再建立 TLS 加密连接。途中 Wi‑Fi、运营商或公共网络无法直接看懂传输的正文。
但 HTTPS 并不自动等于“只有你能访问”。它负责保密传输;谁有访问权限则由后面的认证来决定。
Tunnel:NAS 主动“打出去”的长连接
传统做法是让路由器开放一个端口,例如把公网的 443 映射到 NAS。这样每个互联网用户都能直接敲 NAS 的门。
Tunnel 反过来做:NAS 中的 Cloudflared 主动向 Cloudflare 建立出站连接。家用网络通常允许这种“从内向外”的连接,所以不需要端口映射。有人访问域名时,Cloudflare 再沿着已有隧道把请求送回来。
1 | |
这也是 Tunnel 能避开动态公网 IP、运营商封端口,以及家庭路由器复杂配置的原因。
推荐阅读:
为什么网址能长期固定
之前的 trycloudflare.com 是 Quick Tunnel:它适合临时试用,容器重启后会得到新的随机网址。
现在用的是 Named Tunnel(命名隧道):
1 | |
只要域名持续续费、Cloudflare 账户与 NAS 容器仍在运行,网址就保持不变。Cloudflared 的登录证书和 Tunnel 凭据保存在 NAS 的私密目录中;它们像“NAS 连接到 Cloudflare 的身份证和钥匙”,不应复制到聊天、Git 仓库或公开网页中。
推荐阅读:
两道访问保护
目前写入动作需要通过两道门:
flowchart LR
Request["写入请求"] --> Basic["第 1 道:网页 Basic Auth\n用户名 + 密码"]
Basic -->|"通过"| Token["第 2 道:Bearer Token\n长随机写入密钥"]
Token -->|"通过"| Write["写入 NAS 的 .md 文件"]
Basic -->|"失败"| Stop1["401"]
Token -->|"失败"| Stop2["401"]
第 1 道:Caddy Basic Auth
这是浏览器访问网页时弹出的用户名和密码框。它保护整个公网入口,包括阅读页面和写入 API。
第 2 道:写入 Token
为了避免“能阅读的人自动也能修改文件”,Go 服务要求写入 API 再带一个长随机 Token。
1 | |
这里不用 Authorization: Bearer ...,是因为同一个 HTTP 请求的Authorization 已由第一道 Basic Auth 占用;一个请求不能同时把它当作
Basic Auth 和 Bearer Token。独立的 X-API-Write-Token 头避免了这个冲突。
因此:
- 只有网页密码:可以阅读,不能写入。
- 只有写入 Token:仍然过不了 Caddy 的网页密码。
- 两个都正确:才可覆盖或追加 Markdown。
Token 应视为密码:不要放入 Markdown、截图、Git commit、公开脚本或 URL。若泄漏,应立即生成新 Token 并重启 md-reader 容器使其生效。
推荐阅读:
Markdown 写入 API
接口只接受 content 根目录里的一个 .md 文件名,例如 skill-compass.md;不接受目录、.. 或其他路径字符。这能阻止接口被用来写到 NAS 的其他位置。
完整覆盖:PUT
1 | |
请求体放完整 Markdown。服务先写入临时文件,写完后才替换原文件;如果中途失败,不会留下“只写了一半”的正文。
追加新章节:POST /append
1 | |
请求体是 JSON:
1 | |
服务会在文件末尾追加:
1 | |
写入大小上限为 2 MiB,并且服务会让同一时刻的写入依次进行,避免两次请求把内容交错写进一个文件。
推荐阅读:
常见概念速查
| 概念 | 白话解释 | 在本服务中的例子 |
|---|---|---|
| 域名 | 人方便记的网络名字 | ink-md.asia |
| DNS | 把名字查成网络路线的电话簿 | Cloudflare DNS |
| 注册商 | 替你登记并续费域名的平台 | 腾讯云 |
| 名称服务器 | 负责回答某个域名 DNS 查询的服务器 | Cloudflare 给出的两条 *.ns.cloudflare.com |
| HTTPS / TLS | 浏览器与网站之间的加密信封 | 浏览器到 Cloudflare |
| 反向代理 | 站在服务前面接待请求,再转交后端 | Caddy |
| 认证 | 确认“你是谁 / 你有钥匙吗” | Basic Auth、Bearer Token |
| Docker 容器 | 打包好的独立小运行环境 | md-reader、markdown-auth、markdown-named-tunnel |
| Tunnel | 从 NAS 主动连出的安全通道 | Cloudflared 到 Cloudflare |
| 端口 | 一台机器上区分不同网络服务的编号 | NAS 本机 8090、认证层 18080 |
出问题时怎么初步判断
| 现象 | 优先检查 |
|---|---|
| 域名打不开 | Cloudflare DNS 是否激活;markdown-named-tunnel 是否运行。 |
| 出现密码框但登录后仍打不开 | markdown-auth 与 md-reader 是否运行。 |
| 网页能读,写入返回 401 | 是否同时提供了 Basic Auth 和 Bearer Token。 |
| 写入返回 404 | 文件名是否存在、是否是根目录单个 .md 文件名。 |
| 写入返回 503 | API_WRITE_TOKEN 没有配置到 md-reader。 |
| 电子书打不开 Mermaid 图 | 先查看 /__diag/ 诊断页;旧 WebView 会使用兼容的 Mermaid 版本。 |
NAS 上可查看这三个容器:
1 | |
查看 Tunnel 日志:
1 | |
以后可以怎样继续升级
当前方案已经适合个人阅读与受控的 agent 写入。若未来访问者变多、内容更敏感或希望进一步简化登录,可考虑:
- Cloudflare Access:用邮箱一次性验证码、Google 登录或身份验证器代替网页 Basic Auth。
- 分开读写域名:例如
read.ink-md.asia只读,write.ink-md.asia只给写入工具使用。 - Token 定期轮换:每隔一段时间更换写入 Token。
- 备份与版本管理:让 Markdown 内容目录定期备份,或用 Git 记录每次修改。
- 上传审计日志:记录何时、由哪个工具修改了哪个文件。
推荐阅读:
一句话总结
腾讯云负责“这个域名是你的”;Cloudflare 负责“互联网访问这个域名时,安全地送到哪里”;NAS 负责“真正保存、阅读和修改 Markdown”。
Cloudflare Tunnel 让 NAS 主动向外建立连接,因此不必把家庭网络的端口直接暴露到公网;Caddy 密码与写入 Token 则让“看书”和“改书”各有一道门。