内网穿透配置笔记

内网穿透配置笔记

前言

下个月就要回家过年了。为了在家也能用 SSH 访问实验室服务器,我决定尝试用 frp 做内网穿透。

frp(fast reverse proxy)是一个专注内网穿透的开源应用,包含客户端和服务端。内网穿透需要一台拥有公网 IP 的服务器运行 frp 服务端来作为中转站,并在一台内网设备上运行 frp 客户端;此时公网中的设备就可以通过访问中转站来与内网通信。在热心同门的指导下,我通过学生认证申请了一台阿里云的 ECS 云服务器作为中转服务器。

服务端

下载 frp

首先获取最新版本的 frp:

1
2
3
wget https://github.com/fatedier/frp/releases/download/v0.66.0/frp_0.66.0_linux_amd64.tar.gz
tar -zxvf frp_0.66.0_linux_amd64.tar.gz
mv frp_0.66.0_linux_amd64 frp

下载并解压完成后,可以看到 frpcfrpc.tomlfrpsfrps.toml,分别是 frp 的客户端程序、客户端配置、服务端程序、服务端配置。

自 v0.52.0 版本起,frp 支持 .toml.yaml.json 格式的配置文件,而旧版常见的 .ini 文件将被逐渐弃用。

配置 frps

.toml 为例,我们编辑服务端配置文件 frps.toml

1
2
3
4
5
6
7
8
9
10
11
12
# frps 监听 IP 和端口
bindAddr = "0.0.0.0"
bindPort = *****

# 身份认证令牌(可选)
auth.token = "******"

# WEB管理面板设置
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "*****"
webServer.password = "*****"

完成配置以后,还需要注意在防火墙上开放端口,并在阿里云的控制台上设置安全组规则。

最后直接后台运行 frps 即可:

1
nohup ./frps -c frps.toml &

以系统服务方式运行 frps

为了长期使用方便,还可以将 frps 添加为系统级别 systemd 服务,实现开机自启。创建 /etc/systemd/system/frps.service

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=FRP Server Service
After=network.target

[Service]
Type=simple
ExecStart=/root/frp/frps -c /root/frp/frps.toml
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

然后重载配置,设置自启动并激活服务:

1
2
3
4
sudo systemctl daemon-reload
sudo systemctl enable frps
sudo systemctl start frps
sudo systemctl status frps

如果之后修改了相关配置,需要重启服务:

1
sudo systemctl restart frps

客户端

下载 frp

同样地,先获取最新版本的 frp:

1
2
3
wget https://github.com/fatedier/frp/releases/download/v0.66.0/frp_0.66.0_linux_arm64.tar.gz
tar -zxvf frp_0.66.0_linux_arm64.tar.gz
mv frp_0.66.0_linux_arm64 frp

配置 frpc

同样地,编辑 frpc.toml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
serverAddr = "***.***.**.***" # 中转服务器公网 IP
serverPort = ***** # 中转服务器的 frps 端口
auth.token = "**********" # 认证令牌

[[proxies]]
name = "ssh-spark"
type = "tcp"
localIP = "127.0.0.1" # 代理本机的 SSH
localPort = 25252 # 本地 SSH 端口
remotePort = 10517 # 映射到中转服务器的端口
transport.useEncryption = true # 加密传输
transport.useCompression = true # 数据压缩

[[proxies]]
name = "ssh-223"
type = "tcp"
localIP = "10.82.1.223" # 还可以代理内网中其他设备
localPort = 8864 # 该设备 SSH 端口
remotePort = 10223
transport.useEncryption = true
transport.useCompression = true

配置完成后,同样后台运行即可:

1
nohup ./frpc -c ./frpc.toml &

以系统服务方式运行 frpc

同样地,我们可以将 frpc 添加为系统级别 systemd 服务。

如果只添加为用户级别服务,服务有可能会在用户所有会话都退出时被终止。幸运的是,我在内网中恰巧有一台拥有 sudo 权限的设备。

创建 /etc/systemd/system/frpc.service

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=FRP Client Service
After=network.target

[Service]
Type=simple
ExecStart=/home/omniai-1/frp/frpc -c /home/omniai-1/frp/frpc.toml
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

与 frps 同样的操作:

1
2
3
4
sudo systemctl daemon-reload
sudo systemctl enable frpc
sudo systemctl start frpc
sudo systemctl status frpc

至此,就可以通过访问中转服务器的不同端口来访问内网的各个设备了!

安全措施

然而,进行内网穿透必须考虑到安全性——将内网设备服务端口暴露在公网中是一个有风险的行为。我意识到,虽然我的 frp 客户端设备已经设置了 SSH 仅密钥登录,但其代理的另一台共享服务器的 SSH 配置是不受我控制的,所以依然是存在一定风险的。

目前的问题是,如果我在公网中的 IP 不固定,无法在 frps 上设置 IP 白名单,frps 就无法识别连接是来自我本人的还是来自攻击者的。针对这个问题,最理想的解决方案是采用 sTCP(secret TCP)模式。该模式的核心逻辑是:不在公网服务器上直接开放服务端口,而是通过一个独立的加密控制通道进行连接验证;只有运行着 visitor 模式的 frpc 并配置了正确密码的设备才能与 frps 建立连接,然后将服务端口映射到自身的端口上。

采用 sTCP 模式后,frp 服务端配置不需要进行修改,只需要修改客户端配置 frpc.toml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
serverAddr = "***.***.***.***"
serverPort = *****
auth.token = "**********"

[[proxies]]
name = "ssh-spark"
type = "stcp" # 改为 stcp 模式
secretKey = "**********" # stcp 密码
localIP = "127.0.0.1"
localPort = 25252
# 移除 remotePort
transport.useEncryption = true
transport.useCompression = true

[[proxies]]
name = "ssh-223"
type = "stcp" # 改为 stcp 模式
secretKey = "**********" # stcp 密码
localIP = "10.82.1.223"
localPort = 8864
# 移除 remotePort
transport.useEncryption = true
transport.useCompression = true

然后重启 frpc 服务。

对于需要访问内网的公网设备,需要下载 frp,并配置 frpc.toml 为 visitor 模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
serverAddr = "***.***.***.***"
serverPort = *****
auth.token = "**********"

[[visitors]]
name = "visitor-spark"
type = "stcp"
serverName = "ssh-spark"
secretKey = "**********"
bindAddr = "127.0.0.1"
bindPort = 10517 # 映射到本地的端口
transport.useEncryption = true
transport.useCompression = true

[[visitors]]
name = "visitor-223"
type = "stcp"
serverName = "ssh-223"
secretKey = "**********"
bindAddr = "127.0.0.1"
bindPort = 10223 # 映射到本地的端口
transport.useEncryption = true
transport.useCompression = true

然后运行 frpc,即可直接在本地端口上访问 frp 代理的服务。

作者

Cu_OH_2

发布于

2026-01-17

更新于

2026-01-24

许可协议