frp打洞公有云私有云对接初探

前言

公司采用公有云和私有云的部署方案,最近需要我来做一个公有云和私有云部署的对接测试,但是私有云环境那边流程太麻烦了,又是申请公网ip,又是备案,又是审批流程什么的,麻烦死了,这不,我已经卡了两天了,还不知道什么时候能下来,还不能预测后面会碰到的问题

我想做什么

1.私有云环境是在内网里面,内网里面有一台机器可以访问外网

2.公有云部署的测试环境在我的虚拟机里面

3.我想把他们打通,让他们能通信,方便我做部署测试

怎么做

第一反应当然是内网穿透,那就需要一台公网机器,这个好解决,我调查了一下内网穿透方案,传统的如花生壳,新型的 ngrok 都验证过方案是可行的,但是感觉都不怎么好用,发现一个新工具 frp 还不错,据说是一个人不满 ngrok 作者荒废项目,更新太慢自己重写的,听起来不明觉厉

开始做

问题知道了,方案也有了,剩下的就是实施了,这个相对容易,这里主要记录一下 frp 的使用特性和配置方法吧,方便下次再用回头翻

首先奉上 frp 项目 github 地址 https://github.com/fatedier/frp/,项目介绍,frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议,配置也很简单

公网服务器完整配置(server)

要想把内网服务代理到公网,我们需要一台公网服务器,方便一些打洞时候必要数据校验和传输,启动命令非常简单 ./frps -c frps.ini,完整配置文件及注释如下:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# [common] is integral section
[common]
# A literal address or host name for IPv6 must be enclosed
# in square brackets, as in "[::1]:80", "[ipv6-host]:http" or "[ipv6-host%zone]:80"
bind_addr = 0.0.0.0 # 公网服务器ip地址
bind_port = 7000 # 公网服务器和打洞服务器,打洞数据传输端口

# udp port to help make udp hole to penetrate nat
bind_udp_port = 7001

# udp port used for kcp protocol, it can be same with 'bind_port'
# if not set, kcp is disabled in frps
kcp_bind_port = 7000

# specify which address proxy will listen for, default value is same with bind_addr
# proxy_bind_addr = 127.0.0.1

# if you want to support virtual host, you must set the http port for listening (optional)
# Note: http port and https port can be same with bind_port
vhost_http_port = 80 #公网服务器对外http访问接口
vhost_https_port = 443 #公网服务器对外https访问接口

# set dashboard_addr and dashboard_port to view dashboard of frps
# dashboard_addr's default value is same with bind_addr
# dashboard is available only if dashboard_port is set
dashboard_addr = 0.0.0.0
dashboard_port = 7500

# dashboard user and passwd for basic auth protect, if not set, both default value is admin
dashboard_user = admin
dashboard_pwd = admin

# dashboard assets directory(only for debug mode)
# assets_dir = ./static
# console or real logFile path like ./frps.log
log_file = ./frps.log

# trace, debug, info, warn, error
log_level = info

log_max_days = 3

# auth token
token = 12345678

# heartbeat configure, it's not recommended to modify the default value
# the default value of heartbeat_timeout is 90
# heartbeat_timeout = 90

# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
allow_ports = 2000-3000,3001,3003,4000-50000

# pool_count in each proxy will change to max_pool_count if they exceed the maximum value
max_pool_count = 5

# max ports can be used for each client, default value is 0 means no limit
max_ports_per_client = 0

# authentication_timeout means the timeout interval (seconds) when the frpc connects frps
# if authentication_timeout is zero, the time is not verified, default is 900s
authentication_timeout = 900

# if subdomain_host is not empty, you can set subdomain when type is http or https in frpc's configure file
# when subdomain is test, the host used by routing is test.frps.com
subdomain_host = frps.com

# if tcp stream multiplexing is used, default is true
tcp_mux = true

打洞服务器完整配置(client)

打洞服务器指的是内网中一台有外网访问权限的服务器,我们通过他来做反向代理服务器,把外网过来的请求,转发到内网中的服务器,启动命令非常简单 ./frpc -c frpc.ini,完整配置文件及注释如下:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# [common] is integral section
[common]
# A literal address or host name for IPv6 must be enclosed
# in square brackets, as in "[::1]:80", "[ipv6-host]:http" or "[ipv6-host%zone]:80"
server_addr = 0.0.0.0 # 公网服务器ip
server_port = 7000 # 公网服务器和打洞服务器,打洞数据传输端口

# if you want to connect frps by http proxy or socks5 proxy, you can set http_proxy here or in global environment variables
# it only works when protocol is tcp
# http_proxy = http://user:passwd@192.168.1.128:8080
# http_proxy = socks5://user:passwd@192.168.1.128:1080

# console or real logFile path like ./frpc.log
log_file = ./frpc.log

# trace, debug, info, warn, error
log_level = info

log_max_days = 3

# for authentication
token = 12345678

# set admin address for control frpc's action by http api such as reload
admin_addr = 127.0.0.1
admin_port = 7400
admin_user = admin
admin_passwd = admin

# connections will be established in advance, default value is zero
pool_count = 5

# if tcp stream multiplexing is used, default is true, it must be same with frps
tcp_mux = true

# your proxy name will be changed to {user}.{proxy}
user = your_name

# decide if exit program when first login failed, otherwise continuous relogin to frps
# default is true
login_fail_exit = true

# communication protocol used to connect to server
# now it supports tcp and kcp, default is tcp
protocol = tcp

# specify a dns server, so frpc will use this instead of default one
# dns_server = 8.8.8.8

# proxy names you want to start divided by ','
# default is empty, means all proxies
# start = ssh,dns

# heartbeat configure, it's not recommended to modify the default value
# the default value of heartbeat_interval is 10 and heartbeat_timeout is 90
# heartbeat_interval = 30
# heartbeat_timeout = 90

# 'ssh' is the unique proxy name
# if user in [common] section is not empty, it will be changed to {user}.{proxy} such as 'your_name.ssh'
[ssh]
# tcp | udp | http | https | stcp | xtcp, default is tcp
type = tcp
local_ip = 127.0.0.1 # 公网服务器6001端口数据被影射到内网 127.0.0.1 机器
local_port = 22 # 公网服务器6001端口被影射到22端口
# true or false, if true, messages between frps and frpc will be encrypted, default is false
use_encryption = false
# if true, message will be compressed
use_compression = false
# remote port listen by frps
remote_port = 6001 # 在公网服务器的端口映射
# frps will load balancing connections for proxies in same group
group = test_group
# group should have same group key
group_key = 123456

[ssh_random]
type = tcp
local_ip = 127.0.0.1
local_port = 22
# if remote_port is 0, frps will assign a random port for you
remote_port = 0

# if you want to expose multiple ports, add 'range:' prefix to the section name
# frpc will generate multiple proxies such as 'tcp_port_6010', 'tcp_port_6011' and so on.
[range:tcp_port] # 支持纯 tcp 数据转发
type = tcp # 转发的协议类型
local_ip = 127.0.0.1 # 转发到的内网ip地址
local_port = 6010-6020,6022,6024-6028 # 转发到的内网端口
remote_port = 6010-6020,6022,6024-6028 # 外网监听的端口
use_encryption = false
use_compression = false

[dns] # 支持 dns 数据代理
type = udp
local_ip = 114.114.114.114
local_port = 53
remote_port = 6002
use_encryption = false
use_compression = false

[range:udp_port]
type = udp
local_ip = 127.0.0.1
local_port = 6010-6020
remote_port = 6010-6020
use_encryption = false
use_compression = false

# Resolve your domain names to [server_addr] so you can use http://web01.yourdomain.com to browse web01 and http://web02.yourdomain.com to browse web02
[web01] # 支持 http,https数据转发
type = http
local_ip = 127.0.0.1 # 被转发到 127.0.0.1 地址
local_port = 80 # 数据被转发到 80 端口
use_encryption = false
use_compression = true
# http username and password are safety certification for http protocol
# if not set, you can access this custom_domains without certification
http_user = admin
http_pwd = admin
# if domain for frps is frps.com, then you can access [web01] proxy by URL http://test.frps.com
subdomain = web01
custom_domains = web02.yourdomain.com # 支持域名绑定,外网ip对应 web02.yourdomain.com 域名的请求被转发过来
# locations is only available for http type
locations = /,/pic
host_header_rewrite = example.com
# params with prefix "header_" will be used to update http request headers
header_X-From-Where = frp

[web02]
type = https
local_ip = 127.0.0.1
local_port = 8000
use_encryption = false
use_compression = false
subdomain = web01
custom_domains = web02.yourdomain.com

[plugin_unix_domain_socket]
type = tcp
remote_port = 6003
# if plugin is defined, local_ip and local_port is useless
# plugin will handle connections got from frps
plugin = unix_domain_socket
# params with prefix "plugin_" that plugin needed
plugin_unix_path = /var/run/docker.sock

[plugin_http_proxy]
type = tcp
remote_port = 6004
plugin = http_proxy
plugin_http_user = abc
plugin_http_passwd = abc

[plugin_socks5]
type = tcp
remote_port = 6005
plugin = socks5
plugin_user = abc
plugin_passwd = abc

[plugin_static_file]
type = tcp
remote_port = 6006
plugin = static_file
plugin_local_path = /var/www/blog
plugin_strip_prefix = static
plugin_http_user = abc
plugin_http_passwd = abc

[secret_tcp]
# If the type is secret tcp, remote_port is useless
# Who want to connect local port should deploy another frpc with stcp proxy and role is visitor
type = stcp
# sk used for authentication for visitors
sk = abcdefg
local_ip = 127.0.0.1
local_port = 22
use_encryption = false
use_compression = false

# user of frpc should be same in both stcp server and stcp visitor
[secret_tcp_visitor]
# frpc role visitor -> frps -> frpc role server
role = visitor
type = stcp
# the server name you want to visitor
server_name = secret_tcp
sk = abcdefg
# connect this address to visitor stcp server
bind_addr = 127.0.0.1
bind_port = 9000
use_encryption = false
use_compression = false

[p2p_tcp]
type = xtcp
sk = abcdefg
local_ip = 127.0.0.1
local_port = 22
use_encryption = false
use_compression = false

[p2p_tcp_visitor]
role = visitor
type = xtcp
server_name = p2p_tcp
sk = abcdefg
bind_addr = 127.0.0.1
bind_port = 9001
use_encryption = false
use_compression = false

其他案列

我需要给外网同事传输一个很大的文件,用 qq 和 百度云 的实测效果都不好,于是我用 frp 做了一个 tcp 穿透,然后用一台公网服务器做代理,效果杠杠的,爽爆,速度从之前的 200kb/s, 提升到了 3 Mb/s

总结

外网服务器请求被转发到内网打洞服务器,然后打洞服务器反向代理到内网服务器,如果你的公有云和私有云内网服务器都不能访问外网,还需要两边都做代理,也就是公有云,私有云,两边都需要打洞,请求走公网服务器做中转

坚持原创技术分享,您的支持将鼓励我继续创作!