一句话概括
frp(Fast Reverse Proxy)是一个开源的内网穿透工具,让你把藏在内网(家里、公司)的服务暴露到公网,外面的人也能访问。
解决什么问题
你在家里的 Mac 上跑了一个 AI 服务,想让朋友通过网址访问。但问题是:
markdown
你的 Mac(内网 IP: 192.168.1.100)
→ 路由器(NAT)
→ 运营商(大概率没有公网 IP)
→ 互联网
朋友根本没法直接连到你的 Mac
frp 的作用就是在中间架一座桥:
markdown
你的 Mac ──frpc──→ 公网服务器(frps) ←── 朋友访问
主动连出 被动接入
frpc(客户端)从内网主动连接到公网服务器上的 frps(服务端),建立一条隧道。外部用户访问公网服务器的某个端口,流量就通过隧道转发到你的内网服务。
核心概念
frps(服务端)
运行在有公网 IP 的服务器上,负责:
- 监听端口,等待 frpc 连接
- 接收外部用户的请求
- 通过隧道转发到 frpc
frpc(客户端)
运行在你的内网机器上,负责:
- 主动连接 frps,建立隧道
- 接收 frps 转发过来的请求
- 把请求转发给本地服务
关键:是 frpc 主动连出去
这就是为什么 frp 能穿透内网 ------ 内网机器无法被外部访问,但可以主动向外发起连接。frpc 主动连接 frps,建立一条长连接隧道,后续流量就通过这条隧道双向传输。
安装
服务端(公网服务器,Linux)
bash
# 下载最新版 (以 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)
bash
brew install frpc
或者直接下载 macOS 版本解压使用。
配置与使用
最简配置:暴露一个 TCP 端口
服务端 frps.toml:
toml
bindPort = 7000 # frps 监听的端口,frpc 连这个
auth.method = "token"
auth.token = "your-password" # 认证密码,两端必须一致
启动:
bash
./frps -c frps.toml
客户端 frpc.toml:
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 # 公网暴露的端口
启动:
bash
frpc -c frpc.toml
效果 :访问 45.207.210.130:6100 = 访问你本地的 127.0.0.1:3000
多个服务同时穿透
一个 frpc 可以同时穿透多个服务,添加多个 [[proxies]] 即可:
toml
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 端口:
服务端额外配置:
toml
bindPort = 7000
vhostHTTPPort = 80 # HTTP 代理监听的端口
客户端:
toml
[[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 会根据请求的域名把流量转发到不同的本地服务。
完整数据流
以本项目为例,一个请求的完整路径:
markdown
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 也可以容器化:
yaml
# 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 宿主机):
toml
[[proxies]]
name = "my-service"
type = "tcp"
localIP = "host.docker.internal" # 不是 127.0.0.1
localPort = 3000
remotePort = 6100
用 systemd 保持后台运行
服务端(Linux)
bash
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)
bash
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 任何人都能连上来穿透,相当于把你的服务器当成公共代理:
toml
# frps.toml 和 frpc.toml 都要配置
auth.method = "token"
auth.token = "一个足够复杂的密码"
2. 防火墙只开必要端口
bash
# 服务器上只开放需要的端口
sudo ufw allow 7000 # frps 通信端口
sudo ufw allow 6100 # gemma4-chat 暴露端口
# 不要 ufw allow 1-65535
3. 搭配 Nginx + HTTPS
不要让用户直接访问 IP:端口,用 Nginx 套一层域名和 SSL:
scss
用户 → Nginx(443/HTTPS) → frps(6100) → frpc → 本地服务
4. 不要暴露敏感服务
数据库(3306、5432)、SSH(22)等服务尽量不要穿透到公网,如果必须穿透 SSH,建议改端口并使用密钥登录。
常见问题
Q: frpc 连不上 frps
检查清单:
- 服务器防火墙是否放行了
bindPort(默认 7000) - frps 是否正在运行:
ps aux | grep frps - 两端的
auth.token是否一致 serverAddr是否填对
bash
# 测试端口连通性
telnet 45.207.210.130 7000
Q: 穿透成功但访问超时
- 检查本地服务是否真的在运行
- 检查
localIP和localPort是否正确 - 如果 frpc 在容器中,确认用了
host.docker.internal
Q: 速度慢
frp 本身只是转发,速度取决于:
- 公网服务器的带宽
- 你家里的上行带宽
- 服务器和你之间的网络延迟
Q: frpc 断线后能自动重连吗
能。frpc 内置了断线重连机制,如果网络中断会自动重新连接。用 Docker 的 restart: unless-stopped 或 systemd 的 Restart=always 可以保证进程级别的持续运行。
总结
| 概念 | 说明 |
|---|---|
| frp 是什么 | 内网穿透工具,把内网服务暴露到公网 |
| frps | 服务端,跑在有公网 IP 的服务器上 |
| frpc | 客户端,跑在你的内网机器上 |
| 原理 | frpc 主动连接 frps 建立隧道,流量双向传输 |
| 前提 | 你需要一台有公网 IP 的服务器 |
一句话总结:frp 就是让你在家里跑服务,全世界都能访问。