@code33
2019-07-01T09:50:24.000000Z
字数 11815
阅读 1419
frp
ngrok
技术文档
modify by jyo on 2018-09-15
modify by jyo on 2018-07
modify by jyo on 2018-06-08
create by Bunm Jyo on 2017-05-13
contact code0515@gmail.com
应用场景:
解决内网无固定IP,需要向外网开放服务端口请求的功能需求
用于外网向内网请求,而内网无需在路由器配置开放及映射端口
目前技术已有两种实现 ngrok 和 frp
原理:
外网需要一服务器长连接FRPSERVICE服务端,与内网保持长链接维持心跳,并与之通信,请求数据通过长连接通道实现,之间的通信以长连接的socks方式实现
注意:
但若是该穿透通道服务需要与指定域名进行绑定,则需对其进行特殊的headers HOST处理,以便让FRPSERVICE可识别到具体哪项通道服务
# 新建一个伪造header Host 的nginx端口服务
server {
listen 10335;
server_name _;
charset utf-8;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 伪造header Host 的nginx端口服务
proxy_set_header Host bessnodeprepro.frp.1000hou.com:51901;
#proxy_set_header X-NginX-Proxy true;
proxy_pass http://bessnodeprepro.frp.1000hou.com:51901/;
#health_check;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' GET,POST,PUT,OPTIONS,DELETE,HEAD;
proxy_redirect off;
}
}
# 做成一个流服务映射
upstream bessnodepreprorls-frp {
server 127.0.0.1:10335;
}
server {
listen 443;
server_name hdzbessmana.1000hou.com;
ssl on;
ssl_certificate /etc/nginx/CA/hdzbessmana/hdzbessmana2018.pem;
ssl_certificate_key /etc/nginx/CA/hdzbessmana/hdzbessmana2018.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/hdzbessmana.ssl.access.log;
error_log /var/log/nginx/hdzbessmana.ssl.error.log;
location /.well-known/pki-validation/fileauth.txt {
proxy_pass http://hdzbessmana-ssl/;
}
location ~ ^/v1.1.2/bsmana/?((?<=/).*)?$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $proxy_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header versionc '1.1.2';
add_header versionc '1.1.2';
# txc
#proxy_pass http://bessnodepreprotxc-frp/$1$is_args$args;
#release 这里就是代理到穿透通道nginx流服务
proxy_pass http://bessnodepreprorls-frp/$1$is_args$args;
#add_header Content-Type 'application/json; charset=utf-8';
proxy_redirect off;
}
}
一款代理服务应用,通过它可以走宿主机的流量
输出为TCP协议
windows-32 http://xyzsetup.dlhis.com/shadowsocks-libqss-v1.9.0-win32.7z
windows-64 http://xyzsetup.dlhis.com/shadowsocks-libqss-v1.9.0-win64.7z
配置参数
保存为config.json
{
"server":"0.0.0.0",
"server_port":14201,
"password":"523186",
"timeout":300,
"method":"rc4-md5",
"fast_open":false,
"workers": 2
}
运行命令附带参数
shadowsocks-libqss.exe -c config.json -S
以下版本基于frp 0.9.3
支持 tcp, udp, http, https 等协议类型,并且 web 服务支持根据域名进行路由转发。
源码 http://xyzsetup.dlhis.com/frp-0.9.3-source.tar.gz
arm http://xyzsetup.dlhis.com/frp_0.9.3_linux_arm.tar.gz
windows-64 http://xyzsetup.dlhis.com/frp_0.9.3_windows_amd64.zip
windows-32 http://xyzsetup.dlhis.com/frp_0.9.3_windows_386.zip
linux-64 http://xyzsetup.dlhis.com/frp_0.9.3_linux_amd64.tar.gz
根据自己的操作系统下载对应的包
还有更多版本 可以查看这里 Release
解压后 进入文件夹,可以看到这几个文件 (以下在Linux 64bit上操作举例)
其中无后缀的为可执行文件,ini为配置文件
服务端开启服务执行
./frps -c frps.ini
客户端开启服务执行
./frpc -c frpc.ini
# 服务器组件连接配置
# [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
# 服务端供客户端连接的握手端口
bind_port = 7000
# if you want to support virtual host, you must set the http port for listening (optional)
# 若是要对http服务支持,则必须配置该项目
# vhost_http_port意为服务端对外开放的http协议的端口
vhost_http_port = 80
# vhost_https_port意为服务端对外开放的https协议的端口
vhost_https_port = 443
# 控制面板管理端口
# if you want to configure or reload frps by dashboard, dashboard_port must be set
dashboard_port = 7500
# 控制面板用户名及口令
# dashboard user and pwd 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
# debug, info, warn, error
# 日志级别
log_level = info
# 保留日志天数
log_max_days = 3
# if you enable privilege mode, frpc can create a proxy without pre-configure in frps when privilege_token is correct
# 特权服务模式,无需对服务端配置文件变更,即可接收来自于客户端的配置增加及变更,令服务端接收其配置方案并生效(如新增一个http通道即可直接在客户端新增一个[web-someone]配置即可)
privilege_mode = true
privilege_token = 12345678
# heartbeat configure, it's not recommended to modify the default value
# the default value of heartbeat_timeout is 30
# 心跳时间,默认30s
# heartbeat_timeout = 30
# 特权服务允许的端口范围
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
privilege_allow_ports = 2000-3000,3001,3003,4000-60000
# pool_count in each proxy will change to max_pool_count if they exceed the maximum value
# 连接池通道数量
max_pool_count = 100
# 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
# 服务器绑定的域名,需要先在域名解析服务上配置
# 这里建议使用泛域名符号 *
# example: *.frps.com
subdomain_host = frps.com
# 以下是各个子服务代理通道连接的服务端静态配置方案,[name] 改配置内可自定义其名称
# ssh is the proxy name, client will use this name and auth_token to connect to server
[ssh]
type = tcp
auth_token = 123
bind_addr = 0.0.0.0
listen_port = 6000
[dns]
type = udp
auth_token = 123
bind_addr = 0.0.0.0
listen_port = 5353
[web01]
# if type equals http, vhost_http_port must be set
type = http
auth_token = 123
# if proxy type equals http, custom_domains must be set separated by commas
custom_domains = web01.yourdomain.com,web01.yourdomain2.com
[web02]
# if type equals https, vhost_https_port must be set
type = https
auth_token = 123
custom_domains = web02.yourdomain.com
# [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"
# 服务器地址 可以是IP 也可以是domain
server_addr = 0.0.0.0
# frp服务,服务连接端口
server_port = 7000
# if you want to connect frps by http proxy, you can set http_proxy here or in global environment variables
# 通过代理的形式连接~好骚
# http_proxy = http://user:pwd@192.168.1.128:8080
# console or real logFile path like ./frpc.log
# 客户端工作日志
log_file = ./frpc.log
# debug, info, warn, error
log_level = info
log_max_days = 3
# for authentication
# 身份token
auth_token = 123
# 特权token
# for privilege mode
privilege_token = 12345678
# heartbeat configure, it's not recommended to modify the default value
# the default value of heartbeat_interval is 10 and heartbeat_timeout is 30
# 心跳,根据自己的需求也可以将心跳加快,当然服务端的负荷也会随之增加
# heartbeat_interval = 10
# heartbeat_timeout = 30
# ssh is the proxy name same as server's configuration
# 注意这里的项目名称[name],如果服务端是静态配置,客户端则需与之相符,否则就需要privilege_token,意为动态操作服务端配置
[ssh]
# tcp | http, default is tcp
type = tcp
local_ip = 127.0.0.1
local_port = 22
# true or false, if true, messages between frps and frpc will be encrypted, default is false
# 加密项,如果开启了该功能,则在服务端也要做对应的配置
use_encryption = false
# default is false
# 压缩
use_gzip = false
remote_port = 53001
[dns]
type = udp
local_ip = 114.114.114.114
local_port = 53
# 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, the domains are set in frps.ini
[web01]
type = http
# 客户端於local service需要穿透的内网IP(局域网IP)
local_ip = 127.0.0.1
# 需要穿透的local service端口
local_port = 80
# 压缩
use_gzip = true
# connections will be established in advance, default value is zero
# 连接池数量
pool_count = 20
# http username and password are safety certification for http protocol
# if not set, you can access this custom_domains without certification
# http连接的用户名口令,个人认为并没有什么卵用
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 = test
[web02]
type = http
local_ip = 127.0.0.1
local_port = 8000
[privilege_ssh]
# if privilege_mode is enabled, this proxy will be created automatically
privilege_mode = true
type = tcp
local_ip = 127.0.0.1
local_port = 22
use_encryption = true
use_gzip = false
# 注意该端口必须是外网服务已经开启了允许的范围值之端口
remote_port = 6001
[privilege_web]
# 开启特权模式
privilege_mode = true
type = http
local_ip = 127.0.0.1
local_port = 80
use_gzip = true
# 自定义域名
custom_domains = web03.yourdomain.com
# locations is only useful for http type
# 连接仅限http service路径
locations = /,/pic
# 重写header 域名host
host_header_rewrite = example.com
# 从域名
subdomain = dev
穿透服务进程化启动 run on daemon
import os, sys, time
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
def __init__(self):
pass
def fail(self,msg):
print(self.FAIL+str(msg)+self.ENDC)
def warn(self,params):
print(self.WARNING+str(params)+self.ENDC)
def info(self,msg):
print(self.OKGREEN+str(msg) + self.ENDC)
the_bcolors = bcolors()
service_name = 'webdav_frpc'
configfile = '/'+service_name+'.ini'
class serviceStartDemo:
def __init__(self):
self.project_path = os.getcwd()
self.service_name=service_name
self.user = self.project_path.replace('/home/','').split('/')[0]
self.pid_file = self.project_path+'/'+ self.service_name + '.pid'
# self.runCommond = self.project_path+'/frpc -- -c '+ self.project_path+'/panetrate-mana-frpc.ini'
self.runCommond = self.project_path+'/frpc -- -c '+ self.project_path+configfile
def checkPidFile(self):
return os.path.isfile(self.pid_file)
def checkPortstatus(self):
return self.getPid(self.service_port)
def getPid(self,servciePort):
#result = os.popen("lsof -i:"+str(servciePort)).readlines()
#if (len(result) > 0):
#resAry = result[1].split()
#pidNum = resAry[1]
#return pidNum
#else:
#return None
with open(self.pid_file, 'r') as f:
servicePid = f.readline()
return servicePid
def serverStart(self):
if self.checkPidFile():
the_bcolors.fail("pidfile is exist at "+str(self.pid_file)+" ,start failed!")
return 0
the_bcolors.info ("prepair to start "+self.service_name)
os.chdir(self.project_path)
fcmdStr="start-stop-daemon --start --quiet -b -v -m --pidfile=" + str(self.pid_file) + " --user " + str(self.user) + " -d "+self.project_path+" --exec " + str(self.runCommond) + " 2>/dev/null"
os.system(fcmdStr)
print(self.runCommond)
checkCount = 0
while checkCount < 10:
if self.checkPidFile():
the_bcolors.info("pidfile has been created!")
break
else:
the_bcolors.warn ("pidfile still has not been created!")
checkCount=checkCount+1
time.sleep(6)
if checkCount==10:
the_bcolors.fail (self.service_name+" start failed")
def serverStop(self):
if self.checkPidFile():
with open(self.pid_file, 'r') as f:
servicePid = f.readline()
if (servicePid is None) or (servicePid ==''):
the_bcolors.info (self.service_name + " is already stoped!")
else:
os.system("kill -9 "+str(servicePid))
the_bcolors.info (self.service_name + " is running with pid %s,prepro to kill it!"%(str(servicePid)))
the_bcolors.info ("pidfile is exist at " + self.pid_file + " ,prepair to delete it!")
os.system("rm -f " + self.pid_file)
else:
the_bcolors.warn ("pidfile is not exist!")
return True
def serverRestart(self):
has_stop = self.serverStop()
if(has_stop):
self.serverStart()
else:
the_bcolors.fail("restart failed! plz try again")
def serverStatus(self):
runingStatus = 'false'
if self.checkPidFile():
pidfileStatus=self.pid_file
else:
pidfileStatus="not exists!"
the_bcolors.info (""+self.service_name+" status:"+pidfileStatus)
#the_bcolors.info (""+self.service_name+" status:")
#the_bcolors.info ("running status: "+runingStatus)
#the_bcolors.info ("running pid: "+ str(pid))
#the_bcolors.info ("running pid file: "+pidfileStatus)
pass;
if __name__ == '__main__':
try:
operate = sys.argv[1]
service = serviceStartDemo()
if operate == "start":
service.serverStart()
elif operate == "stop":
service.serverStop()
elif operate == "restart":
service.serverRestart()
elif operate == "status":
service.serverStatus()
else:
the_bcolors.fail ("param args only support start,stop,restart,status")
except:
the_bcolors.fail ("operate param must be required")
Ubuntu 16.04 以上的 systemd 脚本 使用 systemctl 进行服务维护操作
注意下列版本号为 0.21 版本,与上述不同
#系统服务文件路径
sudo vim /etc/systemd/system/frpc.service
[Unit]
Description=A frpc server
#After=network.target
Description=frpc daemon
After=syslog.target network.target
Wants=network.target
[Service]
Type=simple
#注意这里的用户名,如果不存在,则先行创建
User=nobody
PIDFile=/var/run/frpc.pid
#ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/home/jyo/tools/frp_0.21.0_linux_amd64/frpc -c /home/jyo/tools/frp_0.21.0_linux_amd64/tcp-util.ini
ExecStop=/usr/bin/killall frpc
TimeoutStopSec=5
Restart=always
RestartSec=20
KillMode=mixed
[Install]
WantedBy=multi-user.target
# 启动项目
systemctl start frpc
# 关闭项目
systemctl stop frpc
#将项目加入到系统字段启动
systemctl enable frpc
技术文档