1 问题场景
电脑A需要访问电脑B上的某个服务,但是电脑A、B在两个不同的网络中,且不具备公网IP、不具备对路由器的修改权限;
用户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,则需要以下步骤来实现:
- 在内网机器上部署一个VPN,如OpenVPN;
- 测试确保能通过
内网IP+端口
的形式连接上VPN; - 使用
frp
内网穿透,将VPN的端口暴露到公网,测试确保能通过公网IP+端口
的形式连接上VPN; - 通过内网机器、VPN服务端的一些设置,确保连接上VPN后能够访问内网其他资源。
3.1 OpenVPN的服务端配置
3.1.1 Windows系统
该部分主要参考这篇博文,按照步骤来基本不会有问题。
- 从 OpenVPN 社区 下载
Windows 64-bit MSI installer
; - 在选择安装类型时,选择 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
; - 总之能装的全装上。
- 勾选
- 安装完毕后,会弹出一条消息提示未找到可读的连接配置文件,暂时忽略。此时在
控制面板\网络和 Internet\网络连接
中可以看到创建了两个新的网络适配器 OpenVPN TAP-Windows6 和 OpenVPN Wintun; - 进入 OpenVPN 默认安装目录中的 easy-rsa 目录
C:\Program Files\OpenVPN\easy-rsa
; - 执行CMD命令进入 Easy-RSA 3 Shell:
.\EasyRSA-Start.bat
- 初始化公钥基础设施目录 pki:
./easyrsa init-pki
- 构建证书颁发机构(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
- 构建服务器证书和密钥。创建的 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
- 构建客户端证书和密钥。创建的 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
- 生成 Diffie-Hellman 参数:
./easyrsa gen-dh
- 从目录
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
- 复制
ca.crt
,dh.pem
,server.crt
和server.key
到目录C:\Program Files\OpenVPN\config
中; - 启动 OpenVPN,点击连接,系统提示分配 IP 为 10.8.0.1。按配置,每次 OpenVPN server 都将为自己分配 10.8.0.1。
3.1.2 Linux系统
以Ubuntu为例,用安装脚本比较简单:
wget https://git.io/vpn -O openvpn-ubuntu-install.sh
sudo bash openvpn-ubuntu-install.sh
,逐步设定后自动完成安装- 根据输出信息能找到服务端配置文件在
/etc/openvpn/server/server.conf
,客户端配置文件直接输出在脚本运行目录下
3.2 OpenVPN客户端配置
- Linux系统用脚本安装的一般已经配置好了,只需要修改
remote your-server-ip 1194
这行,改为公网IP和对应端口; - Windows版本比较复杂,需要替换几个密钥的文本到客户端配置文件里:
- 从目录
C:\Program Files\OpenVPN\sample-config
复制客户端配置文件模板client.ovpn
,修改配置; - 将
remote your-server 1194
中的地址和端口替换成你的 OpenVPN 服务端对外的地址和端口; - 将
ca ca.crt
,cert client.crt
,key client.key
,tls-auth ta.key 1
注释掉,再将各自文件中的内容以类 XML 的形式粘贴到client.ovpn
中; - 将修改好的客户端配置文件导入到客户端中。
- 从目录
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系统
- 确认 OpenVPN 配置是否正确下发路由:
- 在服务端配置文件
server.conf
里增加:
push "route 192.168.x.0 255.255.255.0"
内网真实网段可通过cmd
的ipconfig
或route print
命令打印,一般可以从局域网 IP 和子网掩码推断出来。
- 开启 Windows 的 IP 转发,Windows 默认不转发 VPN 网段到内网,需要手动开启:
- 打开注册表:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
- 找到或新建 DWORD 值改为:
IPEnableRouter = 1
Win + R
→ 输入services.msc
→ 回车,服务里重启 Routing and Remote Access 服务。
- 设置防火墙允许转发,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
- 处理回程路由问题(只能访问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系统
- 确认 OpenVPN 配置是否正确下发路由:
- 在服务端配置文件
server.conf
里增加:
push "route 192.168.x.0 255.255.255.0"
(我测试出来ubuntu系统只做完1后面的步骤没弄就已经可以正常访问内网其他资源了)
- 确认服务端开启 IP 转发:
sudo vi /etc/sysctl.conf
#确保 net.ipv4.ip_forward = 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