frp-内网穿透详解
1. 简介与工作原理
frp(Fast Reverse Proxy)是一个高性能的反向代理 / 内网穿透工具。典型部署模式:
- 在公网 VPS上运行
frps(服务端),监听来自frpc的出站持久连接(控制端口,通常 7000)。 - 在内网机器上运行
frpc(客户端),与 frps 建立长连接并注册若干映射(如 tcp/http)。 - 当外部请求到达 frps(公网),frps 根据路由规则把流量转发回对应的 frpc 连接,再由 frpc 转发到本地服务(如 SSH、HTTP)。
重要:frp 的核心不是 P2P 打洞(虽然支持一些直连模式),它通过中心化的 client -> server 长连接 + server 转发 实现稳定穿透。
2. 关键术语
- frps:服务端,部署在有公网 IP 的 VPS。负责接收 frpc 的持久连接并转发外部流量。
- frpc:客户端,部署在内网机器,负责发起到 frps 的长连接并接收转发流量到本地服务。
- bind_port / server_port:frps 用来接收 frpc 连接的端口(默认常见为
7000)。 - vhost_http_port / vhost_https_port:frps 提供的 HTTP/HTTPS 虚拟主机入口端口(用于基于 Host 的路由)。
- subdomain / custom_domains:HTTP 类型代理常用,用于 Host 路由(例如
foo.example.com)。 - remote_port:tcp 类型代理中,frps 上开放的远程端口,被外部直接连接.
3. 先决条件
- 一台有公网 IP 的 VPS(建议静态 IP)。
- VPS 能够开放/允许所需端口(如 7000、80、443、dashboard 端口)。
- 可选:域名(建议,用于子域名映射与 HTTPS)。
- 两端均能下载并运行 frp 二进制或 Docker 镜像。
4. frps(Server)部署
4.1 下载与二进制
从 frp 官方 GitHub Releases 下载与你的系统相匹配的压缩包,解压并把 frps 放到 /usr/local/bin/frps(或你希望的位置)。
示例:
# 假设在 Linux x86_64
wget https://github.com/fatedier/frp/releases/download/vX.Y.Z/frp_X.Y.Z_linux_amd64.tar.gz
tar zxvf frp_X.Y.Z_linux_amd64.tar.gz
sudo mv frp_X.Y.Z_linux_amd64/frps /usr/local/bin/frps
(注意:换成实际版本号)
4.2 frps.toml 示例(基础)
把下面保存为 /etc/frp/frps.toml:
# /etc/frp/frps.toml
[common]
bind_port = 7000
# 可选:HTTP/HTTPS 虚拟主机入口(将公网 80/443 请求交给 frp 做 Host 路由)
vhost_http_port = 80
vhost_https_port = 443
# Dashboard
dashboard_addr = "0.0.0.0"
dashboard_port = 7500
dashboard_user = "admin"
dashboard_pwd = "very_strong_password"
# 基本认证 token
token = "REPLACE_WITH_STRONG_TOKEN"
# subdomain_host = "example.com" # 如果使用 subdomain 模式,请填入你的主域
说明:
token是最基础的认证方式,请务必替换为强字符串并妥善保存。
4.3 启用 TLS(传输加密)思路
frp 支持在 frpc<->frps 之间启用传输层的 TLS。常见做法:
-
最简单(常用):在 VPS 使用 Nginx / Caddy 做 80/443 TLS 终端,frps 继续监听非 TLS 的控制端口(7000),这能把外部 HTTP(S) 先在 VPS 解密,再转发给 frps。证书由 Nginx/Caddy 管理(certbot / ACME)。
-
frp 原生 TLS:配置 frps 的
transport.tls.*(或 frp 文档对应字段)并在 frpc 中提供证书与验证配置;此方式可以在控制通道上启用加密与 单/双向证书验证,但证书发放与管理复杂度上升。
(细节请参考官方 transport.tls 文档,或在需要时将我需要的部署信息给我,我可以生成证书示例和具体的 toml 配置)
4.4 systemd 服务单元示例
创建 /etc/systemd/system/frps.service:
[Unit]
Description=frps service
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
然后:
sudo systemctl daemon-reload
sudo systemctl enable frps
sudo systemctl start frps
sudo journalctl -u frps -f
4.5 Docker / docker-compose 示例
使用社区镜像(示例):fatedier/frps:latest。
version: '3.8'
services:
frps:
image: fatedier/frps:latest
container_name: frps
volumes:
- ./frps.toml:/frp/frps.ini:ro
network_mode: host # 简化端口映射(可选)
restart: always
注意:
network_mode: host会使容器共享宿主机网络,部署时请考虑安全策略;也可用ports:映射端口。
5. frpc(Client)部署
5.1 frpc.toml 示例(常见场景)
保存为 /etc/frp/frpc.toml:
# /etc/frp/frpc.toml
[common]
server_addr = "VPS_PUBLIC_IP_OR_DOMAIN"
server_port = 7000
token = "REPLACE_WITH_STRONG_TOKEN"
# 把内网 SSH 暴露为 VPS 的 6000
[ssh]
type = "tcp"
local_ip = "127.0.0.1"
local_port = 22
remote_port = 6000
# 把本地 web (8080) 通过子域名 app.example.com 映射
[web]
type = "http"
local_port = 8080
subdomain = "app"
说明:
subdomain生效依赖于 frps 的subdomain_host配置和 DNS 的*.example.com指向 VPS。
5.2 systemd 自启示例(客户端)
/etc/systemd/system/frpc.service:
[Unit]
Description=frpc client
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
启用:
sudo systemctl daemon-reload
sudo systemctl enable frpc
sudo systemctl start frpc
sudo journalctl -u frpc -f
6. 域名 / DNS / HTTP(S) 映射要点
- 要通过子域名(
foo.example.com)访问内网 web 服务:在 DNS 中添加A记录或*.example.com指向 VPS 公网 IP。 - frps 必须配置
vhost_http_port(通常 80)与subdomain_host(例如example.com)。访问时 frps 会根据 Host 头或subdomain把请求路由到对应 frpc。 - HTTPS 推荐在 VPS 使用 Nginx/Caddy 做证书管理(Let’s Encrypt)并作为 TLS 终端,Nginx 将解密后的 HTTP 请求交给 frps(或直接反向代理到 frpc,但这会绕过 frps 的 Host 路由)。
7. 常见场景与完整配置模板
7.1 子域名映射 web 服务(app.example.com)
frps.toml(关键项):
[common]
bind_port = 7000
vhost_http_port = 80
vhost_https_port = 443
subdomain_host = "example.com"
token = "supersecret"
frpc.toml:
[common]
server_addr = "vps.example.com"
server_port = 7000
token = "supersecret"
[app]
type = "http"
local_port = 3000
subdomain = "app"
DNS:app.example.com 指向 VPS IP 或 *.example.com 指向 VPS IP。
访问:http://app.example.com 将被路由到内网机器的 3000 端口。
7.2 把本地 22(SSH)暴露为公网 6000
在 frpc 中添加:
[ssh]
type = "tcp"
local_ip = "127.0.0.1"
local_port = 22
remote_port = 6000
外部连接命令(从任意外网主机):
ssh -p 6000 user@VPS_IP
注意:以上方式会在 VPS 上开放 6000 端口并把连接转发到内网机器,请确保 frps 上允许此 remote_port 的使用并做好审计与防护。
8. TLS 与认证(安全建议)
- token:最低限度的认证;把
token设置为强字符串并在两端一致。 - 传输加密:优先在 VPS 用 Nginx/Caddy 做 HTTPS 终端;若需要端到端加密,可启用 frp 原生的 TLS 配置(
transport.tls),并使用证书 + CA 签发策略实现单向或双向验证。 - Dashboard 保护:若启用 dashboard,务必设置强用户名/密码,并限制仅可信 IP 访问(或放在私有网段)。
- 最小暴露原则:仅开放必要端口,限制 remote_port 使用范围,避免把管理口暴露给全网。
9. 常见问题与排查清单
-
frpc 无法连接 frps:
- 检查 VPS 防火墙 / 云安全组是否允许
bind_port(例如 7000)。 - 确认
server_addr/server_port无误。 - 查看两端日志:
journalctl -u frps -f/journalctl -u frpc -f或直接前台运行./frpc -c frpc.toml查看错误。
- 检查 VPS 防火墙 / 云安全组是否允许
-
子域名 HTTP 不生效:
- 检查 DNS 是否生效(
dig app.example.com)。 - 确认 frps 的
vhost_http_port与subdomain_host配置正确。 - 检查是否有其他服务占用 80/443(例如 Nginx),导致 frps 无法绑定端口。
- 检查 DNS 是否生效(
-
TLS 相关问题:
- 若使用 frp 的 transport TLS,请确认证书文件与 chain 配置无误,且客户端与服务端参数匹配。
-
端口被占用 / 403 / 404:
- 检查服务端端口(80/443/7000)是否已由其他进程占用;查看
ss -lntp/netstat -plant。
- 检查服务端端口(80/443/7000)是否已由其他进程占用;查看
如果您觉得这篇文章有帮助,请点个赞吧~
评论
请登录后发表评论
去登录