---
title: rathole + Caddy 内网穿透:从 CGNAT 到公网 HTTPS 的完整方案
url: https://doc.liz6.com/homelab/rathole-tunnel
locale: zh
area: homelab
tags:
- homelab
date: 2026-07-01
modified: 2026-08-15
description: 适用场景:CGNAT 或无公网 IP,有 VPS,只需要 TCP 端口转发,追求轻量零内核依赖,不想装 WireGuard 或配 Cloudflare Tunnel。 本机用 rathole——一个 Rust 写的轻量 TCP 隧道,搭在 Docker 里,配合 Caddy 做 TLS 反代,把 Grafana、文档…
---

# rathole + Caddy 内网穿透:从 CGNAT 到公网 HTTPS 的完整方案

> **适用场景**:CGNAT 或无公网 IP,有 VPS,只需要 TCP 端口转发,追求轻量零内核依赖,不想装 WireGuard 或配 Cloudflare Tunnel。
>
> 本机用 rathole——一个 Rust 写的轻量 TCP 隧道,搭在 Docker 里,配合 Caddy 做 TLS 反代,把 Grafana、文档站、SSH 全部透出去。本文从选型、搭建、证书策略,到踩过的三个大坑(HTTP/3、conntrack 掐连接、本机代理劫持隧道),给出一套可复现的完整配置。

## 一、rathole 是什么,什么时候用它

内网穿透的选项很多,按场景选:

| 方案 | 适合 | 不适合 |
|------|------|--------|
| **rathole** | 有 VPS,只需 TCP 端口转发,轻量零依赖 | 需要 UDP、P2P 直连 |
| **frp** | 同上 + 需要 Web 管理面板、更多协议 | 配置更重 |
| **Tailscale** | 不想管 VPS,只自己用,接受 relay 延迟 | 家人/公网用户需要装 client |
| **WireGuard** | 已有 VPS,想组网而非端口映射 | 需要内核模块,CGNAT 下需额外打洞 |
| **Cloudflare Tunnel** | 有域名在 CF,完全不想管 VPS | 流量过 CF(隐私/合规),国内慢 |

本机选的 rathole。理由:已有一台腾讯云 VPS,只需要把家里几个 HTTP 服务 + SSH 透出去,不需要 UDP/P2P/管理面板。rathole 就是一条 TCP 隧道,不解析 TLS、不碰证书——TLS 交给 VPS 上的 Caddy。

> 如果你的场景和本机不重合:CGNAT + 没有 VPS 选 Cloudflare Tunnel;需要组网选 Tailscale;需要 UDP 选 frp。这几种本机没深度用过,下文只展开 rathole 方案。

## 二、架构:一条隧道,两个角色

<svg viewBox="0 0 720 300" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="rathole 隧道架构">
  <defs>
    <marker id="rah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker>
  </defs>
  <rect width="720" height="300" fill="#ffffff"/>
  <text x="360" y="30" text-anchor="middle" font-size="18" font-weight="700" fill="#1f2933">rathole 架构:家里的服务经 TCP 隧道 → VPS → Caddy 暴露到公网</text>
  <!-- Home -->
  <rect x="36" y="56" width="188" height="188" rx="10" fill="#fef3c7" stroke="#f59e0b"/>
  <text x="130" y="84" text-anchor="middle" font-size="14" font-weight="700" fill="#b45309">家里(内网)</text>
  <rect x="52" y="96" width="156" height="30" rx="5" fill="#ffffff"/>
  <text x="130" y="115" text-anchor="middle" font-size="11" fill="#475569">Grafana :3000</text>
  <rect x="52" y="130" width="156" height="30" rx="5" fill="#ffffff"/>
  <text x="130" y="149" text-anchor="middle" font-size="11" fill="#475569">文档站 :8090</text>
  <rect x="52" y="164" width="156" height="30" rx="5" fill="#ffffff"/>
  <text x="130" y="183" text-anchor="middle" font-size="11" fill="#475569">SSH :22 · 更多…</text>
  <rect x="52" y="198" width="156" height="36" rx="6" fill="#f59e0b"/>
  <text x="130" y="214" text-anchor="middle" font-size="11" font-weight="700" fill="#ffffff">rathole-client</text>
  <text x="130" y="228" text-anchor="middle" font-size="10" fill="#fef3c7">network_mode: host</text>
  <!-- arrow -->
  <line x1="224" y1="216" x2="284" y2="216" stroke="#475569" stroke-width="2" marker-end="url(#rah)"/>
  <text x="254" y="240" text-anchor="middle" font-size="11" fill="#64748b">TCP 隧道</text>
  <text x="254" y="254" text-anchor="middle" font-size="10" fill="#94a3b8">加密 · 长连接</text>
  <!-- VPS -->
  <rect x="292" y="56" width="188" height="188" rx="10" fill="#dbeafe" stroke="#3b82f6"/>
  <text x="386" y="84" text-anchor="middle" font-size="14" font-weight="700" fill="#1e40af">VPS(公网)</text>
  <rect x="308" y="96" width="156" height="36" rx="6" fill="#3b82f6"/>
  <text x="386" y="112" text-anchor="middle" font-size="11" font-weight="700" fill="#ffffff">rathole-server</text>
  <text x="386" y="126" text-anchor="middle" font-size="10" fill="#dbeafe">:2333 隧道口</text>
  <rect x="308" y="140" width="156" height="30" rx="5" fill="#ffffff"/>
  <text x="386" y="159" text-anchor="middle" font-size="11" fill="#475569">127.0.0.1:13000+</text>
  <rect x="308" y="178" width="156" height="36" rx="6" fill="#2563eb"/>
  <text x="386" y="194" text-anchor="middle" font-size="11" font-weight="700" fill="#ffffff">Caddy</text>
  <text x="386" y="208" text-anchor="middle" font-size="10" fill="#dbeafe">TLS 终止 · 反代</text>
  <!-- arrow -->
  <line x1="480" y1="196" x2="540" y2="196" stroke="#475569" stroke-width="2" marker-end="url(#rah)"/>
  <text x="510" y="220" text-anchor="middle" font-size="10" fill="#64748b">HTTPS</text>
  <!-- Internet -->
  <rect x="548" y="160" width="136" height="72" rx="10" fill="#dcfce7" stroke="#22c55e"/>
  <text x="616" y="190" text-anchor="middle" font-size="13" font-weight="700" fill="#166534">公网用户</text>
  <text x="616" y="210" text-anchor="middle" font-size="11" fill="#15803d">https://doc.liz6.com</text>
  <!-- bottom note -->
  <rect x="120" y="260" width="480" height="28" rx="6" fill="#f1f5f9"/>
  <text x="360" y="279" text-anchor="middle" font-size="11" fill="#475569">rathole 只做 TCP 端口转发,不解析 TLS;TLS 证书由 Caddy 在 VPS 侧全自动管理。</text>
</svg>

角色分工很清晰:

- **rathole-client**(家里,Docker + host 网络):连到 VPS 的 server,把家里 `127.0.0.1:3000` 映射为 VPS 上的 `127.0.0.1:13000`。
- **rathole-server**(VPS,Docker + host 网络):监听 `:2333`,接收 client 连接,按配置把各服务 bind 到本机端口。
- **Caddy**(VPS,裸机):对外监听 443,按域名反代到 rathole-server 的对应端口;TLS 证书全自动。

家里服务全部只绑 `127.0.0.1`,不经 rathole 隧道无法从外部访问——这是纵深防御里的"最小暴露面"。

## 三、搭起来:从零到公网可访问

### 3.1 VPS 侧:rathole-server + Caddy

两台机器的 rathole 都跑 Docker,用 host 网络(容器内 `127.0.0.1` = 宿主机)。先写 server.toml:

```toml
# VPS: /opt/rathole/server.toml
[server]
bind_addr = "0.0.0.0:2333"         # client 连这个口

[server.transport]
type = "tcp"

[server.services.grafana]
token = "<生成一个随机 token>"     # client 也要配同样 token
bind_addr = "127.0.0.1:13000"      # 只给 Caddy 反代,不暴露公网

[server.services.doc]
token = "<随机 token>"
bind_addr = "127.0.0.1:13002"

# SSH 不走 Caddy,直接 bind 0.0.0.0:
[server.services.homessh]
token = "<随机 token>"
bind_addr = "0.0.0.0:30022"

# 其余服务: openwebui→13001, paste→13003, caldav→13004, OTLP→9443(同上格式)
```

```yaml
# VPS: /opt/rathole/docker-compose.yml
services:
  rathole:
    image: rapiz1/rathole:latest
    container_name: rathole-server
    restart: unless-stopped
    network_mode: host
    command: ["--server", "/config/server.toml"]
    volumes:
      - ./server.toml:/config/server.toml:ro
```

然后 Caddy 反代(在 VPS 上裸机跑):

```caddyfile
# /etc/caddy/Caddyfile
grafana.liz6.com {
    reverse_proxy 127.0.0.1:13000
}
doc.liz6.com {
    reverse_proxy 127.0.0.1:13002
}
```

Caddy 会自动去 Let's Encrypt 签 TLS 证书——如果 VPS 有独立公网 IP 且 80/443 端口可达。不行的话,见 3.3 节证书策略。

### 3.2 家里侧:rathole-client

```toml
# 家里: /opt/rathole-home/client.toml
[client]
remote_addr = "<VPS 公网 IP>:2333"

[client.transport]
type = "tcp"

[client.transport.tcp]
keepalive_secs = 10           # 保活心跳,对抗 NAT/conntrack 掐连接
keepalive_interval = 5
nodelay = true

[client.services.grafana]
token = "<和 server.toml 同样的 token>"
local_addr = "127.0.0.1:3000"

[client.services.doc]
token = "<和 server.toml 同样的 token>"
local_addr = "127.0.0.1:8090"
```

```yaml
# 家里: /opt/rathole-home/docker-compose.yml
services:
  rathole:
    image: rapiz1/rathole:latest
    container_name: rathole-client
    restart: unless-stopped
    network_mode: host
    command: ["--client", "/config/client.toml"]
    volumes:
      - ./client.toml:/config/client.toml:ro
```

`network_mode: host` 让容器直接访问宿主机的 `127.0.0.1:3000` 等端口——所有家里服务绑 localhost 即可,无需额外暴露给 Docker 网桥。

### 3.3 证书策略:两个场景

**场景 A:VPS 有独立公网 IP(推荐)。** Caddy 的 `tls` 块留空就行,全自动 Let's Encrypt。这是当前本机主力配置。

**场景 B:NAT VPS,公网 80/443 不可用。** 共享 IP NAT 且境外不通(连不上 Let's Encrypt)时:

1. 家里跑 `acme.sh`,用阿里云 DNS-01 签通配符 `*.liz6.com`(ACME 请求经代理出国,DNS API 走国内直连)。
2. `--install-cert --reloadcmd` 自动 scp 证书到 VPS + reload Caddy。
3. VPS 上 Caddy 用静态证书(不走自动 LE),URL 带 NAT 高位端口后缀。

能从场景 B 切到场景 A 时,URL 去掉端口后缀,acme.sh 通配证书仅保留给 DERP 等无法走 LE 的场景。能用标准 443 + Caddy 自动 LE 就尽量用,少一个手动环节少一个故障面。

## 四、踩坑:这三个坑全踩过一遍

### 4.1 HTTP/3 的 alt-svc 端口对不上

Caddy 默认开启 HTTP/3(QUIC)。HTTP/3 靠 `alt-svc` 响应头告诉浏览器"下次走 QUIC,端口是 X"。但 **Caddy 只知道自己监听在哪个口**,不知道外面有没有 NAT 转发。

如果公网端口 ≠ Caddy 监听端口(场景 B 的 NAT 高位口),`alt-svc` 里写的端口就错了——浏览器收到错误的 QUIC 端口号,尝试连接失败,页面打不开。

**现象**:Open WebUI 在场景 B 下莫名其妙打不开;`curl` 正常(走 HTTP/1.1),浏览器不行(尝试 QUIC)。**排查**:浏览器 DevTools → Network,看是否卡在 `h3` 请求上。

**修法**:关掉 Caddy 的 h3——`servers { protocols h1 h2 }`。切回标准 443(场景 A)后,确保 Caddy 对外端口 = 监听端口(都是 443),可重新打开 h3。如果 Caddy 前面有反向代理或 NAT 端口映射,需要 `header_up` 或 `header_down` 手动修正 `alt-svc`。

**残留坑**:浏览器会缓存 `alt-svc` 最长 30 天(HSTS 也会影响),修完后用无痕窗口或用 DevTools → Application → Clear site data 验证。

### 4.2 Early EOF:conntrack 掐空闲连接

CGNAT ↔ 共享 IP NAT 跨网链路上,rathole 日志每 ~10 分钟刷 `Failed to read cmd: early eof`——控制通道(长连接,平时基本没流量)被中间 conntrack 当 idle 清理了。

**这个不是 rathole 的问题。** 裸 TCP 隧道(frp 同理)在这类链路上都吃这个——连接空闲太久,中间 NAT 网关的 conntrack 表项到期被清,下次通信时 TCP 直接 reset。

**修法**(两个手段,各管各的):
1. **TCP keepalive**(保活):client.toml 设 `keepalive_secs=10 / keepalive_interval=5`——rathole 连接都是 client 主动发起,只改 client 端即可覆盖控制和数据通道。
2. **Watchdog 兜底**(见第五节):keepalive 只是降低概率,极端链路仍会断;watchdog 断连后自动重启恢复。

### 4.3 大坑:本机 TUN 代理劫持了隧道传输

这三个里藏得最深的一个。

**现象**:VPS 是独立公网(ICMP 0 丢包、延迟稳),keepalive 也开了,但 rathole **照样稳态超时**——24h 约 470 次 timeout、控制通道每 ~7min 重建。更诡异的是:用得越少的服务超时越多(上百次),高频的 grafana 才个位数。

**排查过程——常规手段在 TUN 代理环境下会骗你:**

先用 `curl` / `nc` 测 VPS 连通性 → 全通。后来才发现:**在开着 TUN 代理(mihomo)的机器上,`curl` 的 TCP 握手会被 TUN 在本地截住假应答**,连一个 VPS 上根本没监听的端口也"成功"。VPS 端 `tcpdump` 抓不到任何包,家里这边却说通了。

通往真相的排查路径:

1. `ip route get <VPS_IP>` → `via 198.18.0.2 dev Meta`——到 VPS 的流量全部穿 TUN。
2. 用 `curl -v` 连 VPS 上一个**确定关闭的端口**(如 9999),如果"成功" = TUN 假应答;如果被拒绝 = 真的到了 VPS。
3. VPS 上 `tcpdump -i eth0 tcp port 2333` 抓包——**注意不能用 `-i any`**,它用 cooked 伪链路头会导致 `tcp[tcpflags]` 字节偏移过滤静默零匹配。

**根因**:家里机器自己跑着 mihomo TUN,做了 `auto-route` + `strict-route`,接管了整机出向流量。rathole 到 VPS 的连接被塞进 mihomo 的 TUN 数据面——虽然分流规则判为 `DIRECT`(不挂代理节点),但 `DIRECT` 只表示"不走代理出口",**连接本身仍然穿 TUN 用户态栈**。mihomo 的空闲连接回收/reload 会掐掉 rathole 预建连接池里的 data channel = 超时。

本质和 4.2 节 Early EOF 同一类(idle 连接被回收),只是元凶从运营商 NAT 换成了本机代理。

<svg viewBox="0 0 720 250" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="TUN 劫持隧道传输的根因">
  <defs><marker id="tunah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#ef4444"/></marker></defs>
  <rect width="720" height="250" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">TUN 劫持:rathole 到 VPS 的连接被本机 mihomo TUN 截住再掐</text>
  <!-- wrong path -->
  <text x="80" y="64" font-size="13" font-weight="700" fill="#dc2626">修复前(错误路径)</text>
  <rect x="36" y="76" width="100" height="36" rx="6" fill="#fef2f2"/>
  <text x="86" y="99" text-anchor="middle" font-size="11" font-weight="600" fill="#991b1b">rathole</text>
  <line x1="140" y1="94" x2="210" y2="94" stroke="#ef4444" stroke-width="1.8" marker-end="url(#tunah)"/>
  <rect x="214" y="76" width="130" height="36" rx="6" fill="#fecaca"/>
  <text x="279" y="92" text-anchor="middle" font-size="11" font-weight="600" fill="#991b1b">mihomo TUN</text>
  <text x="279" y="106" text-anchor="middle" font-size="10" fill="#dc2626">198.18.0.2</text>
  <line x1="348" y1="94" x2="418" y2="94" stroke="#ef4444" stroke-width="1.8" marker-end="url(#tunah)"/>
  <rect x="422" y="76" width="100" height="36" rx="6" fill="#fef2f2"/>
  <text x="472" y="99" text-anchor="middle" font-size="11" font-weight="600" fill="#991b1b">VPS</text>
  <text x="279" y="132" text-anchor="middle" font-size="11" fill="#dc2626">"DIRECT" ≠ 绕过 TUN,连接仍被 mihomo 管</text>
  <!-- correct path -->
  <text x="80" y="170" font-size="13" font-weight="700" fill="#16a34a">修复后(正确路径)</text>
  <rect x="36" y="182" width="100" height="36" rx="6" fill="#f0fdf4"/>
  <text x="86" y="205" text-anchor="middle" font-size="11" font-weight="600" fill="#166534">rathole</text>
  <line x1="140" y1="200" x2="452" y2="200" stroke="#22c55e" stroke-width="2.2"/>
  <rect x="422" y="182" width="100" height="36" rx="6" fill="#f0fdf4"/>
  <text x="472" y="205" text-anchor="middle" font-size="11" font-weight="600" fill="#166534">VPS</text>
  <text x="296" y="198" text-anchor="middle" font-size="11" font-weight="700" fill="#166534">内核直连(wlp9s0)</text>
  <text x="296" y="234" text-anchor="middle" font-size="11" fill="#16a34a">路由排除:TUN 不再碰这个 IP</text>
</svg>

**修法**:把 VPS IP 写进 mihomo 的 TUN 路由排除列表,让它走内核直连、彻底绕开代理:

```yaml
# mihomo config.yaml
tun:
  inet4-route-exclude-address:
    - 1.117.75.80/32   # rathole VPS, 绕开本机 mihomo TUN
```

`systemctl restart mihomo` 后 `ip route get <VPS_IP>` 应变成 `via 192.168.31.1 dev wlp9s0`(原生路由),再 `docker restart rathole-client` 让连接重建走直连。改后连续静默 5 分钟零 timeout、8/8 服务在线——之前是每 7 分钟必断。

> **通用原则**:隧道 / VPN 的承载连接(transport)永远不要再穿另一层本机 TUN 代理——既多一层故障面,又会被代理的连接生命周期管理误伤。承载连接必须走原生路由。这个原则对 rathole、frp、WireGuard、Tailscale、ZeroTier 等所有需要长连接的隧道方案都适用。

## 五、监控:隧道挂了怎么知道

隧道是基础设施,挂了影响所有服务。两个层次:

**① 健康检查 + 自动恢复(watchdog)。** 一个简单的 bash 脚本,用 systemd timer 每 5 分钟跑一次:

```bash
#!/bin/bash
# /usr/local/bin/rathole-watchdog
ENDPOINT="http://127.0.0.1:13002/health"   # 经 rathole 隧道打 VPS 上 doc 服务的健康端点
MAX_FAILS=3                                  # 连续失败 3 次才判定为挂(防抖动)
FAIL_FILE=/tmp/rathole-watchdog-fails

curl -s --connect-timeout 5 --max-time 5 "$ENDPOINT" > /dev/null
if [ $? -ne 0 ]; then
    fails=$(($(cat $FAIL_FILE 2>/dev/null || echo 0) + 1))
    echo $fails > $FAIL_FILE
    if [ $fails -ge $MAX_FAILS ]; then
        docker restart rathole-client
        rm -f $FAIL_FILE
    fi
else
    rm -f $FAIL_FILE
fi
```

**② 监控盲区:单个业务通道卡死。** watchdog 只探了一个端口(本机探 doc 的 13002),如果**其他隧道通道**卡了(比如 grafana 的 13000),watchdog 看不见——rathole 的控制通道还活着,健康端点也通,但某条数据通道在一轮网络抖动后不自愈。

真实案例:doc.liz6.com 挂了数小时——TLS/证书正常,但 rathole 的 doc 数据通道在一次网络抖动后卡死,其余 5 条隧道全好。`docker restart rathole-client` 强制全通道重连才恢复。

**教训**:watchdog 应增探至少两个业务端口(如 doc + grafana),不能只探一个。理想状态下,如果 rathole 或后续替代方案支持 per-service 重连,应针对性只重启卡死的通道,而不是重启整个 client(会踢掉所有连接的 SSH 会话)。

## 六、安全加固

- VPS sshd:`PasswordAuthentication no`,仅密钥登录。
- rathole 所有 bind 默认 `127.0.0.1`;只有 SSH 隧道因不走 Caddy 绑了 `0.0.0.0:30022`,加 TOTP 2FA(`google-authenticator` PAM)。
- Caddy 只反代 rathole 隧道口,不直接暴露家里端口。
- 敏感链路(如 OTLP metrics)额外套 mTLS——Caddy 验证客户端证书 + 吊销检查,隧道只透传密文。
- VPS 侧用 `ufw` 或 `iptables` 限制 rathole 端口(`:2333`)仅允许家里 IP 连接;IP 会变的话至少限制 SSH 端口(`:30022`)的爆破尝试(fail2ban)。
- rathole token 用 `openssl rand -hex 24` 生成强随机值,不要多服务共用同一个 token。
- Docker `network_mode: host` 意味着容器能直接访问宿主机所有端口——仅限可信网络使用,rathole-server 和 rathole-client 都应在受控机器上跑。

## 七、完整配置

### VPS:server.toml + docker-compose.yml

```toml
# /opt/rathole/server.toml
[server]
bind_addr = "0.0.0.0:2333"

[server.transport]
type = "tcp"

[server.services.grafana]
token = "<随机 token>"
bind_addr = "127.0.0.1:13000"

[server.services.doc]
token = "<随机 token>"
bind_addr = "127.0.0.1:13002"

# SSH 不走 Caddy,直接暴露 0.0.0.0
[server.services.homessh]
token = "<随机 token>"
bind_addr = "0.0.0.0:30022"
```

```yaml
# /opt/rathole/docker-compose.yml
services:
  rathole:
    image: rapiz1/rathole:latest
    container_name: rathole-server
    restart: unless-stopped
    network_mode: host
    command: ["--server", "/config/server.toml"]
    volumes:
      - ./server.toml:/config/server.toml:ro
```

### VPS:Caddyfile(示例,按需加路由)

```caddyfile
grafana.liz6.com {
    reverse_proxy 127.0.0.1:13000
}
doc.liz6.com {
    reverse_proxy 127.0.0.1:13002
}
```

### 家里:client.toml + docker-compose.yml + watchdog

```toml
# /opt/rathole-home/client.toml
[client]
remote_addr = "<VPS IP>:2333"

[client.transport]
type = "tcp"

[client.transport.tcp]
keepalive_secs = 10
keepalive_interval = 5
nodelay = true

[client.services.grafana]
token = "<和 server.toml 一致>"
local_addr = "127.0.0.1:3000"

[client.services.doc]
token = "<和 server.toml 一致>"
local_addr = "127.0.0.1:8090"
```

```yaml
# /opt/rathole-home/docker-compose.yml
services:
  rathole:
    image: rapiz1/rathole:latest
    container_name: rathole-client
    restart: unless-stopped
    network_mode: host
    command: ["--client", "/config/client.toml"]
    volumes:
      - ./client.toml:/config/client.toml:ro
```

```bash
# /usr/local/bin/rathole-watchdog(完整版见第五节)
```

配 systemd timer 每 5 分钟触发:

```ini
# ~/.config/systemd/user/rathole-watchdog.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/rathole-watchdog

# ~/.config/systemd/user/rathole-watchdog.timer
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target
```

## 相关文档

- [network-architecture.md](network-architecture.md) — 拓扑总览
- [network-recovery.md](network-recovery.md) — 故障恢复
- [monitoring.md](monitoring.md) — 监控架构
