reserve proxy by frp

使用背景

在没有公网IP的情况下需要将运营商内网的服务暴露到外网访问就需要使用到反向代理。需要有一台能够被公网访问的机器,局域网内的机器主动与公网机器建立tcp连接。公网机器处理用户的请求,并把流量转发给局域网机器。这种原理与服务发现类似,而 FRP就优雅地实现了该功能。

frp 使用go语言编写,只有一个服务端文件和一个客户端文件加上配置文件就能快速部署,非常优雅。frp使用go语言编写,内嵌了一个 vue 的页面,方便在网页看到对应的流量转发和服务注册情况。

FRP 服务端配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bindPort = 7100  # 服务端监听的端口
# transport.heartbeatTimeout = 90 # 默认的心跳超时时间,超过这个时间没有收到心跳认为客户端以及断开
# transport.tcpKeepalive = 7200 # tcp连接的保活时间,超过这个时间tcp要重新建立连接

# 虚拟主机端口配置
vhostHTTPPort = 8888 # 可以 proxy_pass 用户请求到客户端,当客户端type 是 http 时

# 鉴权配置
# auth.method = "token" # 支持 token 以及 OIDC
auth.token = "xxxxx"

# ssh 跳板配置
sshTunnelGateway.bindPort = 2222 # 网关端口,frp监听的,客户端ssh连接时需指定
sshTunnelGateway.privateKeyFile = "./ssh/id_rsa" # ssh网关对客户端鉴权的私钥,默认为空使用自动生成的
sshTunnelGateway.autoGenPrivateKeyPath = "./ssh/frp_autogen_ssh_key" # 默认是 ./.autogen_ssh_key frp自动生成的密钥文件目录
sshTunnelGateway.authorizedKeysFile = "./ssh/authorized_keys" # 指定受信的公钥

# 管理后台配置
# webServer.addr = "127.0.0.1" # 地址
webServer.port = 8880 # 端口
webServer.user = "xxx" # 用户名,可选
webServer.password = "xxx" # 密码,可选

所有的配置项可以参考: https://github.com/fatedier/frp/blob/dev/conf/frps_full_example.toml

./frps -c frps.toml 来启动服务端。

NGINX 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# mobile sub domain
upstream frps_dashboard {
server localhost:8880 weight=5;
}
server {
listen 443 ssl;
listen [::]:443 ssl;

ssl_certificate /xxx/kangqingfei.cn.pem;
ssl_certificate_key /xxx/kangqingfei.cn.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;

ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
#listen 80;
server_name mobile.kangqingfei.cn;
root /usr/share/nginx/;

location = /admin/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

rewrite ^/admin/(.*)$ /$1 break;
proxy_pass http://frps_dashboard;
#proxy_pass http://127.0.0.1:8880/;
}
location ^~ /static/ {
proxy_pass http://frps_dashboard;
}
location ^~ /api/ {
proxy_pass http://frps_dashboard;
}

location / {
proxy_pass http://127.0.0.1:8888;
}
}
server {
listen 80;
server_name mobile.kangqingfei.cn;
rewrite ^(.*)$ https://$host$1 permanent;
}

防火墙配置

CentOS 8 SELinux 需要配置防火墙才能访问对应的端口:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 先查看哪些端口被占用了
firewall-cmd --permanent --list-all
# 开启端口映射并重启防火墙
firewall-cmd --permanent --add-port=7100/tcp
systemctl restart firewalld.service # 或者 firewall-cmd --reload

# 端口分配
2201: mbp16
2202: desktop macos catalina
2203: oppo findx5 termux
2204: desktop linux
2205: xps13 macos catalina
2206: rk3399_device1 ubuntu

FRP 客户端配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
user = "rk3399" # 指定客户机的名字,在管理后台会以 {user}.{proxy} 命名一条连接

serverAddr = "127.0.0.1" # 服务端的IP,也可以使用域名,例如 mobile.kangqingfei.cn
serverPort = 7100 # 服务端监听的端口
auth.token = "xxxx" # 注册到服务端时需要鉴权的密钥

# 客户端的管理后台配置
webServer.addr = "192.168.2.102"
webServer.port = 7400
webServer.user = "admin"
webServer.password = "admin"

[[proxies]] # 注册一个服务,可以注册多个
name = "python web" # 名字
type = "tcp" # 协议类型
localIP = "127.0.0.1" # 指定注册的地址,可以是局域网的其他机器
localPort = 8000 # 需要被反代的本地端口
remotePort = 7200 # 服务端访问需要使用的端口,如果是0 就会使用随机分配的端口
customDomains = ["mobile.kangqingfei.cn"] # 可以用来区分不同的服务

还有一些带宽等相关配置可以参考:https://github.com/fatedier/frp/blob/dev/conf/frpc_full_example.toml

./frpc -c frpc.toml 来启动客户端。

image-20240216000432208

然后访问 mobile.kangqingfei.cn:7200 就能访问到局域网内的 8000 端口的python服务了

image-20240216000840853

image-20240216000930878

同样可以用来代理ssh服务

image-20240216001654604

另外还支持反代 dns,udp, http,socket 等协议。

FRP 管理后台

客户端,主要进行配置的热更新

image-20240216001356268

服务端,主要查看当前注册的连接

image-20240216000620345

FRP 实现 SSH 跳板

SSH Tunnel Gateway,通常用来作为外网到内容ssh的跳板机,对连接进行审计和鉴权(例如两步验证)。这就需要客户端A拥有 到跳板机B的连接权限,再检查客户端到目标机器C的连接权限。

ssh 跳板机逻辑

1
2
3
4
5
# 网关 B配置
sshTunnelGateway.bindPort = 2222
sshTunnelGateway.privateKeyFile = "~/.ssh/id_rsa" # 使用向目标机器登陆的私钥,如果为空则使用autoGenPrivateKeyPath
sshTunnelGateway.autoGenPrivateKeyPath = "~/.ssh/frp_autogen_ssh_key" # 如果privateKeyFile为空,将使用这个作为私钥发起登陆,这个也为空就自动生成
sshTunnelGateway.authorizedKeysFile = "~/.ssh/authorized_keys"

被代理机器(任意小鸡)C 发起代理(开启后门)

1
2
3
4
5
6
7
8
9
10
11
# 反代tcp or ssh

ssh -R :80:{local_ip:port} v0@{frps_address} -p {frps_ssh_listen_port} {tcp|http|https|stcp|tcpmux} --remote_port {real_remote_port} --proxy_name {proxy_name} --token {frp_token}

ssh -R :80:localhost:22 [email protected] -p 2222 tcp --token xxxx --remote_port 2206 --proxy_name rk3399 #这个 v0 目前貌似没啥作用

# 被代理机器显示
User: qingfei.kang@xxx
ProxyName: [email protected]
Type: tcp
RemoteAddress: :2201

网关B登录

ssh -p 2201 [email protected] 验证ok

客户端 A 登录

ssh -t [email protected] ssh -p 2201 [email protected] 验证ok

ssh [email protected] -p 2201 直接连接,验证ok

反代 http

1
2
3
4
5
ssh -R :80:127.0.0.1:8080 v0@{frp address} -p 2200 http --proxy_name "test-http"  --custom_domain test-http.frps.com

ssh -R :80:localhost:8000 [email protected] -p 2222 http --token xxx --custom_domain cd.kangqingfei.cn # 绑定域名+端口 可以用于映射不同服务,但是端口不能变

ssh -R :80:localhost:8000 [email protected] -p 2222 http --token xxx --custom_domain 127.0.0.1 # 必须绑定,不然无法 proxy_pass
T B
站点访问量: / , 本页阅读量:
T B