用 frp 实现内网 SSH 穿透:从搭建到排障
文章目录
家里的电脑、公司的开发机,或者实验环境中的虚拟机,经常没有固定公网 IP。人已经离开现场,但又想临时 SSH 登录回去,这时就需要把内网服务安全地“映射”到一个有公网 IP 的服务器上。frp 正是用于解决这类问题的反向代理工具。
本文将基于 Linux 和 systemd,使用 frp 将内网机器的 SSH 端口映射到云服务器,并给出验证、排障和基本的安全建议。
先理解 frp 的工作方式
frp 采用客户端与服务端配合的方式工作:
frps:运行在具有公网 IP 的服务器上,等待客户端连接并对外提供映射端口。frpc:运行在内网机器上,主动连接frps,把内网服务转发到公网服务器。
以 SSH 穿透为例,整体链路如下:
flowchart LR
admin[远程管理电脑] -->|TCP 7001| frps[云服务器 frps]
frpc[内网机器 frpc] -->|控制连接 7000| frps
frpc -->|127.0.0.1:22| ssh[内网 SSH 服务]本文约定两个端口:
| 端口 | 用途 | 暴露位置 |
|---|---|---|
7000 | frpc 连接 frps 的控制端口 | 云服务器公网 |
7001 | 映射到内网 SSH 的远程端口 | 云服务器公网 |
需要强调一点:frp 不能凭空让内网机器获得公网入口,仍然需要一台能被公网访问的服务器。
准备环境
开始前确认以下条件:
- 云服务器具有公网 IP,并能修改安全组规则。
- 内网机器可以主动访问公网。
- 内网机器已经启用 SSH 服务,默认端口为
22。 - 两端最好使用相同版本的 frp,避免配置格式或协议不兼容。
frp 的发布包可以在 GitHub Releases
下载。下载时根据 CPU 架构选择文件,例如常见的 64 位 x86 服务器通常选择 linux_amd64。
解压后可以看到客户端和服务端分别需要的文件:
frpc
frpc.toml
frps
frps.toml服务端只需要 frps 和 frps.toml,客户端只需要 frpc 和 frpc.toml。
tar -xzf frp_*_linux_amd64.tar.gz
cd frp_*_linux_amd64下面的配置会把程序安装到 /usr/local/bin,并把配置放到 /etc/frp。这样程序和配置的路径固定,后续交给 systemd 管理也更方便。
配置服务端 frps
先在云服务器上放置程序和配置:
sudo install -Dm0755 frps /usr/local/bin/frps
sudo install -Dm0600 frps.toml /etc/frp/frps.toml生成一个足够随机的鉴权 token:
openssl rand -hex 32然后编辑 /etc/frp/frps.toml:
bindPort = 7000
auth.method = "token"
auth.token = "替换为刚刚生成的随机token"bindPort = 7000 是 frp 的控制端口。auth.token 用于确认连接的客户端是否可信,服务端和客户端必须完全一致。
编辑配置文件时要保证文件可读,否则以普通方式启动服务时可能读取失败:
sudo chmod 600 /etc/frp/frps.toml用 systemd 托管 frps
创建 /etc/systemd/system/frps.service:
[Unit]
Description=frp server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target启动服务并设置开机自启:
sudo systemctl daemon-reload
sudo systemctl enable --now frps查看运行状态和日志:
systemctl status frps --no-pager
journalctl -u frps -n 100 --no-pager配置文件修改后,可以先用 frp 自带命令检查语法,再重启服务:
sudo frps verify -c /etc/frp/frps.toml
sudo systemctl restart frps配置客户端 frpc
在内网机器上安装客户端:
sudo install -Dm0755 frpc /usr/local/bin/frpc
sudo install -Dm0600 frpc.toml /etc/frp/frpc.toml编辑 /etc/frp/frpc.toml:
serverAddr = "你的云服务器公网IP"
serverPort = 7000
auth.method = "token"
auth.token = "与服务端完全一致的token"
[[proxies]]
name = "home-ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 7001各项配置的含义如下:
| 配置项 | 说明 |
|---|---|
serverAddr | 云服务器的公网 IP 或域名 |
serverPort | 服务端监听的 frp 控制端口 |
localIP | 内网 SSH 服务所在地址,和 frpc 同机时可使用 127.0.0.1 |
localPort | 内网 SSH 实际监听的端口 |
remotePort | 外部访问云服务器时使用的端口 |
这里的 remotePort = 7001 是举例。它不能与 serverPort 或其他代理的远程端口重复,并且必须与服务端安全组中放行的端口一致。
创建客户端服务 /etc/systemd/system/frpc.service:
[Unit]
Description=frp client
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target同样地,启动并检查客户端:
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
systemctl status frpc --no-pager
journalctl -u frpc -n 100 --no-pager放行云服务器端口
以阿里云为例,需要进入实例的安全组,添加入方向规则:
- 协议类型:TCP。
- 端口范围:至少包含
7000和7001。 - 授权对象:测试阶段可暂时使用
0.0.0.0/0,生产环境应尽量限制为实际访问来源的 IP。
如果服务器本机启用了防火墙,还需要同步放行这些端口。不同发行版使用的防火墙工具不同,可以先确认防火墙状态,再按照实际环境添加规则。
端口放行后在云服务器上检查监听情况:
sudo ss -lntp | grep -E ':(7000|7001)\b'正常情况下,应该能看到 frps 监听 7000,并在客户端连接成功后监听 7001。
登录内网 SSH
frp 连接建立后,在任意外部电脑上执行:
ssh -p 7001 内网机器的用户名@云服务器公网IP这里容易混淆的是两个身份:
内网机器的用户名是 SSH 登录时使用的 Linux 用户。云服务器公网IP是连接地址,因为 frp 把入口暴露在这台服务器上。
SSH 的端口参数是小写 -p,与 scp 使用的 -P 不同。原文档中的写法 ssh -o Port=7001 ... 同样可以工作,但直接使用 -p 更直观。
如果经常登录,可以把它写入 ~/.ssh/config:
Host home-pc
HostName 203.0.113.10
Port 7001
User zhangsan
ServerAliveInterval 30之后直接执行 ssh home-pc 即可。把示例中的 IP 和用户名替换成自己的值。
常见问题排查
连接被拒绝或一直超时
依次检查控制端口、安全组和监听状态:
frps是否正在运行。- 云服务器安全组是否放行
7000和7001。 - 客户端配置中的
serverAddr是否正确。 - 云服务器上是否存在
7001的监听记录。
systemctl status frps --no-pager
sudo ss -lntp | grep -E ':(7000|7001)\b'客户端提示鉴权失败
检查两端 auth.method 和 auth.token 是否完全一致,包括大小写与多余空格。token 应当保存在受限权限的配置文件中,不要提交到 Git 仓库,也不要直接展示在截图里。
提示远程端口已被占用
remotePort 已经被另一个代理或系统进程占用。换一个未使用的端口,同时更新云服务器安全组规则和客户端配置。
服务启动后立即退出
优先查看日志定位配置错误或路径问题:
journalctl -u frps -n 100 --no-pager
journalctl -u frpc -n 100 --no-pager如果 systemd 单元中使用了自定义路径,确认路径与实际安装位置一致。移动二进制文件或配置文件后,需要执行 systemctl daemon-reload。
安全建议
frp 解决的是网络可达性,不会代替应用本身的安全措施。尤其是 SSH 映射,建议至少做到以下几点:
- 使用
openssl rand -hex 32之类的命令生成高强度 token,服务端和客户端共享同一份。 - 安全组只放行业务真正需要的端口。
7001是管理入口,条件允许时应限制访问来源 IP。 - 内网 SSH 使用密钥登录,并在确认密钥可用后关闭密码登录。
- 不要把数据库、Redis 管理端口等未经认证的服务直接映射到公网。
- 关注 frp 的版本更新,及时升级客户端和服务端。
完成以上配置后,云服务器负责提供公网入口,内网机器主动维持 frp 连接,外部电脑就能通过一个固定端口访问内网 SSH。整个方案的关键只有三点:两端 token 一致、控制端口可达、远程端口放行。遇到问题时沿着这三条链路检查,通常就能快速定位原因。