公网服务器用 Docker 跑 frps,内网机器原生跑 frpc。
服务端用 host 网络,所以客户端想用哪个端口都行——你只需要管一件事:在云厂商安全组放行端口。
一、拓扑
外网 ──► <服务器公网IP>:6000 / 6001 / 任意远程端口
│
┌───────▼────────┐
│ 云服务器 │
│ frps (Docker) │
│ network_mode:host│
└───────▲────────┘
│ frpc 主动外连 bindPort
│(出方向,客户端不需要公网 IP,也不用路由器端口映射)
┌───────┴────────┐
│ 内网机器 │
│ frpc 原生运行 │
└────────────────┘二、服务端:4 步搞定
1. 装 Docker
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker国内拉镜像慢可配加速(以腾讯云为例):
echo '{ "registry-mirrors": ["https://mirror.ccs.tencentyun.com"] }' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker2. 改配置
编辑 .env,把两个 CHANGE_ME_* 换成你自己的随机值:
openssl rand -hex 16 # 用它生成 FRP_TOKENFRP_TOKEN=你的32位随机串
FRPS_BIND_PORT=7000
FRPS_DASHBOARD_PORT=7500
FRPS_DASHBOARD_USER=admin
FRPS_DASHBOARD_PASSWORD=你的强密码3. 构建并启动
bash deploy.shdeploy.sh 会先做 9 步预检再构建。不想上传 20MB 的 frps 二进制的话:
DOCKERFILE=Dockerfile.download bash deploy.sh # 构建时自动下载 frp4. 安全组放行
| 协议 | 端口 | 源 | 用途 |
|---|---|---|---|
| TCP | 7000 | 0.0.0.0/0 | frpc 接入 |
| TCP | 6000-6010 | 0.0.0.0/0 | 各服务对外访问 |
| TCP | 7500 | 只填你自己的 IP | 管理面板 |
host 网络下安全组是唯一开关。 客户端新增代理时,只加一条安全组规则即可,不用改配置、不用重建容器。
三、客户端:一份配置文件
把 fnos-frpc.toml 拷到内网机器上改名 frpc.toml,改三处:
serverAddr = "你的服务器公网IP"
auth.token = "与服务端 FRP_TOKEN 完全一致"
[[proxies]]
name = "web"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 6000 # 随便填,只要在安全组放行启动:./frpc -c frpc.toml
开机自启用 frpc.service(记得改里面的路径)。
飞牛 fnOS 用户:默认 Web 端口是 5666(HTTPS 5667),SSH 需在设置里开启。
四、验证
服务端日志出现 new proxy [xxx] type [tcp] success 即成功。
外网访问 <服务器公网IP>:6000 测试。
五、三个必看的坑
坑 1:注释里的大括号会让 frp 启动失败
template: frp:5: missing value for commandfrp 会把整份配置文件当 Go 模板渲染,连注释也会被解析。
注释里写一对孤立的大括号(比如想说明语法),就会被当成"空动作"直接报错。
合法写法只有一种:{{ .Envs.变量名 }}。deploy.sh 的模板自检会提前拦下并报出行号。
坑 2:frps 必须用 host 网络
frps 的职责是"按客户端要求随时开端口",而 Docker 的 ports: 是启动时写死的——两者天然矛盾。
症状最迷惑人:日志显示 new proxy success、tcp proxy listen port [...] 一切正常,外网却连不上。
因为那句日志说的是容器里监听了,而端口没被发布到宿主机。
解法就是 network_mode: host——frps 直接使用宿主机网络栈,这个矛盾彻底消失。
代价是容器失去网络隔离,别让别的服务占用 7000 / 7500 及各远程端口。
坑 3:用三分法定位问题,别瞎猜
做一次 TCP 连通性探测,三种结果对应三种原因:
| 结果 | 含义 | 处理 |
|---|---|---|
| TIMEOUT | 包被无声丢弃 | 安全组没放行 |
| REFUSED | 网络到达了主机,但没人监听该端口 | 服务没起来 / 客户端离线 |
| OPEN | 正常 | — |
nc -vz <服务器公网IP> 7000 # Linux
Test-NetConnection <IP> -Port 7000 # Windows PowerShell⚠️ TIMEOUT 时你无法判断服务有没有在跑——过滤层把状态掩盖了。
必须先放行,才能验证服务;放行后若变成 REFUSED,才说明服务没起。
六、新增一个穿透服务:两步
- 安全组加一条规则(放行新的远程端口)
- 客户端改配置、重启 frpc
不用碰服务端、不用重建容器。
七、安全清单
- 别用默认端口:
FRPS_BIND_PORT换成不常见的高位端口,能挡掉大量扫描 - 面板别全公网开:
7500只放行自己的 IP,或把conf/frps.toml的webServer.addr改成127.0.0.1走 SSH 隧道 - 开 TLS 加密:服务端
transport.tls.force = true,客户端transport.tls.enable = true - token 定期轮换:改
.env和客户端配置,两边重启 - (可选)限制端口范围:
conf/frps.toml启用allowPorts——⚠️ 这会禁止客户端用区间外的端口,与"任意端口"互斥,二选一
八、文件清单
Dockerfile / Dockerfile.download 两种构建方式
docker-compose.yml host 网络
docker/entrypoint.sh 容器入口
conf/frps.toml 服务端配置(模板)
.env 所有可调参数
deploy.sh 一键部署 + 9 步预检
fnos-frpc.toml 客户端配置样例
fnos-frpc.service 客户端开机自启(可选)
.dockerignore 构建上下文裁剪
frps linux/amd64 二进制
LICENSE Apache-2.0改配置后怎么生效
| 改了什么 | 执行 |
|---|---|
.env(端口 / token / 密码) | docker compose up -d |
conf/frps.toml(加功能) | docker compose restart |
两种都不需要重新 build 镜像。
评论 (0)