frp+OpenVPN实现内网访问实践

1 问题场景

  1. 电脑A需要访问电脑B上的某个服务,但是电脑A、B在两个不同的网络中,且不具备公网IP、不具备对路由器的修改权限;

  2. 用户C在家想要访问公司内网上的一些资源/机器,但又不想通过RustDesk等远程桌面的形式。

2 技术方案

2.1 frp内网穿透的使用

2.1.1 工具下载

在github相关页面直接下载编译好的可执行文件: https://github.com/fatedier/frp/releases

2.1.2 服务端配置

这里只讲新版配置文件(.toml)的写法,旧版(.ini)差不多,只是一些变量名的区别

bindPort = 7000 #{必选} 客户端与该端口建立连接
kcpBindPort = 7000   # kcp 绑定的是 UDP 端口,可以和 bindPort 一样
log.to = "console" #{可选} 日志配置, 通过打印的方式输出日志
vhostHTTPPort = 7070 #{可选} http代理需要,当访问该端口时跳到对应本地frpc代理
vhostHTTPSPort = 7443 #{可选} https代理需要,当访问该端口时跳到对应本地frpc代理
transport.tcpMux = true #tcp流多路复用(优化传输,客户端与服务端同时配置才有效)

#身份验证
auth.method = "token" #{可选}身份验证方式
auth.token = "abcdefgGHSDSAFDXFW324324321313U90809" #token设置密码,用于通过身份验证创建连接

#frp服务仪表板配置
webServer.port = 8888 #{自行修改端口}
webServer.addr = "0.0.0.0" #公网ip或者0.0.0.0或者域名
webServer.user = "admin" #登录用户名{自行修改}
webServer.password = "admin" #登录密码{自行修改}

2.1.3 客户端配置

serverAddr = "1.1.1.1" #[必选]服务器公网ip地址/域名
serverPort = 7000 # [必选] 要连接的 frps 端口
auth.token = "abcdefgGHSDSAFDXFW324324321313U90809" #与服务端校验的令牌(需一致)
transport.tcpMux = true #tcp流多路复用(优化传输,客户端与服务端同时配置才有效)
transport.protocol = "kcp"  #相比于 TCP,在弱网环境下传输效率提升明显,但是会有一些额外的流量消耗
user = xxx

[[proxies]]
name = "web" # 代理名称(随便填)
type = "tcp" # 代理类型
localIP = "127.0.0.1" # 代理地址, 要转发的那个地址
localPort = 3000 #  代理端口, 要转发的本地的那个端口
remotePort = 8081 # 远程端口(通过公网IP+对应端口访问localPort服务)
transport.useCompression = true  # 对传输内容进行压缩,可以有效减小 frpc 与 frps 之间的网络流量,加快流量转发速度,但是会额外消耗一些 CPU 资源

[[proxies]]
name = "filelink"
type = "tcp"
localIp = "127.0.0.1"
localPort = 4888
remotePort = 9002
transport.useCompression = true 

[[proxies]]
name = "vpn"
type = "udp"
localIp = "127.0.0.1"
localPort = 1194
remotePort =9003
transport.useCompression = true

2.1.4 服务端的端口配置

需要放行的端口有:

  • webServer.port TCP: 管理面板网页访问
  • bindPort TCP: 核心端口之一
  • kcpBindPort UDP: 核心端口之一
  • remotePort TCP/UDP: 根据实际用到的放行即可

2.1.5 客户端的端口配置

  • 防火墙放行所有localPort TCP/UDP端口

3 实现路径

  • 对于问题场景1,实际上通过上述frp的简单配置就能够满足需求

  • 对于问题场景2,则需要以下步骤来实现:

    1. 在内网机器上部署一个VPN,如OpenVPN;
    2. 测试确保能通过内网IP+端口的形式连接上VPN;
    3. 使用frp内网穿透,将VPN的端口暴露到公网,测试确保能通过公网IP+端口的形式连接上VPN;
    4. 通过内网机器、VPN服务端的一些设置,确保连接上VPN后能够访问内网其他资源。

3.1 OpenVPN的服务端配置

3.1.1 Windows系统

该部分主要参考这篇博文,按照步骤来基本不会有问题。

  1. OpenVPN 社区 下载 Windows 64-bit MSI installer
  2. 在选择安装类型时,选择 Customize 而不要选择 Install Now;
    • 勾选 OpenVPN -> OpenVPN Service -> Entire feature will be installed on local hard drive
    • 勾选 OpenSSL Utilities -> EasyRSA 3 Certificate Management Scripts -> Entire feature will be installed on local hard drive
    • 总之能装的全装上。
  3. 安装完毕后,会弹出一条消息提示未找到可读的连接配置文件,暂时忽略。此时在控制面板\网络和 Internet\网络连接中可以看到创建了两个新的网络适配器 OpenVPN TAP-Windows6 和 OpenVPN Wintun;
  4. 进入 OpenVPN 默认安装目录中的 easy-rsa 目录C:\Program Files\OpenVPN\easy-rsa
  5. 执行CMD命令进入 Easy-RSA 3 Shell:
.\EasyRSA-Start.bat
  1. 初始化公钥基础设施目录 pki:
./easyrsa init-pki
  1. 构建证书颁发机构(CA)密钥,CA 根证书文件将在后续用于对其他证书和密钥进行签名。该命令要求输入 Common Name,输入主机名即可。创建的 ca.crt 保存在目录C:\Program Files\OpenVPN\easy-rsa\pki中,ca.key 保存在目录C:\Program Files\OpenVPN\easy-rsa\pki\private中:
./easyrsa build-ca nopass
  1. 构建服务器证书和密钥。创建的 server.crt 保存在目录 C:\Program Files\OpenVPN\easy-rsa\pki\issued 中,server.key 保存在目录 C:\Program Files\OpenVPN\easy-rsa\pki\private 中:
./easyrsa build-server-full server nopass
  1. 构建客户端证书和密钥。创建的 client.crt 保存在目录 C:\Program Files\OpenVPN\easy-rsa\pki\issued 中,client.key 保存在目录 C:\Program Files\OpenVPN\easy-rsa\pki\private 中:
./easyrsa build-client-full client nopass
  1. 生成 Diffie-Hellman 参数:
./easyrsa gen-dh
  1. 从目录 C:\Program Files\OpenVPN\sample-config 复制服务端配置文件模板 server.ovpn 到目录 C:\Program Files\OpenVPN\config 中,修改以下配置:端口号按需修改,默认为 1194,需要保证 OpenVPN 的网络流量可以通过防火墙,设置 Windows 10 Defender 允许 OpenVPN 通过即可。dh2048.pem 修改为生成的文件名 dh.pem。取消注释 duplicate-cn,让多个客户端使用同一个客户端证书。注释掉 tls-auth ta.key 0
port 1194
dh dh.pem
duplicate-cn
;tls-auth ta.key 0
  1. 复制 ca.crtdh.pemserver.crtserver.key 到目录 C:\Program Files\OpenVPN\config 中;
  2. 启动 OpenVPN,点击连接,系统提示分配 IP 为 10.8.0.1。按配置,每次 OpenVPN server 都将为自己分配 10.8.0.1。

3.1.2 Linux系统

以Ubuntu为例,用安装脚本比较简单:

  1. wget https://git.io/vpn -O openvpn-ubuntu-install.sh
  2. sudo bash openvpn-ubuntu-install.sh,逐步设定后自动完成安装
  3. 根据输出信息能找到服务端配置文件在/etc/openvpn/server/server.conf,客户端配置文件直接输出在脚本运行目录下

3.2 OpenVPN客户端配置

  • Linux系统用脚本安装的一般已经配置好了,只需要修改remote your-server-ip 1194这行,改为公网IP和对应端口
  • Windows版本比较复杂,需要替换几个密钥的文本到客户端配置文件里:
    1. 从目录 C:\Program Files\OpenVPN\sample-config 复制客户端配置文件模板 client.ovpn,修改配置;
    2. remote your-server 1194 中的地址和端口替换成你的 OpenVPN 服务端对外的地址和端口;
    3. ca ca.crtcert client.crtkey client.keytls-auth ta.key 1 注释掉,再将各自文件中的内容以类 XML 的形式粘贴到 client.ovpn 中;
    4. 将修改好的客户端配置文件导入到客户端中。
remote your-server 1194

;ca ca.crt
;cert client.crt
;key client.key

;tls-auth ta.key 1

<ca>
-----BEGIN CERTIFICATE-----
paste contents of ca.crt
-----END CERTIFICATE-----
</ca>
<cert>
-----BEGIN CERTIFICATE-----
paste contents of client.crt
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN PRIVATE KEY-----
paste contents of client.key
-----END PRIVATE KEY-----
</key>

3.3 内网穿透配置

具体frp配置请参照前文

[[proxies]]
name = "vpn"
type = "udp"
localIp = "127.0.0.1"
localPort = 1194
remotePort= 9003
transport.useCompression = true

3.4 实现访问内网资源的配置

按照上述配置完成后,应该能用OpenVPN Connect连接上VPN,但一般还无法访问内网资源。

3.4.1 Windows系统

  1. 确认 OpenVPN 配置是否正确下发路由:
  • 在服务端配置文件server.conf里增加:
push "route 192.168.x.0 255.255.255.0"

内网真实网段可通过cmdipconfigroute print命令打印,一般可以从局域网 IP 和子网掩码推断出来。

  1. 开启 Windows 的 IP 转发,Windows 默认不转发 VPN 网段到内网,需要手动开启:
  • 打开注册表:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
  • 找到或新建 DWORD 值改为:
IPEnableRouter = 1
  • Win + R → 输入 services.msc → 回车,服务里重启 Routing and Remote Access 服务。
  1. 设置防火墙允许转发,Windows 防火墙可能会阻止 VPN 网段访问内网。
  • 打开 PowerShell 运行:
netsh advfirewall firewall add rule name="Allow OpenVPN" dir=in action=allow protocol=any localport=1194
netsh advfirewall firewall add rule name="Allow VPN Traffic" dir=in action=allow protocol=any
  1. 处理回程路由问题(只能访问VPN这台机器,无法访问其他内网资源):
  • 管理员打开powershell
  • 启用 NAT(假设 VPN 网段是 10.8.0.0/24),这样,Windows 会自动对来自 10.8.0.0/24 的流量做 NAT,让它们看起来像是从 192.168.1.100(假设VPN服务端机器IP) 发出的。
New-NetNat -Name "OpenVPN-NAT" -InternalIPInterfaceAddressPrefix 10.8.0.0/24
  • 查看 NAT 状态: Get-NetNat
  • 如需清理NAT: Remove-NetNat -Name "OpenVPN-NAT"

3.4.2 Linux系统

  1. 确认 OpenVPN 配置是否正确下发路由:
  • 在服务端配置文件server.conf里增加:
push "route 192.168.x.0 255.255.255.0"

(我测试出来ubuntu系统只做完1后面的步骤没弄就已经可以正常访问内网其他资源了)

  1. 确认服务端开启 IP 转发:
sudo vi /etc/sysctl.conf
#确保 net.ipv4.ip_forward = 1
  1. 确认 NAT/防火墙规则:
    首先确保服务器1194端口打开。如果 VPN 网段(例如 10.8.0.0/24)要访问内网(比如 192.168.1.0/24),VPN 服务端必须做路由转发或 NAT。最常见做法是在 VPN 服务器上加 iptables:
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -d 192.168.1.0/24 -j MASQUERADE
Author: zcp
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source zcp !
评论
 Current
frp+OpenVPN实现内网访问实践
1 问题场景 电脑A需要访问电脑B上的某个服务,但是电脑A、B在两个不同的网络中,且不具备公网IP、不具备对路由器的修改权限; 用户C在家想要访问公司内网上的一些资源/机器,但又不想通过RustDesk等远程桌面的形式。
Next 
程序访存性能瓶颈分析
1 问题场景在测试程序的并行效率时,发现Release版本的并行效率很低,而Debug版测出来则符合预期,怀疑程序受内存带宽限制而无法发挥应有的性能。但需要用实际数据来验证这个合理的猜想。 想象内存带宽就是一根水管,数据是水
  TOC