利用 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

解决的问题

  1. 源 IP 地址保留

    • WireGuard 的隧道特性保持原始源 IP 不变
    • 克服了 FRP 代理模式丢失源 IP 的问题
  2. 对称路由(路径一致性)

    • 响应数据包通过原 WireGuard 隧道返回
    • 避免非对称路由导致的连接问题
  3. 公网可达性

    • 通过 VPS 的公网 IP 提供访问入口
    • 成本远低于商业专线方案
  4. 规避 QoS 限制

    • FRP 外层封装避免运营商识别 WireGuard 流量
    • 保持隧道稳定性和性能

方案优势

成本效益

  • VPS 月费仅需 5-10 美元
  • 无需申请昂贵的商业专线
  • 利用现有家庭网络设备

技术优势

  • 完整的端到端加密(WireGuard)
  • 高性能隧道传输
  • 灵活的流量控制策略
  • 易于维护和扩展

适用场景

  • 家庭 NAS 远程访问
  • 自建服务公网发布
  • 远程办公网络接入
  • 跨地域网络互联

经验总结

这个方案成功地将复杂的网络技术组合应用,解决了实际需求。关键在于理解不同工具的特性和如何协同工作:

  • FRP 擅长穿透 NAT,但会修改数据包
  • WireGuard 提供纯净隧道,但容易被 QoS
  • 策略路由 确保流量按预期路径传输
  • FreeBSD 网络栈 提供强大的路由和防火墙能力

通过这种分层设计,我们以极低的成本实现了相当于商业专线的效果,为家庭用户和小型企业提供了可行的公网访问解决方案。

这个方案已经稳定运行多月,证明了其在实际环境中的可靠性和实用性。希望这个经验分享能够帮助遇到类似问题的技术爱好者。

本文链接:

https://www.abo.moe/archives/29.html
1 + 2 =
快来做第一个评论的人吧~
The Website have been running for 438 days.