一、什么是内网穿透?
在日常开发和运维中,我们经常遇到这样的场景:在本地开发了一个 Web 服务想给远程同事演示;家里的 NAS 想在公司访问;机房内网的测试环境需要临时暴露给外部调用。这些场景的共同痛点是——服务运行在内网,没有公网 IP,外部无法直接访问。
frp(Fast Reverse Proxy)是 GitHub 上 Star 数超过 83,000 的开源内网穿透工具,由 Go 语言编写,单二进制文件部署,性能极高。它通过一台具有公网 IP 的中转服务器,将内网服务安全地暴露到公网。
二、frp 服务端部署(frps)
下载与安装
# 下载最新版本(替换为实际版本号)
wget https://github.com/fatedier/frp/releases/download/v0.58.0/frp_0.58.0_linux_amd64.tar.gz
tar -xzf frp_0.58.0_linux_amd64.tar.gz
cd frp_0.58.0_linux_amd64
# 只需要 frps 和 frps.toml
cp frps /usr/local/bin/
mkdir -p /etc/frp
服务端配置文件
# /etc/frp/frps.toml
bindPort = 7000 # frp 服务端监听端口
# Dashboard 监控面板
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "your_strong_password"
# 认证令牌(客户端连接需要匹配)
auth.method = "token"
auth.token = "your_secret_token_here"
# 允许客户端绑定的端口范围
allowPorts = [
{ start = 6000, end = 6100 }, # TCP 代理端口
{ start = 8000, end = 8010 }, # HTTP 代理端口
]
# 日志配置
log.to = "/var/log/frps.log"
log.level = "info"
log.maxDays = 7
systemd 服务配置
# /etc/systemd/system/frps.service
[Unit]
Description=frp Server
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
# 启动服务
sudo systemctl daemon-reload
sudo systemctl enable frps --now
sudo systemctl status frps
三、frp 客户端配置(frpc)
常见代理场景
场景一:暴露本地 Web 服务
# /etc/frp/frpc.toml
serverAddr = "your-server-ip"
serverPort = 7000
auth.token = "your_secret_token_here"
[[proxies]]
name = "web-demo"
type = "http"
localIP = "127.0.0.1"
localPort = 3000
customDomains = ["demo.yourdomain.com"]
场景二:TCP 端口映射(SSH/NAS/数据库)
[[proxies]]
name = "ssh-internal"
type = "tcp"
localIP = "192.168.1.100"
localPort = 22
remotePort = 6022
# 外部通过 your-server-ip:6022 即可 SSH 到内网机器
场景三:HTTPS 穿透(自动 SSL)
[[proxies]]
name = "secure-web"
type = "https"
localIP = "127.0.0.1"
localPort = 443
customDomains = ["secure.yourdomain.com"]
# frp 服务端自动处理 SSL 证书
transport.protocol = "tls"
四、安全加固措施
- 强认证机制:使用
auth.token而非默认的 token 模式,token 长度至少 32 字符 - 端口白名单:通过
allowPorts严格限制客户端可绑定的端口范围 - Dashboard 防护:Dashboard 仅监听 127.0.0.1,通过 SSH 隧道访问:
ssh -L 7500:127.0.0.1:7500 user@your-server - 防火墙控制:仅开放必要的端口(7000、以及约定的代理端口)
- 连接加密:在生产环境启用
transport.useEncryption = true和transport.useCompression = true
五、常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 连接被拒绝 | 防火墙未放行 | ufw allow 7000/tcp |
| token 不匹配 | 服务端/客户端 token 不一致 | 检查两边 auth.token |
| 端口冲突 | remotePort 被占用 | ss -tlnp \| grep 端口号 |
| 域名未生效 | DNS 未解析或未配置 | A 记录指向 frps 服务器 IP |
💡 最佳实践
生产环境建议为每个客户端生成独立 token,便于后续审计和权限回收。使用 subdomain 模式而非 customDomains 可实现泛域名代理(*.frp.yourdomain.com),减少 DNS 配置工作量。