Frp 是一款开源的反向代理工具,能够帮助我们反向代理出在内网的服务。
Github 地址:点此前往
当然最近 Github 因为某些原因被 GFW Gank 了,需要一些特殊手段上去。
服务器配置
将下载好的 frp 解压,frps文件放在 /usr/bin
下,systemd下的 frps .service文件放在 /etc/systemd
下,配置文件 frps.ini 放在 /etc/frp
下,/etc/frp
目录需要手工建立。
frps.ini 配置文件参考,具体配置参见官方说明
[common]
bind_port = 7000
bind_udp_port = 7001
vhost_http_port = 7080
vhost_https_port = 7443
subdomain_host = xxx.xxx.xxx
dashboard_addr = 127.0.0.1
dashboard_port = 7500
dashboard_user = xxxxxx
dashboard_pwd = xxxxxx
如果不需要使用 Nginx 作为访问前端,vhost_http_port 绑定 80端口,vhost_https_port 绑定443端口就好。
客户端配置
客户端配置和服务器差不多,但是对应的就是 frpc,frpc.ini,frpc.service 这三个文件放在相应的位置
frpc.ini 配置文件参考,具体配置参见官方说明
[common]
server_addr = xxx.xxx.xxx.xxx
server_port = 7000
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 2020
[wordpress]
type = https
local_port = 443
subdomain = www
[nextcloud]
type = https
local_port = 443
subdomain = nextcloud
该配置仅供参考。
SSL证书
关于SSL证书的配置就不多说了,相关教程网上一大把
Https 使用 Nginx 反代
这里是踩坑最多的地方,查询了谷歌后发现相关信息极少,如果没有必须使用 Nginx 的需求,可以直接使用 frp 绑定80和443端口即可。
如果必须使用 Nginx 作为前端(比如反向代理服务器上还有其他网站),这时你会发现常规 https 访问就会直接返回502了。
样例Nginx配置
server {
server_name *.testtest.com;
listen 443 ssl http2;
ssl_certificate /etc/ssl/testtest.com/fullchain.pem;
ssl_certificate_key /etc/ssl/testtest.com/privkey.pem;
location / {
proxy_pass https://127.0.0.1:7443;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
这么看很合理的一份配置,就是在访问的时候出现502,并且在客户端上的http服务中看不到访问日志。
在反向代理服务器上的 Nginx 发现错误日志:
2020/02/26 02:57:13 [error] 16513#16513: *133785 peer closed connection in SSL handshake while SSL handshaking to upstream, client: xxx.xxx.xxx.xxx, server: *.xxx.xxx.xxx, request: "GET / HTTP/2.0", upstream: "https://127.0.0.1:7443/", host: "xxx.xxx.xxx"
然而我们通过这个报错并没有办法查到什么有用的信息。最后在#671中发现了解决方案。
推测是 frp 在反向代理https的时候,因为 Nginx 已经处理过了 https 的握手信息,所以, Frp 无法获取到 SNI 信息,导致发送请求的时候就是不完整的https请求。因为如果改成http或者tcp反向代理都可以成功,顾认为是 Frp 机制的问题,他访问的域名变成127.0.0.1,没有 SNI 信息。所以在上面那份配置的情况下,可以通过域名+端口号成功访问。
所以修改后的配置如下:
server {
ssl_protocols TLSv1.2 TLSv1.3;
listen 443 ssl http2;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
server_name *.xxx.xxx.xxx;
location / {
resolver 127.0.0.53;
proxy_pass https://$host:7443;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_ssl_server_name on;
}
ssl_certificate /etc/letsencrypt/live/xxx.xxx.xxx/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/xxx.xxx.xxx/privkey.pem;
}
server {
listen 80;
server_name *.xxx.xxx.xxx;
return 301 https://$server_name$request_uri;
}
相应的,需要设置DNS解析相关域名到本地。
可以使用 dnsmasq 或者直接修改 /etc/hosts
127.0.0.1 localhost
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
# map for frp https with ngxin frontend
127.0.0.1 xxx.xxx.xxx
总结
虽然说这样配置很烦,但是这样可以使用泛域名的方式访问,就是需要使用 dnsmasq。修改 /etc/hosts
不能泛域名。
Frp 很强大,但是没有什么好办法和 Nginx 配合使用,不得不说这应该是设计之初的问题了。在 Chrome 很快就要禁止 http 链接的情况下,https肯定是要上的,就是这样配置太不友好了。
本文地址: Frp使用Nginx前端反向代理Https