在没有公网 IP 的家庭宽带或公司内网里,想把跑在笔记本上的接口、数据库或调试页面临时分享给外部同事,往往卡在”别人访问不到”。内网穿透正是解决这一顽疾的通用方案:它在公网服务器与内网客户端之间建立一条加密隧道,把本地端口映射出去。开源项目 frp(Fast Reverse Proxy)轻量、配置直观,是目前最受欢迎的自建穿透工具之一。下面从架构到落地,完整走一遍。
一、内网穿透解决什么痛点
典型网络里,你的开发机藏在多层 NAT 之后,外部无法直连。内网穿透的思路是:在一台有公网 IP 的服务器上运行服务端(frps),在内网机器上运行客户端(frpc);frpc 主动连上 frps 并保持长连接,外部用户访问 frps 的公网端口时,流量经隧道转发到 frpc 背后的本地服务。整个过程不需要在路由器上做端口映射,也不需要申请固定公网 IP。
二、什么场景需要它
| 场景 | 痛点 | frp 方案 |
|---|---|---|
| 远程 SSH 运维 | 家里/机房机器无公网 IP | 把本地 22 端口映射为 frps 的一个 TCP 端口 |
| 本地 Web 联调 | 微信/支付宝回调、OAuth 重定向需要公网可达 | 把本地 8080 映射为 frps 的 HTTP 端口并绑定子域名 |
| 远程桌面 | 临时帮家人/同事处理电脑问题 | 把本地 3389(RDP)映射为 frps TCP 端口 |
| 演示与协作 | 想把未上线的原型给客户看一眼 | 临时开一条 Web 穿透,用完即关 |
如果你的目标是在两台设备之间组建稳定的私有网络(而非临时暴露某个端口),那么点对点 VPN(如 WireGuard 异地组网实战)往往是更合适的选择。frp 擅长”把某个端口暴露出去”,VPN 擅长”把两张网卡打通”。
三、frp 的核心概念
- frps:服务端,部署在有公网 IP 的服务器上,统一接收外部流量。
- frpc:客户端,跑在内网机器上,主动连 frps 并声明要暴露哪些本地端口。
- proxy:一条穿透规则,类型支持 tcp / udp / http / https / stcp 等。
- visitor:用于 stcp 等点对点模式的访问端,避免把端口直接暴露在公网。
四、搭建 frps 服务端
在公网服务器(以 Ubuntu 为例)下载 frp 后,新建 frps.toml。新版 frp 使用 TOML 配置:
# /etc/frp/frps.toml
bindPort = 7000 # frpc 连接 frps 的控制端口
auth.token = "换成一段足够随机的密钥" # 客户端必须一致
# Web 类穿透使用的虚拟端口
vhostHTTPPort = 80
vhostHTTPSPort = 443
# 可选:后台管理面板
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "再换一段强密码"
用 systemd 托管 frps,保证开机自启、崩溃重启:
# /etc/systemd/system/frps.service
[Unit]
Description=frps
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
放行防火墙(以 ufw 为例),只开放必要端口:
sudo ufw allow 7000/tcp # 控制端口
sudo ufw allow 80/tcp # HTTP 穿透
sudo ufw allow 443/tcp # HTTPS 穿透
sudo ufw allow 7500/tcp # 管理面板(建议仅内网或加 IP 限制)
sudo systemctl enable --now frps
五、客户端配置与常见穿透
内网机器上的 frpc.toml 通过 serverAddr 指向公网服务器。下面是三个最常用的场景。
# /etc/frp/frpc.toml
serverAddr = "你的公网服务器IP"
serverPort = 7000
auth.token = "与服务端一致的密钥"
# 1) 远程 SSH:把本地 22 映射为 frps 的 2222
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 2222
# 2) 本地 Web 联调:绑定子域名 web.example.com
[[proxies]]
name = "web"
type = "http"
localPort = 8080
customDomains = ["web.example.com"]
# 3) 远程桌面 RDP
[[proxies]]
name = "rdp"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3389
remotePort = 3389
配置完成后,外部即可用 ssh -p 2222 公网IP 连回内网机器;Web 场景则在 DNS 把 web.example.com 解析到 frps 公网 IP,访问即直达本地 8080。若本地服务本身跑在容器里,可参考 Docker 容器化部署实践 把 frpc 也放进同一网络,省去端口暴露的麻烦。
六、安全加固(必做)
- 强制 token 鉴权:上面已配置
auth.token,杜绝未授权客户端连入。 - 启用 TLS:在 frpc 增加
transport.tls.enable = true,防止控制通道被中间人窃听。 - 最小端口暴露:只为真正需要的 proxy 分配 remotePort,关闭用不到的 Web 面板公网访问。
- 前端再挡一层:HTTP 类穿透前可加 Nginx 反向代理 做 HTTPS 终止与限流,既加密又防刷。
- 定期更新:frp 偶有安全修复,保持版本较新。
七、frp 与同类方案怎么选
| 方案 | 部署成本 | 是否需要自有服务器 | 适用场景 |
|---|---|---|---|
| frp | 低,单二进制 | 需要一台公网服务器 | 自建、可控、可同时穿透多端口 |
| ngrok | 零,注册即用 | 不需要(用官方隧道) | 临时演示、快速联调,免费版域名随机 |
| Cloudflare Tunnel | 中 | 不需要(需 Cloudflare 域名) | 把站点安全暴露,自带 CDN 与防护 |
| WireGuard | 中 | 需要服务器组点对点 | 组建私有网络而非单端口暴露 |
八、排错与最佳实践
- 连不上:先
telnet 公网IP 7000确认控制端口可达,再查 frps/frpc 日志(默认 stdout)。 - token 报错:两端
auth.token必须完全一致,含大小写。 - Web 访问 404:确认
customDomains的 DNS 已解析到 frps,且vhostHTTPPort与访问端口一致。 - 避免长期裸奔:演示用完即删对应 proxy;生产穿透务必叠加 TLS + 反向代理。
- 自动化触发:把 frpc 启动写进开机任务,结合 GitHub Actions 做配置下发,团队成员一键接入。
九、小结
内网穿透把”没有公网 IP”这个障碍彻底抹平,而 frp 以极简的配置做到了生产可用的稳定。记住一个判断口诀:要”暴露端口”用 frp,要”打通两张网”用 WireGuard。把 token、TLS、反向代理这三道锁上好,你就能既方便又安全地随时连回自己的内网世界。




