内网穿透

基础理解

内网穿透能够使仅可被内网访问的服务被公网上的设备访问到。

举个例子,当我需要使用学校实验室的服务器,只能通过使我的电脑连接到学校的网络(与服务器处于同一局域网),再通过局域网下的 IP 地址(内网地址)访问服务器;而当我的电脑和服务器不处于同一局域网时,我便无法连接到服务器。通过内网穿透的方式,我便可以通过一些中介将我的请求转发给服务器,达到和服务器近似处于同一局域网的效果。

再举个例子,在我的家中有一台主机一直开机,硬盘上存放着一些影视资源。由于默认情况下,我们使用的是 ISP 分配的随机 IP 地址,家中主机的 IP 地址不固定,在外我也就无法和家中的主机建立稳定联系,获取这些影视资源。而通过内网穿透,我便可以通过一些中介进入家庭内网,访问硬盘资源,甚至可以建立 P2P 连接。

条件支持

其实有很多服务商提供内网穿透服务,如 花生壳,在此不赘述。本文将通过自购服务器及 FRP 软件搭建内网穿透服务。所以需要的前提条件是:

  1. 存在具体的内网穿透的需求(如游戏联机、NAS 布置、SSH 访问等)
  2. 拥有一台具有固定 IP 地址的服务器
  3. 在需要被访问的内网拥有可以稳定在线的设备
  4. 内网(局域网)本身可以连接到互联网

Frp

Frp 本质上是一个反向代理软件,基于 Go 语言,开源免费,支持多种协议,支持多种类型的终端,可以访问 Frp 仓库页面 查看详情。Frp 服务分为服务端(Frps)和客户端(Frpc),分别需要安装在公网 IP 主机上、内网终端/访问端上。本文将使用腾讯云服务器(Lighthouse,Ubuntu 20.04)作为公网服务器,安卓手机(Mi 8,Android 8)作为内网终端搭建 Frp 服务。

安装

Frp 基于 Go 语言,需要先安装好环境,可以参照 Download & Install Golang 页面说明配置。对于 Linux 服务器,可以下载 Go,并解压放至 /usr/local/go 文件夹,并添加环境变量:

1
2
3
wget https://go.dev/dl/go1.17.8.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.8.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin

随后,进入 Releases · fatedier/frp 页面,选择部署终端对应的安装包并下载,如 Ubuntu 系统的服务器下载 frp_0.38.0_linux_amd64.tar.gz。随后将其解压到任意位置即可。对于 Android 设备,可以进入 Releases · HaidyCao/frp 直接下载 apk 安装包安装即可。

配置

进入解压的文件夹,可以看到 frpcfrps 及对应的配置文件 frpc.inifrps.ini。服务端(公网 ip 设备)运行 frps,修改 frps.ini 配置文件;客户端(内网设备、访问设备)运行 frpc,修改 frpc.ini 配置文件。

frps 文件夹

无论是 frps.ini 还是 frpc.ini,配置文件格式都类似于如下形式:

1
2
3
4
[<配置服务名>]
<参数名> = <参数值>
<参数名> = <参数值>
....

启动

编辑完配置文件后,先通过 ./frps -c ./frps.ini 启动服务端,再通过 ./frpc -c ./frpc.ini 启动客户端。即使是在 Windows 上,也需要在 cmd.exe 终端中执行命令运行。

对于 Android 端,编辑配置文件后,直接点击右下角图标运行即可。

Frp 配置实例

下面对特定应用场景举例修改 Frp 的配置文件,更多配置可以参考 frp中文文档示例frp官方文档

例:ssh 访问内网机器

修改服务端配置:

1
2
3
# frps.ini
[common]
bind_port = 7000
  • bind_port 的端口用于监听客户端连接请求。(需在服务器防火墙放行)

修改客户端配置:

1
2
3
4
5
6
7
8
9
10
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000
  • server_addr 填入服务端主机的公网 ip
  • server_port 填入刚才填入的监听端口
  • local_ip 填入在内网需要访问主机的 ip 地址(可以是局域网地址),如果是本机则填入 127.0.0.1
  • remote_port 填入服务端监听 ssh 请求的端口,访问该端口的请求会被转发到局域网的 <local_ip>:<local_port>(需在服务器防火墙放行)

启动服务后,执行如下命令即可访问局域网主机,frp 会将请求转发至局域网的 <local_ip>:<local_port>

1
ssh -oPort=<remote_port> <username>@<server_addr>

例:通过域名访问内网 Web 服务

修改服务端配置:

1
2
3
4
# frps.ini
[common]
bind_port = 7000
vhost_http_port = 8080
  • vhost_http_port 的端口用于监听来自外网的 http 请求。(需在服务器防火墙放行)

修改客户端配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[xxxx]
type = http
local_ip = 127.0.0.1
local_port = 80
custom_domains = www.xxxxxx.com

[xxxx]
type = http
local_ip = 127.0.0.1
local_port = 9090
custom_domains = www.xxxxxx.com
  • 每项 web 服务单独配置即可;
  • custom_domain 处填写需在外网访问该应用的域名(该域名需要解析到服务端 ip 地址)。

其他设备访问 http://<custom_domain>:<vhost_http_port>,即可访问到局域网 http://<local_ip>:<local_port> 的 Web 应用。

例:P2P 内网穿透

大多数情况下,服务端服务器将转发所有内网客户端和外网机器的流量,假设我从 PC 向局域网主机上传一个 100M 的文件,那么这个文件的包会首先经过服务端,再转发给客户端,将消耗服务端服务器的 200M 流量,如果这样的任务较多,对中转服务器的带宽和流量将带来不必要的占用。此时可以采用 frp 的 P2P 配置,服务端仅用于建立外网主机和局域网主机的联系,随后流量仅在外网主机和局域网主机点对点传输。

要想以该方式进行内网穿透,额外要求外网连接的机器也部署 frpc,安装过程同上。

修改服务端配置:

1
2
3
4
# frps.ini
[common]
bind_port = 7000
bind_udp_port = 7000
  • bind_udp_port 用于监听两边客户端(局域网主机、外网访问机)的 UDP 请求,并建立之后的联系。(需在服务器防火墙放行)

修改客户端(局域网主机)配置:

1
2
3
4
5
6
7
8
9
10
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[p2p_ssh1]
type = xtcp
sk = secretkey
local_ip = 127.0.0.1
local_port = 22
  • sk 为验证字串,只有验证一致的用户才能访问该服务。

修改客户端(外网访问机)的配置:

1
2
3
4
5
6
7
8
9
10
11
12
# frpc.ini
[common]
server_addr = x.x.x.x
server_port = 7000

[p2pssh1_visitor]
type = xtcp
role = visitor
server_name = p2p_ssh1
sk = secretkey
bind_addr = 127.0.0.1
bind_port = 6000
  • server_name 填入在局域网客户端已配置的应用名
  • bind_addrbind_port 分别填入本机绑定的 ip 地址和端口,用于访问 ssh 服务。

启动服务后,执行如下命令即可访问局域网主机,frp 会将请求转发至局域网的 <local_ip>:<local_port>

1
ssh -oPort=<bind_port> <username>@<bind_addr>

例:配置服务端看板

frp 自带一个看板,提供查看服务端配置、连接情况的服务。只需在服务端看板添加如下配置:

1
2
3
4
5
6
# frps.ini
[common]
# 其他配置略
dashboard_port = 7500
dashboard_user = username
dashboard_pwd = password
  • dashboard_port 端口用于监听访问看板服务的 http 请求。(需在服务器防火墙放行)
  • dashboard_userdashboard_pwd 配置登录看板的用户名和密码。

启用后,访问 http://<server_addr>:<dashboard_port> 即可查看服务端看板。

服务端看板

例:配置客户端管理面板

frps 也提供管理客户端配置的 web 服务。修改客户端配置文件:

1
2
3
4
5
6
7
# frpc.ini
[common]
# 其他配置略
admin_addr = 127.0.0.1
admin_port = 7400
admin_user = admin
admin_pwd = admin

客户端管理页面

启用后,访问 http://<admin_addr>:<admin_port> 即可查看服务端看板。服务端看板可以实时修改客户端配置并热启动。