很多站长手里都有 VPS,但真正让人头疼的往往是另一类需求:家里的 NAS、办公室的电脑、内网里的测试站点,明明就在手边,却没有公网 IP,外面根本访问不到。传统做法是找运营商开公网 IP、做端口映射,可大多数宽带早就换成了 NAT 模式,申请流程又长又麻烦。
内网穿透就是解决这个问题的:用一台有公网 IP 的 VPS 做中转,把内网设备的端口"映射"到公网。frp 是目前用得最多、配置最简单的开源方案之一,服务端和客户端都只有一个二进制文件,几分钟就能跑起来。本文按真实操作顺序,把服务端部署、客户端配置、Web / SSH / 远程桌面三个常见场景,以及安全加固和排错一次讲清。
一、frp 是什么,适合哪些场景
frp 全称 Fast Reverse Proxy,是一个反向代理工具。它的工作方式可以拆成两端:
- frps(服务端):部署在拥有公网 IP 的 VPS 上,负责接收内网客户端的连接,并把公网请求转发进去。
- frpc(客户端):部署在内网设备上,主动连接 frps,建立一条长连接,把本地端口暴露出去。
因为客户端是"主动往外连"的,所以内网设备不需要公网 IP,也不需要路由器做端口映射,只要能上网就能用。常见场景包括:
- 把家里的 NAS、路由器管理页、监控画面发布到公网;
- 在外面用 SSH 管理公司或家里的 Linux 主机;
- 远程桌面连接内网 Windows 电脑;
- 给没有公网 IP 的测试服务器做临时域名访问。
和同类方案相比,frp 的优势是部署轻、协议全(TCP、UDP、HTTP、HTTPS 都支持)、配置直观,缺点是流量要经过中转服务器,速度和延迟取决于 VPS 线路。
二、准备工作
开始之前,确认三样东西:
- 一台有公网 IP 的 VPS:1 核 1G 就够用,系统建议 Debian 12 或 Ubuntu 22.04/24.04,本文命令以这两个系统为准。
- 一个域名(可选):如果要把内网站点发布成
blog.example.com这样的地址,需要域名并完成备案(国内服务器)或直接使用海外服务器。 - 内网设备:能安装 frpc 的 Linux、Windows 或 NAS,以及要暴露的本地端口。
登录 VPS,先更新系统并安装基础工具:
apt update
apt install -y curl wget tar systemd
三、服务端:在 VPS 上部署 frps
frp 官方在 GitHub 发布编译好的二进制包,直接下载解压即可。先设置一个版本变量,实际使用时到 releases 页面换成最新版本号:
FRP_VER="0.61.0"
ARCH="amd64"
cd /tmp
wget https://github.com/fatedier/frp/releases/download/v${FRP_VER}/frp_${FRP_VER}_linux_${ARCH}.tar.gz
tar -xzf frp_${FRP_VER}_linux_${ARCH}.tar.gz
mkdir -p /usr/local/frp
cp frp_${FRP_VER}_linux_${ARCH}/frps /usr/local/frp/
chmod +x /usr/local/frp/frps
新建服务端配置文件 /usr/local/frp/frps.toml。从 v0.52 开始 frp 默认使用 TOML 格式,旧版 ini 写法已经不再推荐:
bindPort = 7000
auth.token = "请换成你自己的强密码"
# 仪表盘,建议只监听本机,通过 SSH 隧道访问
webServer.addr = "127.0.0.1"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "请换成强密码"
# 如要用 HTTP 方式发布网站,开启这一项
vhostHTTPPort = 8080
# 限制客户端可映射的远端端口范围,降低被滥用的风险
allowPorts = [
{ start = 20000, end = 30000 }
]
配置 systemd 托管,保证开机自启、进程掉线自动拉起。新建 /etc/systemd/system/frps.service:
[Unit]
Description=frp server
After=network.target
[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/frp/frps -c /usr/local/frp/frps.toml
[Install]
WantedBy=multi-user.target
启动并检查状态:
systemctl daemon-reload
systemctl enable --now frps
systemctl status frps
journalctl -u frps -f
看到 frps started successfully 就说明服务端已经跑起来了。接着放行防火墙端口,云服务器还要在控制台的安全组里同步放行:
ufw allow 7000/tcp
ufw allow 8080/tcp
ufw allow 2222/tcp
ufw allow 13389/tcp
ufw reload
四、客户端:在内网设备上部署 frpc
以 Linux 客户端为例,下载和安装方式与服务端一致,只需要 frpc 这个二进制:
FRP_VER="0.61.0"
ARCH="amd64"
cd /tmp
wget https://github.com/fatedier/frp/releases/download/v${FRP_VER}/frp_${FRP_VER}_linux_${ARCH}.tar.gz
tar -xzf frp_${FRP_VER}_linux_${ARCH}.tar.gz
mkdir -p /usr/local/frp
cp frp_${FRP_VER}_linux_${ARCH}/frpc /usr/local/frp/
chmod +x /usr/local/frp/frpc
新建 /usr/local/frp/frpc.toml,把地址、Token 和端口换成自己的:
serverAddr = "你的VPS公网IP"
serverPort = 7000
auth.token = "与服务端完全一致"
[[proxies]]
name = "home-web"
type = "http"
localIP = "127.0.0.1"
localPort = 80
customDomains = ["blog.example.com"]
[[proxies]]
name = "home-ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 2222
[[proxies]]
name = "home-rdp"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3389
remotePort = 13389
同样用 systemd 托管 frpc,新建 /etc/systemd/system/frpc.service:
[Unit]
Description=frp client
After=network.target
[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/frp/frpc -c /usr/local/frp/frpc.toml
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now frpc
systemctl status frpc
journalctl -u frpc -f
日志里出现 start proxy success,说明隧道已经建立。此时在服务端仪表盘里也能看到在线的客户端和代理列表。
五、场景一:把内网 Web 站点发布到公网
上面的 home-web 代理用的是 HTTP 类型。要让它通过域名访问,还需要三步:
1. 解析域名。在 DNS 服务商处添加一条 A 记录,把 blog.example.com 指向 VPS 的公网 IP。
2. 服务端开启 vhostHTTPPort。前面配置里的 vhostHTTPPort = 8080 就是 frp 接收 HTTP 请求的端口。访问 http://blog.example.com:8080 就能命中内网站点。
3. 换成 80/443 端口。直接暴露 8080 不美观,也不利于收录。更推荐用 Nginx 做一层反向代理,把 80/443 的请求转给 frp:
server {
listen 80;
server_name blog.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
保存后执行 nginx -t && systemctl reload nginx。再配合 Certbot 申请证书,就能得到完整的 HTTPS 访问。注意 proxy_set_header Host $host 不能漏,否则后端站点可能因为域名不匹配而跳转异常。
六、场景二:在外网 SSH 管理内网机器
home-ssh 代理把内网的 22 端口映射到 VPS 的 2222 端口。连接方式很直接:
ssh -p 2222 用户名@你的VPS公网IP
如果内网机器本身就在 NAT 后面,这相当于给它开了一扇只有你知道的门。几点建议:
- 不要用默认的 2222,换一个不常见的端口,减少被扫描的概率;
- 客户端机器上禁用密码登录,改用 SSH 密钥;
- 在 frps 的
allowPorts里限定可用端口范围,避免被当成免费跳板。
七、场景三:远程桌面连接内网 Windows
Windows 专业版默认开启 RDP,端口 3389。用 frpc 把它映射到公网的 13389:
[[proxies]]
name = "home-rdp"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3389
remotePort = 13389
然后在 Windows 上打开"远程桌面连接",地址填 你的VPS公网IP:13389 即可。RDP 直接暴露在公网风险很高,务必做到:
- 只允许自己的常用 IP 访问,必要时用云防火墙做源 IP 限制;
- 开启 Windows 的账户锁定期和登录审计;
- 能用 VPN 或 ZeroTier 时,优先走 VPN,不要把 3389 长期挂在公网。
八、安全加固:别把穿透做成后门
frp 本身不提供鉴权之外的防护,公网暴露的端口很容易被扫描。下面几项是最低要求:
- 强 Token:服务端和客户端必须使用同一串足够长的随机字符,不要用默认值。
- 开启 TLS:在 frps.toml 中加入
transport.tls.force = true,客户端会自动使用 TLS 连接,避免流量被中间人查看。 - 仪表盘不对外:
webServer.addr保持127.0.0.1,需要查看时用ssh -L 7500:127.0.0.1:7500做本地转发。 - 限制端口范围:
allowPorts只放行自己需要的区间,防止别人拿你的 frps 做任意端口转发。 - 及时升级:frp 版本更新较快,关注 releases 页面的安全修复,升级时服务端和客户端尽量保持同版本。
九、常见问题排查
客户端连不上服务端。先在 VPS 上执行 ss -lntp | grep 7000 确认端口在监听,再检查云安全组和 ufw 是否放行。用 telnet 你的IP 7000 从外网测试,能通再排查 Token 和版本。
提示 token 不一致。服务端和客户端的 auth.token 必须完全一样,注意不要带多余空格。修改后重启两端服务。
域名访问 404 或跳转异常。优先检查 Nginx 是否传递了正确的 Host 头,以及 frpc 的 customDomains 是否和访问域名完全一致。
连接偶尔断线。多半是 VPS 到内网之间的网络抖动,可以在 frpc 中加入 transport.heartbeatInterval 和 transport.heartbeatTimeout,并把 systemd 的 Restart=on-failure 保留好,掉线后会自动重连。
速度慢。frp 的流量全程走中转 VPS,线路质量决定体验。需要大流量传输时,选择带宽充足、回程优化好的服务器,或者改用 P2P 类方案。
十、结语
frp 把"没有公网 IP 也能从外网访问内网设备"这件事,压缩成了两份配置文件和两个 systemd 服务。整套流程跑通之后,NAS、SSH、远程桌面、内网测试站都能统一管理,换设备时也只需要改客户端配置。
最后再提醒一句:内网穿透的本质是把内网端口暴露到公网,便利和安全永远是一对矛盾。Token、TLS、端口限制、访问审计这四件事做到位,再谈方便。如果你也在用 frp,欢迎在评论区分享自己的配置方案和踩坑经历。