<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Eloxt</title><description>关于软件、系统与手艺的笔记。</description><link>https://eloxt.com/</link><language>zh-CN</language><item><title>Homelab 网络结构总结</title><link>https://eloxt.com/blog/homelab-network/</link><guid isPermaLink="true">https://eloxt.com/blog/homelab-network/</guid><description>基于 PVE、RouterOS、Tailscale、Traefik 与 Caddy 构建兼顾安全、隐私与自动化的 Homelab 网络架构</description><pubDate>Fri, 23 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;aside&gt;&lt;p&gt;说明&lt;/p&gt;本文经人工撰写，AI 润色，再人工改写，图也是 AI 画的。&lt;/aside&gt;
&lt;p&gt;最开始我是把所有服务都部署在云服务器上的，除了费钱，其实省心省力没啥毛病。后来跑的服务越来越多、越来越重，手头刚好又有了闲置的机器，索性就把服务全部迁回了本地 Homelab，云服务器退居二线，只负责对外访问的网络中转。毕竟在云端兜里掏空撑死了也就买得起 4C6G 这种入门配置，而搬回家里不仅能轻松拉到 8C16G 甚至更高，后续升级硬盘和内存也是丰俭由人。&lt;/p&gt;
&lt;h2&gt;硬件设备&lt;/h2&gt;
&lt;p&gt;盘点一下硬件阵容，可以说是相当“勤俭持家”了：2022 年买的 J4125 工控机服役至今，笔记本也是公司淘汰下来的二手旧设备，核心诉求就是省电与省钱。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;设备&lt;/th&gt;
&lt;th&gt;数量&lt;/th&gt;
&lt;th&gt;CPU&lt;/th&gt;
&lt;th&gt;内存&lt;/th&gt;
&lt;th&gt;网口&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;J4125 工控机&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;J4125&lt;/td&gt;
&lt;td&gt;8G&lt;/td&gt;
&lt;td&gt;2.5G Ethernet × 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;笔记本电脑&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;i5-1135G7&lt;/td&gt;
&lt;td&gt;8G × 2&lt;/td&gt;
&lt;td&gt;1G Ethernet × 1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;外加一台腾讯云轻量锐驰型服务器（大峰值带宽、不限流量套餐），专门充当所有对外访问的前置代理。&lt;/p&gt;
&lt;h2&gt;软件环境&lt;/h2&gt;
&lt;p&gt;两台物理机均使用 Proxmox Virtual Environment (PVE) 搭建虚拟化平台。部署原则也很明确：&lt;strong&gt;除了必须独立内核或系统形态限制只能以虚拟机（VM）安装的服务，其余一律优先使用资源开销极低的 LXC 容器部署&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;两台机器的分工如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;J4125 工控机&lt;/strong&gt;：主攻网络基础设施，负责软路由、透明代理以及轻量级的常驻网络服务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notebook 笔记本&lt;/strong&gt;：承担数据库、缓存、NAS 以及主力 Docker 应用容器等较重的负载。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;主机&lt;/th&gt;
&lt;th&gt;服务&lt;/th&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;IP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;J4125 PVE&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;10.1.1.254&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;RouterOS&lt;/td&gt;
&lt;td&gt;VM&lt;/td&gt;
&lt;td&gt;10.1.1.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;sing-box&lt;/td&gt;
&lt;td&gt;LXC&lt;/td&gt;
&lt;td&gt;10.1.1.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;td&gt;LXC&lt;/td&gt;
&lt;td&gt;10.1.1.100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Tailscale&lt;/td&gt;
&lt;td&gt;LXC&lt;/td&gt;
&lt;td&gt;10.1.1.101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notebook PVE&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;10.1.1.253&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;LXC&lt;/td&gt;
&lt;td&gt;10.1.1.201&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Valkey&lt;/td&gt;
&lt;td&gt;LXC&lt;/td&gt;
&lt;td&gt;10.1.1.202&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Home Assistant OS&lt;/td&gt;
&lt;td&gt;VM&lt;/td&gt;
&lt;td&gt;10.1.1.252&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;飞牛 (fnOS)&lt;/td&gt;
&lt;td&gt;VM&lt;/td&gt;
&lt;td&gt;10.1.1.250&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;td&gt;LXC&lt;/td&gt;
&lt;td&gt;10.1.1.200&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;网络拓扑&lt;/h2&gt;
&lt;p&gt;整体拓扑结构十分清晰直观：J4125 板载的 4 个 2.5G 物理网口在 PVE 底层分别对应一个 Linux 虚拟网桥（&lt;code&gt;vmbr0&lt;/code&gt; ～ &lt;code&gt;vmbr3&lt;/code&gt;），全部桥接给 RouterOS 虚拟机进行统一纳管。其中 &lt;code&gt;vmbr0&lt;/code&gt; 作为 WAN 口承接光猫拨号，其余 3 个作为 LAN 口组网；笔记本则通过千兆网口直连工控机的其中一个物理 LAN 口。&lt;/p&gt;
&lt;figure&gt;&lt;div&gt;J4125 PVE 10.1.1.254RouterOSVM 10.1.1.1vmbr0eth0 WANvmbr1eth1 LANvmbr2eth2 LANvmbr3eth3 LANsing-boxLXC 10.1.1.2DockerLXC 10.1.1.100tailscaleLXC 10.1.1.101Internet腾讯云锐驰代理Notebook PVE 10.1.1.253PostgreSQLLXC 10.1.1.201ValkeyLXC 10.1.1.202Home AssistantVM 10.1.1.252飞牛VM 10.1.1.250DockerLXC 10.1.1.200&lt;/div&gt;&lt;/figure&gt;
&lt;h2&gt;外网访问&lt;/h2&gt;
&lt;p&gt;我家的宽带是有公网 IP 的，理论上最直接的做法就是在 RouterOS 上配置端口映射配合 DDNS，把需要访问的服务端口逐个丢出去。但实际用起来，有几个让我非常难受的地方。&lt;/p&gt;
&lt;aside&gt;家庭宽带的 80 和 443 端口大概率是被运营商严格封禁的；就算没封，私自开放 Web 服务也非常容易被运营商阻断甚至招致网警排查。&lt;/aside&gt;
&lt;p&gt;首先，我并不想直接对外暴露家宽的真实公网 IP，因为这能被轻易推算出家里的大致地理位置，也容易沦为全网端口扫描的目标。其次，随着服务数量增多，每个服务都得分配并记住一堆杂乱的高位端口。理论上当然也可以在本地起一个 Nginx 或 Caddy 来做反向代理，但在 80/443 被封锁的前提下，对外依然摆脱不了带端口访问的尴尬，真实 IP 也依然处于裸奔状态。最后，三大运营商之间的跨网互联偶尔也会抽风。&lt;/p&gt;
&lt;h3&gt;第一阶段：云端反代 + DDNS 白名单回源&lt;/h3&gt;
&lt;p&gt;为了解决这些痛点，我最初选择在腾讯云服务器上部署 Caddy 来做反向代理，由它来监听公网标准的 80/443 端口并自动申请管理 HTTPS 证书。&lt;/p&gt;
&lt;p&gt;在回源链路上，第一版依然使用 DDNS 和本地端口映射，但&lt;strong&gt;在 RouterOS 的防火墙中严格限制了入站 IP 白名单，只允许腾讯云服务器的固定公网 IP 访问&lt;/strong&gt;。这样既隐藏了家里的真实 IP、统一了访问域名与端口，又杜绝了外部随意扫描本地端口的风险。大致逻辑如图：&lt;/p&gt;
&lt;figure&gt;&lt;div&gt;腾讯云锐驰CaddyHomelab ddns.example.comRouterOS端口映射 来源白名单service1.example.com:8080service1service2.example.com:8081service2service3.example.com:8082service3&lt;/div&gt;&lt;/figure&gt;
&lt;p&gt;但随着服务日常增减，这套方案的维护成本变得不可接受。每次只要新增或调整一个服务，就得经历一套繁琐的连环操作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录 RouterOS 增减 NAT 端口映射；&lt;/li&gt;
&lt;li&gt;登录腾讯云服务器修改 Caddy 配置并 reload；&lt;/li&gt;
&lt;li&gt;在 DNS 解析后台增减子域名的 A 记录；&lt;/li&gt;
&lt;li&gt;本地启动服务容器。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;“部署 5 分钟，配网半小时”，极其折腾。所以我又进行了一次改造。&lt;/p&gt;
&lt;h3&gt;第二阶段：全链路自动化改造&lt;/h3&gt;
&lt;p&gt;首先是&lt;strong&gt;域名解析&lt;/strong&gt;：直接在 DNS 服务商处配置一条泛域名解析（&lt;code&gt;*.example.com&lt;/code&gt;）指向腾讯云服务器的公网 IP，一劳永逸，以后再添新服务无需频繁操作 DNS。&lt;/p&gt;
&lt;p&gt;其次是&lt;strong&gt;内网回源通道&lt;/strong&gt;：利用 Tailscale 打通虚拟局域网。在腾讯云上安装 Tailscale 并加入内网网段后，云端即可直接通过内网 IP 与端口访问 Homelab 中的服务，彻底告别 RouterOS 上繁琐的端口映射。虽然 Tailscale 的 WireGuard 封装带来了一丁点性能损耗，但在家宽上行场景下完全可以忽略不计。&lt;/p&gt;
&lt;p&gt;最后是最核心的问题：&lt;strong&gt;反向代理配置该如何全自动感知？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;和 ChatGPT + Gemini 一通左右脑互搏之后，我决定使用 &lt;strong&gt;Traefik + traefik-kop&lt;/strong&gt; 的方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;多机容器感知&lt;/strong&gt;：原生 Traefik 只能监听本地宿主机的 Docker Socket，而我的 Docker 容器分散在两台宿主机的 LXC 容器中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：在两个 Docker LXC 中都部署轻量的 &lt;a href=&quot;https://github.com/jittering/traefik-kop&quot;&gt;traefik-kop&lt;/a&gt;，由它分别监听各自宿主机的 Docker 容器标签（Labels），解析后统一写入共享的 Valkey（兼容 Redis 协议）配置中心。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traefik 统一入口&lt;/strong&gt;：在其中一个 Docker LXC 上部署 Traefik，配置使用 Valkey 作为动态配置源（Provider），从而自动汇聚两台机器上的所有服务路由规则。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;证书管理&lt;/strong&gt;：由内网的 Traefik 通过 DNS-01 验证统一申请并自动续期 &lt;code&gt;*.example.com&lt;/code&gt; 的通配符证书。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样一来，&lt;strong&gt;腾讯云上的 Caddy 彻底卸下了七层反代与证书管理的负担，只需要做纯粹的四层（Layer 4）流量透传&lt;/strong&gt;，所有的七层路由与证书处理全部交由内网的 Traefik 自动化完成。&lt;/p&gt;
&lt;figure&gt;&lt;div&gt;*.example.com腾讯云锐驰Caddy L4Tailscaleproxy_protocol v2HomelabDocker 10.1.1.100Traefikservice1service2Docker 10.1.1.200service3traefik-koptraefik-kopValkeyLXC 10.1.1.202路由配置&lt;/div&gt;&lt;/figure&gt;
&lt;p&gt;不过，由于我在腾讯云上还运行着少量自身的监控服务，且共用了同一个主域名，因此 Caddy 的四层配置需要通过 TLS SNI 做一次分流：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;匹配到 &lt;code&gt;a.example.com&lt;/code&gt; 和 &lt;code&gt;b.example.com&lt;/code&gt; 时，路由至云端本机的 8443 端口处理；&lt;/li&gt;
&lt;li&gt;其余泛域名流量全部通过 Tailscale 内网透传到 Homelab 的 Traefik 443 端口。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里有一点非常关键：&lt;strong&gt;必须开启 &lt;code&gt;proxy_protocol v2&lt;/code&gt;&lt;/strong&gt;，否则四层透传后 Traefik 看到的来源 IP 全是云服务器的内网 IP，开启 PROXY Protocol 协议后 Traefik 才能正确还原出客户端真实的公网 IP。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    layer4 {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        :443 {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            @local_sni tls sni a.example.com b.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            route @local_sni {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                proxy 127.0.0.1:8443&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            @homelab_sni tls sni example.com *.example.com&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            route @homelab_sni {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                proxy 10.1.1.100:443 {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                    proxy_protocol v2&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;a.example.com:8443 {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        reverse_proxy 127.0.0.1:8080&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;b.example.com:8443 {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        reverse_proxy 127.0.0.1:8081&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至此，以后部署新服务时，只需在 &lt;code&gt;docker-compose.yml&lt;/code&gt; 中给容器贴上 Traefik 标签，整套反向代理与域名解析便会全自动生效：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;labels&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  traefik.enable&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;true&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  traefik.http.routers.service-name.rule&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;Host(`a.example.com`)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  traefik.http.services.service-name.loadbalancer.server.port&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;8080&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  traefik.http.routers.service-name.entrypoints&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;websecure&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  traefik.http.routers.service-name.tls&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;true&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  traefik.http.routers.service-name.service&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;service-name&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;DNS 解析与内网回流&lt;/h2&gt;
&lt;p&gt;由于 Traefik 反代与通配符 HTTPS 证书都在局域网内部，这就给我们带来了一个巨大的好处：&lt;strong&gt;实现内网回流（Split-Horizon DNS）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在局域网内部通过公网域名访问服务时，完全没必要让流量白白去腾讯云公网兜上一圈。只需在路由器上配置静态 DNS 解析，将 &lt;code&gt;*.example.com&lt;/code&gt; 直接指向内网 Traefik 所在的服务器 IP（&lt;code&gt;10.1.1.100&lt;/code&gt;）即可。&lt;/p&gt;
&lt;p&gt;同样地，因为腾讯云上还部署了共用该域名的服务，在 RouterOS 中需要通过静态 DNS 正则规则做一次分流：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;属于云端服务的子域名匹配正则后设为 &lt;code&gt;FWD&lt;/code&gt;，正常转发给上游公共 DNS 解析回云服务器；&lt;/li&gt;
&lt;li&gt;其余 Homelab 服务域名全部直接解析为内网 Traefik 的 IP。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;/ip dns static&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;add regexp=&quot;^(a|b|c)[.]example[.]com\$&quot; type=FWD&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;add address=10.1.1.100 regexp=&quot;^[^.]+[.]example[.]com\$&quot; type=A&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样一来，无论身处外网还是内网，访问体验完全一致（同一套域名 + 自动 HTTPS 证书）；而且在内网访问时直接跑在局域网内网带宽上，零延迟、不占公网流量，体验丝滑顺畅。&lt;/p&gt;
&lt;p&gt;其实还有一些关于 Tailscale 组网细节和 sing-box 透明代理的配置考量，篇幅有限，有空再单独写一篇聊聊吧。&lt;/p&gt;</content:encoded></item></channel></rss>