动机
学校的服务器,NAT上的管理权在网管,想把一些服务开放到公网上就得做内网穿透。STUN
和ZeroTier
太麻烦,且需要依赖别人的服务器,被排除了。自己有NAS、有公网IPv4地址、有域名,做FRP
穿透是最好的选择。
找遍全网,基本都是介绍在云主机上部署FRPS
+Nginx
的方案,对于家用NAS来说太麻烦;一些回答也太冗长,不简洁、太陈旧。
原理
FRP
的英文全称是Fast Reverse Proxy,就是一种代理。
- 服务端叫
FRPS
,要有能侦听公网端口的能力,且其连接公网的设备要能通过域名或固定IP被访问到。
需侦听一个bind_port
,和一堆remote_port
。把remote_port
收到的数据,转发给bind_port
。
需访问FRPS
的bind_port
,根据收到的内容,代理到指定的local_ip
和local_port
。
- 用户端访问
FRPS
的remote_port
,就等同于访问各local_ip
的local_port
。
可见,其本质是由于客户端缺少侦听公网端口的能力,FRP
就在服务端开放这些端口(remote_port
),并通过bind_port
这个通道让客户端自己把所需的服务代理到内网。整个系统对外开放的总端口数并没有减少,至少还增加了一个bind_port
。
配置说明
网络拓扑图如下所示,家里的NAT均可控,学校的NAT不可控。其中,绿色虚线代表HTTPS的访问通道;紫色的虚线代表TCP、UDP等普通应用的访问通道;红色虚线代表固有通道。
NAT的配置
需要把FRPC
上指定使用的端口在家庭路由器上做端口转发,转发到NAS;再把NAS上的这些端口转发给容器。
FRPC
上配置的server_port
最终转发到FRPS
上配置的bind_port
,FRPC
上配置的remote_port
最终也要能转发到FRPS
上。
lucky是个好东西,不光可以做泛域名的DDNS和SSL证书,还能做子域名的泛域名DDNS、SSL证书和反向代理。这里我们先设置*.university.example.com
的DDNS,再设置*.university.example.com
的SSL证书,最后把https://*.university.example.com:6666
(proxy port
)代理到http://frps_ip:8080
(vhost_http_port
)。以上,就完成了拥有SSL证书的泛子域名反向代理。
FRP上的配置
TCP、UDP等穿透很简单,把remote_port
和local_ip
+local_port
建立联系即可。
HTTP的穿透,需要配合FRP
上的代理功能。FRPS
上,指定泛域名subdomain_host = university.example.com
;FRPC
上, 根据不同的subdomain
选择对应的local_ip
和local_port
。由于FRPS
和FRPC
之间是HTTP明文传输,开启了加密use_encryption
;其实FRP
还支持双端SSL认证,太麻烦就没搞(谁会没事闲的攻击我呢?哈哈)。
下面给出4份配置文件,配合网络拓扑图一看就懂。
服务端配置
docker-compose.yaml
version: '3.3'
services:
frps:
image: snowdreamtech/frps
environment:
TZ: Asia/Shanghai
restart: unless-stopped
ports:
- "7070:7070" # dashboard
- "8000:8000" # bind
- "8001:8001" # App 1
- "8002:8002" # App 2
- "8080:8080" # http
volumes:
- ./frps.toml:/etc/frp/frps.toml
配置文件frps.toml
这里要注意,最新版的服务端和客户端的配置文件扩展名不再是.ini
,而是.toml
。
[common]
bind_port = 8000
token = PrNnmRqYrsSLpWpmTFBBsdCphHqtfFGk
# HTTP协议相关
vhost_http_port = 8080
subdomain_host = university.example.com
# 以下为看板端口和用户/密码,非必须
dashboard_user = admin
dashboard_pwd = 123456
dashboard_port = 7070
客户端配置
docker-compose.yaml
version: '3.3'
services:
frpc:
image: snowdreamtech/frpc
environment:
TZ: Asia/Shanghai
restart: unless-stopped
ports:
- "7070:7070" # dashboard
volumes:
- ./frpc.toml:/etc/frp/frpc.toml
配置文件frpc.toml
[common]
server_addr = cloud.example.com
server_port = 8000
token = PrNnmRqYrsSLpWpmTFBBsdCphHqtfFGk # 和服务端的token一致
# 指定可用的域名服务器以访问公网,特定环境下可能需要
dns_server = 114.114.114.114
[App 1]
type = tcp
local_ip = 192.168.1.2
local_port = 5901
remote_port = 8001
[App 2]
type = tcp
local_ip = 192.168.1.3
local_port = 3389
remote_port = 8002
[Gitlab]
type = http
local_ip = 192.168.1.10
local_port = 8080
subdomain = gitlab
use_encryption = true
[iKuai]
type = http
local_ip = 192.168.1.11
local_port = 80
subdomain = gw
use_encryption = true
# 以下为看板端口和用户/密码,非必须
admin_port = 7070
admin_user = admin
admin_pwd = 123456
效果
App 1:访问cloud.example.com
的tcp 8001
端口,被穿透到学校内网的192.168.1.2
的tcp 5901
端口。
App 2:访问cloud.example.com
的tcp 8002
端口,被穿透到学校内网的192.168.1.3
的tcp 3389
端口。
GitLab HTTP:访问https://gitlab.university.example.com:6666
,被穿透到学校内网的http://192.168.1.10:8080
。
iKuai HTTP:访问https://gw.university.example.com:6666
,被穿透到学校内网的http://192.168.1.11:80
。
贡献
本文通过图文介绍了FRP
内网穿透的原理,提出了一种在NAT环境下利用docker-compose
一键部署FRPS
和FRPC
容器进行内网穿透的方案。配合lucky
反向代理,实现了低代码构建基于泛子域名、带SSL证书的HTTP内网穿透。
阅读原文:https://zhuanlan.zhihu.com/p/687477877
该文章在 2025/1/13 18:41:00 编辑过