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 在这里承担三个工作:

  1. DNS:当浏览器询问“ink-md.asia 在哪里?”时,Cloudflare 返回正确的路线。
  2. HTTPS:浏览器和 Cloudflare 之间使用 HTTPS。地址栏的锁,表示传输过程被 TLS 加密。
  3. 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
/srv/Markdown-reader/content

因此它是“服务的源头(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
2
传统端口映射:互联网 ──主动敲门──> 家中路由器 ──> NAS
Cloudflare Tunnel:NAS ──主动建立──> Cloudflare <──浏览器

这也是 Tunnel 能避开动态公网 IP、运营商封端口,以及家庭路由器复杂配置的原因。

推荐阅读:

为什么网址能长期固定

之前的 trycloudflare.com 是 Quick Tunnel:它适合临时试用,容器重启后会得到新的随机网址。

现在用的是 Named Tunnel(命名隧道)

1
2
3
4
5
固定域名 ink-md.asia
↓ DNS CNAME 记录
固定 Tunnel ID
↓ NAS 上的 Tunnel 凭据文件
固定 Cloudflared 容器

只要域名持续续费、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
X-API-Write-Token: <长随机写入密钥>

这里不用 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
PUT /api/v1/documents/skill-compass.md

请求体放完整 Markdown。服务先写入临时文件,写完后才替换原文件;如果中途失败,不会留下“只写了一半”的正文。

追加新章节:POST /append

1
POST /api/v1/documents/skill-compass.md/append

请求体是 JSON:

1
2
3
4
{
"title": "今天的标题",
"content": "要追加的 Markdown 正文"
}

服务会在文件末尾追加:

1
2
3
## 2026-08-15 · 今天的标题

要追加的 Markdown 正文

写入大小上限为 2 MiB,并且服务会让同一时刻的写入依次进行,避免两次请求把内容交错写进一个文件。

推荐阅读:

常见概念速查

概念 白话解释 在本服务中的例子
域名 人方便记的网络名字 ink-md.asia
DNS 把名字查成网络路线的电话簿 Cloudflare DNS
注册商 替你登记并续费域名的平台 腾讯云
名称服务器 负责回答某个域名 DNS 查询的服务器 Cloudflare 给出的两条 *.ns.cloudflare.com
HTTPS / TLS 浏览器与网站之间的加密信封 浏览器到 Cloudflare
反向代理 站在服务前面接待请求,再转交后端 Caddy
认证 确认“你是谁 / 你有钥匙吗” Basic Auth、Bearer Token
Docker 容器 打包好的独立小运行环境 md-readermarkdown-authmarkdown-named-tunnel
Tunnel 从 NAS 主动连出的安全通道 Cloudflared 到 Cloudflare
端口 一台机器上区分不同网络服务的编号 NAS 本机 8090、认证层 18080

出问题时怎么初步判断

现象 优先检查
域名打不开 Cloudflare DNS 是否激活;markdown-named-tunnel 是否运行。
出现密码框但登录后仍打不开 markdown-authmd-reader 是否运行。
网页能读,写入返回 401 是否同时提供了 Basic Auth 和 Bearer Token。
写入返回 404 文件名是否存在、是否是根目录单个 .md 文件名。
写入返回 503 API_WRITE_TOKEN 没有配置到 md-reader
电子书打不开 Mermaid 图 先查看 /__diag/ 诊断页;旧 WebView 会使用兼容的 Mermaid 版本。

NAS 上可查看这三个容器:

1
2
ssh <user>@<ip> \
"docker ps --filter name=md-reader --filter name=markdown-auth --filter name=markdown-named-tunnel"

查看 Tunnel 日志:

1
2
ssh <user>@<ip> \
"docker logs markdown-named-tunnel"

以后可以怎样继续升级

当前方案已经适合个人阅读与受控的 agent 写入。若未来访问者变多、内容更敏感或希望进一步简化登录,可考虑:

  1. Cloudflare Access:用邮箱一次性验证码、Google 登录或身份验证器代替网页 Basic Auth。
  2. 分开读写域名:例如 read.ink-md.asia 只读,write.ink-md.asia 只给写入工具使用。
  3. Token 定期轮换:每隔一段时间更换写入 Token。
  4. 备份与版本管理:让 Markdown 内容目录定期备份,或用 Git 记录每次修改。
  5. 上传审计日志:记录何时、由哪个工具修改了哪个文件。

推荐阅读:

一句话总结

腾讯云负责“这个域名是你的”;Cloudflare 负责“互联网访问这个域名时,安全地送到哪里”;NAS 负责“真正保存、阅读和修改 Markdown”。

Cloudflare Tunnel 让 NAS 主动向外建立连接,因此不必把家庭网络的端口直接暴露到公网;Caddy 密码与写入 Token 则让“看书”和“改书”各有一道门。


Learn network by enabling public domain
https://gou7ma7.github.io/2026/08/15/devops/@2026_learn_network_by_enabling_public_domain/
作者
Roy Lee
发布于
2026年8月15日
许可协议