利用 FRP 与 WireGuard 构建低成本虚拟专线:实现公网 IP 访问内网 NAS
背景与挑战
作为一名计算机爱好者,我家中搭建了 NAS 系统用于数据存储和各类服务。然而,当我想通过公网访问家中 NAS 时,遇到了一个常见问题:运营商不再提供公网 IP 地址,只分配内网 IP。
最初我尝试了 FRP(Fast Reverse Proxy)内网穿透方案,虽然能够实现基本的访问功能,但存在一个严重缺陷:所有数据包的源 IP 地址都变成了 FRP 服务器的内网 IP,这导致我无法获取真实的客户端信息,也影响了一些基于 IP 的安全验证。
解决方案演进
第一代方案:纯 FRP
- 优点:简单易用,实现基本穿透
- 缺点:丢失源 IP 信息,无法满足高级需求
第二代方案:纯 WireGuard
- 优点:保留源 IP,性能优秀
- 缺点:运营商对 WireGuard 流量进行 QoS 限速
最终方案:FRP + WireGuard 混合架构
结合两者优势,使用 FRP 封装 WireGuard 隧道,既解决了 NAT 穿透问题,又避免了 QoS 限制,同时完美保留源 IP 地址。
系统架构设计
完整的网络路径为:
[Internet] → [VPS(FRP + WireGuard + NAT)] → [FreeBSD 路由器(FRP + WireGuard + 策略路由)] → [家庭 NAS]核心组件说明
VPS 端配置:
- 运行 FRP 服务端和 WireGuard
- 开启 NAT 转发,将端口映射到家庭 NAS
- 作为公网入口点
FreeBSD 路由器配置:
- PPPoE 拨号连接家庭宽带
- 双路由表设计(主路由表 + WireGuard 路由表)
- IPFW 防火墙实现策略转发
- 智能路由:NAS 流量走隧道,其他设备走正常宽带
关键技术实现
1. WireGuard 服务管理脚本
以下是 FreeBSD 上的 WireGuard 服务脚本,支持多接口和管理操作:
#!/bin/sh
# PROVIDE: wireguard
# REQUIRE: NETWORKING
# KEYWORD: shutdown
. /etc/rc.subr
name=wireguard
rcvar=wireguard_enable
extra_commands="reload status"
start_cmd="${name}_start"
stop_cmd="${name}_stop"
reload_cmd="${name}_reload"
status_cmd="${name}_status"
wireguard_start()
{
${wireguard_env:+eval export $wireguard_env}
for interface in ${wireguard_interfaces}; do
setfib 1 /usr/local/bin/wg-quick up ${interface}
done
}
wireguard_stop()
{
for interface in ${wireguard_interfaces}; do
setfib 1 /usr/local/bin/wg-quick down ${interface}
done
}
wireguard_reload()
{
${wireguard_env:+eval export $wireguard_env}
for interface in ${wireguard_interfaces}; do
tmpfile="`mktemp`"
setfib 1 /usr/local/bin/wg-quick strip ${interface} > ${tmpfile}
setfib 1 /usr/local/bin/wg syncconf ${interface} ${tmpfile}
rm -f ${tmpfile}
done
}
wireguard_status()
{
${wireguard_env:+eval export $wireguard_env}
wireguard_status="0"
for interface in ${wireguard_interfaces}; do
setfib 1 /usr/local/bin/wg show ${interface} || wireguard_status="1"
done
return ${wireguard_status}
}
load_rc_config $name
: ${wireguard_enable="NO"}
: ${wireguard_interfaces=""}
: ${wireguard_env=""}
run_rc_command "$1"2. 策略路由配置
关键配置要点:
- 使用
setfib 1在特定 FIB(路由表)中运行 WireGuard(代码如上) - 主路由表(FIB 0)处理普通流量
- 副路由表(FIB 1)专门处理 WireGuard 隧道流量
- IPFW 规则将 NAS 流量重定向到 WireGuard 接口
3. 双向流量保障
请求路径: Internet → VPS → WireGuard 隧道 → FreeBSD 路由器 → NAS
响应路径: NAS → FreeBSD 路由器(自动选择 WireGuard 路由)→ WireGuard 隧道 → VPS → Internet
解决的问题
源 IP 地址保留
- WireGuard 的隧道特性保持原始源 IP 不变
- 克服了 FRP 代理模式丢失源 IP 的问题
对称路由(路径一致性)
- 响应数据包通过原 WireGuard 隧道返回
- 避免非对称路由导致的连接问题
公网可达性
- 通过 VPS 的公网 IP 提供访问入口
- 成本远低于商业专线方案
规避 QoS 限制
- FRP 外层封装避免运营商识别 WireGuard 流量
- 保持隧道稳定性和性能
方案优势
成本效益
- VPS 月费仅需 5-10 美元
- 无需申请昂贵的商业专线
- 利用现有家庭网络设备
技术优势
- 完整的端到端加密(WireGuard)
- 高性能隧道传输
- 灵活的流量控制策略
- 易于维护和扩展
适用场景
- 家庭 NAS 远程访问
- 自建服务公网发布
- 远程办公网络接入
- 跨地域网络互联
经验总结
这个方案成功地将复杂的网络技术组合应用,解决了实际需求。关键在于理解不同工具的特性和如何协同工作:
- FRP 擅长穿透 NAT,但会修改数据包
- WireGuard 提供纯净隧道,但容易被 QoS
- 策略路由 确保流量按预期路径传输
- FreeBSD 网络栈 提供强大的路由和防火墙能力
通过这种分层设计,我们以极低的成本实现了相当于商业专线的效果,为家庭用户和小型企业提供了可行的公网访问解决方案。
这个方案已经稳定运行多月,证明了其在实际环境中的可靠性和实用性。希望这个经验分享能够帮助遇到类似问题的技术爱好者。