前言
本文记录了我在 NEC 8代小主机上折腾 PVE 的过程,也希望能为想搭建类似内外网环境的朋友提供一些思路
需求
使用 vconet.top 这个我拥有的域名,给本地服务都用上 SSL、同时异地组网 实现在外访问本地服务,还需要把一些服务公布到互联网上
与此同时,还要保证在各个网络环境下都能保持一致的 URL
配置 PVE
PVE 的安装和基本配置教程网上有很多,不再复述
NAT!
出于种种原因,我在 PVE 上额外划分了一个 10.22.33.0/24 网段,用于虚拟机和 LXC 容器
配置 SDN
创建 Simple 区域
转到 数据中心 ➡️ SDN ➡️ 区域 ➡️ 添加 ➡️ Simple
填一个名称,勾选高级并启用自动 DHCP

创建 VNets
转到 数据中心 ➡️ SDN ➡️ VNets ➡️ 创建
填写名称和区(刚才创建的 Simple 名称)

创建子网
在 VNets 右边的子网创建新子网,填写子网网段和网关,在 DHCP 范围选项卡内填写 DHCP 的 IP 范围


应用更改
转到 数据中心 ➡️ SDN,点击左上角的应用
启用 DHCP
要使 PVE 能真正的提供 DHCP 服务,需要在 PVE 上安装 dnsmasq 并禁用自带的服务
1 | apt install dnsmasq |
自定义 DNS
因为内外网的 DNS 记录不一样,需要给
10.22.33.0/24网段内的虚拟机和 LXC 提供自定义的 DNS 服务器,我将会在下文给出的 Co re + Powerdns 方案
为了让 dnsmasq 能在提供 DHCP 的同时,提供 自定义 DNS,需要编辑 /etc/pve/sdn/subnets.cfg 文件,添加 dhcp-dns-server 选项
1 | subnet: pvenet-10.22.33.0-24 |
防火墙
目前我并没有防火墙的需求,暂时跳过
内网域名解析
为了提供 vconet.top 等 TLD 域名的内部解析,需要一个自己的 DNS 服务器,同时还要方便维护
可以实现上面需求的,可选方案有很多:CoreDNS(两种方案)、Powerdns、TechnitiumDNS,甚至 小米路由器自带的 自定义 Hosts 功能也能满足需求
自定义 DNS 怎么选?
简单记录
如果你只需要简单的 xx.vconet.top对应 ip,那么大可选择小米路由器自带的 自定义 Hosts 功能,亦或是 CoreDNS(方案一)
该方案用到 CoreDNS的 hosts功能:
1 | .:53 { |
复杂记录
如果不仅仅需要 A 记录,还需要 PTR、MX 等,就需要 CoreDNS(方案二)、Powerdns、Technitiumdns 这些权威 DNS 了
CoreDNS(方案二)需要用到 CoreDNS 的 file功能:
1 | . { |
Powerdns、Technitiumdns 有对应的 Web 管理页面,直接添加就可
如果选择权威 DNS 给
vconet.top做解析,且如果本地 DNS 的记录不全,解析时会返回 NXDOMAIN
权威 DNS 在查询到不存在的记录时,会直接返回 NXDOMAIN,而不会继续向上递归查询,这可能导致内外网记录解析失败:
flowchart LR
ldns --本地IP--> id1[Client]
id1 --"local.vconet.top(存在于本地DNS)"-->ldns["本地 DNS"]
ldns--NXDOMAIN-->id2[Client]
id2 --"blog.vconet.top(不存在于本地)"--> ldns
ldns x--"向上查找blog.xx"--x rdns["公共 DNS"]
解决 NXDOMAIN
对于 Technitiumdns,你可以在创建新域名的时候,选择
条件转发对于 CoreDNS(方案二),需要自己编译含有
alternate插件的 CoreDNS:1
2
3
4
5
6vconet.top {
file /etc/CoreDNS/DOMAIN.zone #域名的Zone文件
alternate NXDOMAIN . 223.5.5.5 119.29.29.29
log
errors
}
我的方案
因需要给 PVE 提供 DNS 相关服务,只能选择 Powerdns 解析内网记录,而 Powerdns 本身只用能作权威 DNS,还需要搭配 powerdns-recurosr 之类的前置
但 recursor 并不能非常方便的解决上面 NXDOMAIN 的问题,因此我选择 CoreDNS 而非 powerdns-recursor
CoreDNS 配置:
1 | #################### |
Powerdns 配置:
1 | # 在 /etc/powerdns/pdns.conf 下追加下面这一段 |
请把api-key、local-port、webserver-port修改为自己所需的值
打通内外网
在这一部分开始之前,我需要介绍一下我的网络拓展:
flowchart TD
%% ISP 到家庭网络
ISP((ISP))
WIFI[小米路由器
192.168.31.0/24]
%% 局域网
NB[笔记本
192.168.31.10]
PVE[PVE 宿主机192.168.31.210]
%% PVE 内部网络
SUBNET1[[内部网络
10.22.33.0/24]]
VM1["虚拟机1(核心)
10.22.33.200"]
VM2["虚拟机2(Docker服务)"]
LXC1["LXC 1"]
LXC2["LXC 2"]
%% ZeroTier 网络
ZT[[ZeroTier 网络
192.168.192.0/24]]
%% 拓扑关系
ISP --> WIFI
WIFI --> NB
WIFI --> PVE
PVE --> SUBNET1
SUBNET1 --> VM1
SUBNET1 --> VM2
SUBNET1 --> LXC1
SUBNET1 --> LXC2
VM1 <--> ZT
本地访问
在前面配置中,我们已经在 NAT 环境下新增了一层虚拟网络
接下来要解决的问题是:如何让 192.168.31.0/24 网段内的设备能够访问 10.22.33.0/24 网段的虚拟机和 LXC 容器?
静态路由
什么是路由?
网络路由是选择一个或多个网络上的路径的过程。路由原理可以应用于从电话网络到公共交通的任何类型的网络。在诸如互联网等数据包交换网络中,路由选择互联网协议 (IP) 数据包从其起点到目的地的路径。这些互联网路由决定由称为路由器的专用网络硬件做出。
为了实现这个需求,需要在自己的路由器里添加一条静态路由:
其目标地址为 10.22.33.0,网关为 PVE 的 IP 192.168.31.210,掩码为 255.255.255.0
小米 AX3000T 在开启 ssh 服务后,编辑 /etc/config/network和防火墙 /etc/config/firewall:
1 | # /etc/config/network |
请自行查找其他路由器添加静态路由的方法
生效后,Linux 效果如下
1 | route -n |
这样我们就实现了 192.168.31.0/24 网段访问 10.22.33.0/24 网段
flowchart LR
id1["笔记本 192.168.31.10"] --"ping 10.22.33.200"---> id2["路由器 192.168.31.1"] --"下一跳192.168.31.210"-->id3["PVE .31.210和.33.1"]
id3 --获得请求--> id4["虚拟机1(核心)10.22.33.200"] ---> id1
异地组网
异地组网可选的方案有很多,常用的有 Tailscale 和 ZeroTier,在此我选择功能更少的 ZeroTier
Tailscale 有很多独特的功能,其中就有内网 HTTPS,但这个功能不够强大,而且和下面配置的 Nginx 反代服务重复了
上面提到,我的 ZeroTier 是安装在 虚拟机1(核心)里的,这就意味着 当我的手机连接到 ZeroTier 后,只能访问 192.168.192.31这个 由 ZT 提供的 IP,并不能访问 10.22.33.0/24 网段
解决问题的办法其实很简单,在 ZT 的后台添加一条新的静态路由,但这次的网关是 ZT 提供给虚拟机1(核心)的 IP

但此时,我们还并不能 ping 通,因为从 ZT 发来的请求,PVE 接收到后并不知道返回的路由
因此需要在 PVE 宿主机上添加一条路由:
目标地址为 192.168.192.0/24 (ZeroTier 的网段),网关为 10.22.33.200(虚拟机 1 的 IP)
添加为系统服务,自动添加和删除
1 | [Unit] |
最后,启用 虚拟机1(核心)的转发功能:
至此,在本地或使用 ZeroTier 时,都可以访问 10.22.33.0/24 网段的设备了
这么做也避免了给同一个域名添加两个不同网段 IP 的麻烦,方便维护
外网访问
当下,直接开放端口非 80/443 端口虽可以实现,但这么做容易暴露自己的 IP
一个解决办法是使用 CDN 回源,但免费版 Cloudflre 的 Origin Rule 只能有三条回源规则,数量有限还需要手动维护 IP 记录
那还有没有什么别的办法呢?
有的。那就是赛博活佛 Cloudflare 的 Zero Trust,Zero Trust 中的隧道 功能可以把内网服务公布到互联网上:

cloudflared 的安装和设置 在创建完隧道后有详细的介绍,不再赘述
各种服务
以下是我在内外网打通后部署的一些服务,属于扩展内容,可按需参考
略去了很多设置过程
基础服务
上文曾多次提到虚拟机1(核心),这台虚拟机承担了我内网环境的 Nginx 反代、DNS 服务器和 ZeroTier 组网
Nginx 反代
我尝试过 Nginx Proxy Manager 的网页管理,但决定手动管理,因其可选项比较少,不能灵活配置
Debian 系统可以直接安装 nginx 包和 nginx-full包
在安装完后,按照下面的反代模板添加配置文件即可:
1 | server { |
我在这里使用8443而非443端口的原因在下面 Forgejo 部分有解释
DNS 服务器与 PVE 整合
在前面,我配置好了 Powerdns,下面是 PVE 启用 DNS 插件,实现自动添加虚拟机解析记录和 PTR 记录的方法
添加 DNS 插件
转到 数据中心 ➡️ SDN ➡️ 选项 ➡️ 添加
填写对应的 Powerdns API 地址和 API 密钥

补全 Simple 的信息
转到 数据中心 ➡️ SDN ➡️ 区域 ➡️ 添加 ➡️ Simple
勾选高级,补全下面的信息
在填写DNS 域之前,请在 powerdns 内创建此域

Docker 服务
使用 Docker 是因为方便更新和管理
自动追番

Emby
Emby 的 docker-compose 如下:
1 | services: |
为了实现 Emby 观看番剧时,自动加载 ass 字幕所需的字体,避免本地安装 需要用到 fontInAss 并使用下面的 Nginx 反代
1 | server { |
下载器
使用 qBittorrentEE 和 PeerBanHelper
PeerBanHelper 用于阻止迅雷等吸血客户端
1 | services: |
ASS自动追番
AniRSS 的使用,请阅读官方文档
Forgejo 反代下同域名 ssh
Git 服务器我选择使用 Gitea 的 fork:Forgejo
Forgejo 的安装 Gitea/Forgejo 都有详细的文档,可自行搜索
在这一节中,我需要解决一个问题:由于 Nginx 反代服务器和 Forgejo 并不在同一台虚拟机上,默认情况下我必须为 SSH 使用不同的域名。
经过探索,我发现可以通过 Nginx 的 stream 模块,在同一域名下根据流量类型分别提供 HTTP 反代和 SSH 反代。
在 nginx.conf的 http 段前添加这样一段:
1 | stream { |
这也是我在前面选择使用 8443 端口的原因
虽然和使用单独的域名比,这个方法略显麻烦,但在此记录这个解决办法

结尾
至此,我的 NEC8 小主机在 PVE 上的内外网打通和基础服务搭建就告一段落了。希望本文能为有类似需求的朋友提供一些参考