一、什么是内网穿透?

在日常开发和运维中,我们经常遇到这样的场景:在本地开发了一个 Web 服务想给远程同事演示;家里的 NAS 想在公司访问;机房内网的测试环境需要临时暴露给外部调用。这些场景的共同痛点是——服务运行在内网,没有公网 IP,外部无法直接访问

frp(Fast Reverse Proxy)是 GitHub 上 Star 数超过 83,000 的开源内网穿透工具,由 Go 语言编写,单二进制文件部署,性能极高。它通过一台具有公网 IP 的中转服务器,将内网服务安全地暴露到公网。

外部用户 互联网访问 HTTPS:7000 frps 公网服务器 frps: 7000 Dashboard: 7500 控制连接 frpc 内网客户端 Type: tcp/http local_port: 3000 内网服务 :3000 ↑ 服务端 (frps) ↑ 客户端 (frpc) frp 内网穿透架构:外部 → frps(公网) → 控制通道 → frpc(内网) → 本地服务

二、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"

四、安全加固措施

  1. 强认证机制:使用 auth.token 而非默认的 token 模式,token 长度至少 32 字符
  2. 端口白名单:通过 allowPorts 严格限制客户端可绑定的端口范围
  3. Dashboard 防护:Dashboard 仅监听 127.0.0.1,通过 SSH 隧道访问:
    ssh -L 7500:127.0.0.1:7500 user@your-server
  4. 防火墙控制:仅开放必要的端口(7000、以及约定的代理端口)
  5. 连接加密:在生产环境启用 transport.useEncryption = truetransport.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 配置工作量。