什么是 frp

17 阅读6分钟

一句话概括

frp(Fast Reverse Proxy)是一个开源的内网穿透工具,让你把藏在内网(家里、公司)的服务暴露到公网,外面的人也能访问。

解决什么问题

你在家里的 Mac 上跑了一个 AI 服务,想让朋友通过网址访问。但问题是:

你的 Mac(内网 IP: 192.168.1.100)
  → 路由器(NAT)
    → 运营商(大概率没有公网 IP)
      → 互联网

朋友根本没法直接连到你的 Mac

frp 的作用就是在中间架一座桥:

你的 Mac ──frpc──→ 公网服务器(frps) ←── 朋友访问
          主动连出        被动接入

frpc(客户端)从内网主动连接到公网服务器上的 frps(服务端),建立一条隧道。外部用户访问公网服务器的某个端口,流量就通过隧道转发到你的内网服务。

核心概念

frps(服务端)

运行在有公网 IP 的服务器上,负责:

  • 监听端口,等待 frpc 连接
  • 接收外部用户的请求
  • 通过隧道转发到 frpc

frpc(客户端)

运行在你的内网机器上,负责:

  • 主动连接 frps,建立隧道
  • 接收 frps 转发过来的请求
  • 把请求转发给本地服务

关键:是 frpc 主动连出去

这就是为什么 frp 能穿透内网 —— 内网机器无法被外部访问,但可以主动向外发起连接。frpc 主动连接 frps,建立一条长连接隧道,后续流量就通过这条隧道双向传输。

安装

服务端(公网服务器,Linux)

# 下载最新版 (以 v0.61.1 为例)
wget https://github.com/fatedier/frp/releases/download/v0.61.1/frp_0.61.1_linux_amd64.tar.gz
tar -xzf frp_0.61.1_linux_amd64.tar.gz
cd frp_0.61.1_linux_amd64

# 里面有两个二进制文件:
# frps - 服务端
# frpc - 客户端

客户端(Mac)

brew install frpc

或者直接下载 macOS 版本解压使用。

配置与使用

最简配置:暴露一个 TCP 端口

服务端 frps.toml

bindPort = 7000              # frps 监听的端口,frpc 连这个

auth.method = "token"
auth.token = "your-password" # 认证密码,两端必须一致

启动:

./frps -c frps.toml

客户端 frpc.toml

serverAddr = "45.207.210.130"  # 公网服务器 IP
serverPort = 7000

auth.method = "token"
auth.token = "your-password"

[[proxies]]
name = "my-web"          # 代理名称,随便起
type = "tcp"             # 协议类型
localIP = "127.0.0.1"   # 本地服务地址
localPort = 3000         # 本地服务端口
remotePort = 6100        # 公网暴露的端口

启动:

frpc -c frpc.toml

效果:访问 45.207.210.130:6100 = 访问你本地的 127.0.0.1:3000

多个服务同时穿透

一个 frpc 可以同时穿透多个服务,添加多个 [[proxies]] 即可:

serverAddr = "45.207.210.130"
serverPort = 7000
auth.method = "token"
auth.token = "your-password"

[[proxies]]
name = "ai-chat"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3000
remotePort = 6100

[[proxies]]
name = "my-blog"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 8080

[[proxies]]
name = "ssh-access"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6022

这样公网服务器上就有三个端口分别映射到你本地的三个服务。

HTTP 类型代理(支持域名)

除了 TCP 直接转发,frp 还支持 HTTP 类型,可以通过域名区分不同服务,共用 80 端口:

服务端额外配置

bindPort = 7000
vhostHTTPPort = 80       # HTTP 代理监听的端口

客户端

[[proxies]]
name = "ai-web"
type = "http"
localPort = 3000
customDomains = ["ai.yourdomain.com"]  # 通过域名区分

[[proxies]]
name = "blog-web"
type = "http"
localPort = 8080
customDomains = ["blog.yourdomain.com"]

把这两个域名的 DNS 都指向公网服务器,frps 会根据请求的域名把流量转发到不同的本地服务。

完整数据流

以本项目为例,一个请求的完整路径:

1. 用户发起请求
   curl http://45.207.210.130:6100/chat

2. 到达公网服务器
   frps 监听 6100 端口,收到请求

3. frps 查找映射
   端口 6100 → 隧道 "gemma4-chat" → frpc

4. 通过隧道转发
   frps ──长连接隧道──→ frpc

5. frpc 转发到本地
   frpc → host.docker.internal:3000 → chat-api 容器

6. chat-api 处理请求
   chat-api → Ollama(localhost:11434) → Gemma4 推理

7. 原路返回
   Gemma4 结果 → chat-api → frpc → frps → 用户

在 Docker 中运行 frpc

如果你用 OrbStack/Docker 管理服务,frpc 也可以容器化:

# docker-compose.yml
services:
  frpc:
    image: snowdreamtech/frpc:latest
    container_name: frpc
    volumes:
      - ./frpc.toml:/etc/frp/frpc.toml
    restart: unless-stopped

注意:frpc 在容器中运行时,localIP 不能写 127.0.0.1(那是容器自身),要写 host.docker.internal(指向 Mac 宿主机):

[[proxies]]
name = "my-service"
type = "tcp"
localIP = "host.docker.internal"  # 不是 127.0.0.1
localPort = 3000
remotePort = 6100

用 systemd 保持后台运行

服务端(Linux)

sudo tee /etc/systemd/system/frps.service << 'EOF'
[Unit]
Description=frp server
After=network.target

[Service]
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now frps

客户端(Mac,使用 launchd)

cat > ~/Library/LaunchAgents/com.frpc.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.frpc</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/bin/frpc</string>
        <string>-c</string>
        <string>/path/to/frpc.toml</string>
    </array>
    <key>KeepAlive</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF

launchctl load ~/Library/LaunchAgents/com.frpc.plist

安全注意事项

1. 必须设置认证

没有认证的 frps 任何人都能连上来穿透,相当于把你的服务器当成公共代理:

# frps.toml 和 frpc.toml 都要配置
auth.method = "token"
auth.token = "一个足够复杂的密码"

2. 防火墙只开必要端口

# 服务器上只开放需要的端口
sudo ufw allow 7000    # frps 通信端口
sudo ufw allow 6100    # gemma4-chat 暴露端口
# 不要 ufw allow 1-65535

3. 搭配 Nginx + HTTPS

不要让用户直接访问 IP:端口,用 Nginx 套一层域名和 SSL:

用户 → Nginx(443/HTTPS) → frps(6100) → frpc → 本地服务

4. 不要暴露敏感服务

数据库(3306、5432)、SSH(22)等服务尽量不要穿透到公网,如果必须穿透 SSH,建议改端口并使用密钥登录。

常见问题

Q: frpc 连不上 frps

检查清单:

  1. 服务器防火墙是否放行了 bindPort(默认 7000)
  2. frps 是否正在运行:ps aux | grep frps
  3. 两端的 auth.token 是否一致
  4. serverAddr 是否填对
# 测试端口连通性
telnet 45.207.210.130 7000

Q: 穿透成功但访问超时

  • 检查本地服务是否真的在运行
  • 检查 localIPlocalPort 是否正确
  • 如果 frpc 在容器中,确认用了 host.docker.internal

Q: 速度慢

frp 本身只是转发,速度取决于:

  • 公网服务器的带宽
  • 你家里的上行带宽
  • 服务器和你之间的网络延迟

Q: frpc 断线后能自动重连吗

能。frpc 内置了断线重连机制,如果网络中断会自动重新连接。用 Docker 的 restart: unless-stopped 或 systemd 的 Restart=always 可以保证进程级别的持续运行。

总结

概念说明
frp 是什么内网穿透工具,把内网服务暴露到公网
frps服务端,跑在有公网 IP 的服务器上
frpc客户端,跑在你的内网机器上
原理frpc 主动连接 frps 建立隧道,流量双向传输
前提你需要一台有公网 IP 的服务器

一句话总结:frp 就是让你在家里跑服务,全世界都能访问。