前言
frp 是一个高性能的反向代理应用,可以轻松地进行内网穿透,对外网提供服务,支持 TCP、UDP、HTTP、HTTPS 等协议类型,并且 web 服务支持根据域名进行路由转发。
Github: https://github.com/fatedier/frp
安装frp
Releases: https://github.com/fatedier/frp/releases
可以直接下载编译好的压缩包,在 Releases 页面中找到对应平台的压缩包,解压后就可以直接用,或者自己下载源码编译。
为了表示对作者的尊敬,我决定用 GO 编译。
搭建GO环境
安装依赖
1234 | # Ubuntu$ sudo apt-get install bison ed gawk gcc libc6-dev make# CentOS$ sudo yum install gcc |
下载go支持包
各版本的下载地址 https://www.golangtc.com/static/go/,我使用的是当前最新的1.9rc2
。
1 | $ wget https://www.golangtc.com/static/go/1.9rc2/go1.9rc2.linux-amd64.tar.gz |
解压go包
1 | $ sudo tar -C /usr/local -xzf go1.9rc2.linux-amd64.tar.gz |
添加环境变量和go工作区
1 | $ vim /etc/profile |
在文件的底部添加以下两行:
12 | export PATH=$PATH:/usr/local/go/bin export GOPATH=/usr/local/gopath |
:wq
保存退出后,重新加载环境变量
1 | $ source /etc/profile |
测试
12 | $ mkdir -p /usr/local/gopath && cd /usr/local/gopath$ vim test.go |
简单的打印测试:
1234567 | package mainimport "fmt"func () { fmt.Println("Hello World!") } |
使用go编译运行:
12 | $ go run test.goHello World! |
至此,go环境搭建完毕。
下载编译frp
123 | $ go get github.com/fatedier/frp $ cd /usr/local/gopath/src/github.com/fatedier/frp/$ make |
配置
创建frps配置文件
make
编译完成后,frp
里会多出一个bin
目录,放着frpc
和frps
,对应客户端和服务端的可执行文件。服务端上只需要用到 frps
,可以删掉 frpc
,客户端则相反。除此之外,还需要一个配置文件。
12 | $ rm -rf frpc$ vim frps.ini |
详细的配置请看 https://github.com/fatedier/frp/blob/master/README_zh.md,官方的 README 介绍得非常详细。我再怎么写也没有官方的介绍更详细,这里直接贴我的配置。
1234567891011 | [common]bind_addr = 0.0.0.0bind_port = 7001vhost_http_port = 6666dashboard_port = 7501dashboard_user = {username}dashboard_pwd = {password}auth_token = {token}privilege_token = {privilege_token}privilege_mode = true |
我开启了privilege_mode
,也就是开启了特权模式,这样服务端就不再需要配置每一条诸如 tcp、http 等的隧道,只需要把这个 frps 服务启动即可。
运行服务端
123456 | $ ./frps -c frps.ini2017/09/23 17:28:00 [I] [service.go:83] frps tcp listen on 0.0.0.0:70012017/09/23 17:28:00 [I] [service.go:108] http service listen on 0.0.0.0:66662017/09/23 17:28:00 [I] [service.go:134] Dashboard listen on 0.0.0.0:75012017/09/23 17:28:00 [I] [main.go:112] Start frps success2017/09/23 17:28:00 [I] [main.go:114] PrivilegeMode is enabled, you should pay more attention to security issues |
一般会挂在后台运行这个服务,可以用 nohup:
1 | $ sudo nohup ./frps -c frps.ini >/dev/null 2>&1 & |
也许我有强迫症,我很讨厌生成的 nohup.out,所以使用 >/dev/null 2>&1
来避免 shell 命令运行中有内容输出。
把 frps 服务跑起来后,公网服务器的配置就全部搞完了,当然,还得搞点手脚,让服务器开机自动启动这个服务,否则服务器重启就断开了。这个在 NAT 客户端上也是一样的,放到后面讲。
创建frpc配置文件
接下来,需要在内网中的客户端做同样的操作,搭建go环境(如果你有兴趣的话)、下载编译frp,唯一不同的就是反过来删除 frps,保留 frpc。
12 | $ rm -rf frps$ vim frpc.ini |
由于开启了特权模式,所以,所有的隧道都可以直接在 frpc.ini 里配置。同样,直接贴上我的配置。
1234567891011121314151617 | # frpc.ini[common]server_addr = 120.76.207.187server_port = 7001auth_token = {token}privilege_token = {privilege_token}[bingo_pi_web]type = httplocal_port = 80remote_port = 6666custom_domains = pi.bingo.ren[ssh]type = tcplocal_port = 22remote_port = 3692 |
这里我配置了两条隧道,一条是 http 类型的,一条是 tcp 的。然后,开启 frpc 服务即可。
运行客户端
1 | $ sudo nohup ./frpc -c frpc.ini >/dev/null 2>&1 & |
设置frp服务开机自启
只需要在 /etc/rc.local
文件的最后,添加 frp 服务的启动命令即可。
1 | $ vim /etc/rc.local |
exit 0
是脚本退出的意思,只要将命令加在 exit 0
之前就可以开机启动了。
服务端,设置开机自启 frps 服务。
12345 | ...nohup /usr/local/gopath/src/github.com/fatedier/frp/bin/frps -c /usr/local/gopath/src/github.com/fatedier/frp/bin/frps.ini >/dev/null 2>&1 &exit 0 |
客户端,设置开机自启 frpc 服务。
12345 | ...nohup /usr/local/etc/frp_0.13.0_linux_arm/frpc -c /usr/local/etc/frp_0.13.0_linux_arm/frpc.ini >/dev/null 2>&1 &exit 0 |
设置完 reboot 重启一下,就会发现 frp 服务已经自动启动了。
123 | $ ps -ef | grep frproot 570 1 0 18:29 ? 00:00:00 /usr/local/etc/frp_0.13.0_linux_arm/frpc -c /usr/local/etc/frp_0.13.0_linux_arm/frpc.iniroot 856 806 0 18:30 pts/0 00:00:00 grep --color frp |
测试
经过以上配置,正常情况下,在任何设备上,访问 https://pi.bingo.ren,就可以访问到内网 80 端口的 HTTP 服务。
123456789 | $ curl https://pi.bingo.ren<html> <head> <meta charset="utf-8"/> </head> <body> <h1>This is index page of Bingo's Raspberry PI. 🍺 </h1> </body></html> |
也可以在任何设备上通过 3692 端口连上内网的 sshd 服务。
1234 | $ ssh -p 3692 root@pi.bingo.renLinux bingo 4.9.41-v7+ #1023 SMP Tue Aug 8 16:00:15 BST 2017 armv7lLast login: Sat Sep 23 17:23:29 2017 from 127.0.0.1root@bingo:~# |
如果穿透失败,请优先检查两台服务器上的 iptables,看是否有端口没有开放。确定不是防火墙的问题后,再一步一步排查问题。
补充
贴一下 Nginx 的配置。
12345678910111213141516171819202122232425 | # pi.bingo.ren.confserver { listen 80; listen 443 ssl http2; ssl_certificate /usr/local/nginx/conf/ssl/pi.bingo.ren.crt; ssl_certificate_key /usr/local/nginx/conf/ssl/pi.bingo.ren.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on; ssl_session_timeout 10m; ssl_session_cache builtin:1000 shared:SSL:10m; ssl_buffer_size 1400; add_header Strict-Transport-Security max-age=15768000; ssl_stapling on; ssl_stapling_verify on; server_name pi.bingo.ren; access_log /data/wwwlogs/pi.bingo.ren_nginx.log combined; index index.html index.htm index.jsp; root /data/wwwroot/pi.bingo.ren; location ~ { proxy_pass http://127.0.0.1:6666; include proxy.conf; }} |
用 Nginx 反向代理了 frp 的 http 服务,转发到 frps.ini 中配置的 vhost_http_port
6666 端口。
我遇到了一个坑,我在 README 中看到了 vhost_https_port
,以为 HTTP 请求全部走 vhost_http_port
端口,而 HTTPS 请求需要走 vhost_https_port
端口。
于是,在配置 Nginx 的时候就把 listen 80
和 listen 443
写成两个 server。 80 端口的请求转发到 http://127.0.0.1:6666,443 端口的请求转发到 https://127.0.0.1:8443。
理论上似乎可行,但运行起来后, HTTPS 穿透失败了,一直都出现 502 异常。Github 上的 关于「nginx 反代 frp Https 502」的 issues 有好几个,但都没有解决的方案。作者认为,不使用 Nginx 直接请求 frps 的 https 端口是正常的,所以问题应该是在 nginx 那边,他似乎对很多人提这个 issues 感到很反感和无奈。
后面想到 Nginx 的502有可能是 SSL 证书的问题,Nginx 会验证被反代网站的证书。试了一下反代12306同样出现502,而换成百度就可以成功访问。成功锁定问题,就是内网的那台设备没有 SSL 证书。
于是试了一下自签,仍然会出现502。看来自签也不行,估计 Nginx 还会验 CA 证书,只有权威机构颁发的才能验证通过。
正当我想用 Let’s Encrypt,分一个域名去签的 SSL 证书的时候,突然发现,我的公网服务器已经签了一个证书了,为什么我的内网服务器还要再签一个?frps 和 frpc 的连接通讯应该不需要 HTTPS 了,又不是直接暴露的。
只要公网的域名上了 SSL 就够了,不管访问公网服务器的时候是 http 还是 https 请求,统一走 frp 的 http 隧道即可。
后话
frp 的更多玩法有待研究,目前已经满足了我的需求。一般我就只需要 http 和 tcp 隧道,udp 啥的等到有使用场景的时候再试试。
记得之前在网上看到,frp 是需要使用虚拟内存的,我还没去验证和配置。目前没发现有什么异常,Mark 一下,等出问题再解决吧。
来源:https://www.cnblogs.com/lijianming180/p/12288733.html