2020.06更新:经Github f1ynng8提出的issues发现本地nginx跳转443配置文件缺少了一个)
,现已补上,是我手滑给大家造成不便了,抱歉抱歉~
纯享版新鲜出炉,欢迎大家参考~
关于后端混杂htpps和http还不想全部在frps端处理http到https还想隐藏端口的问题
这种奇怪要求当然我有考虑到 解决方案有两种:
1.为个别后端为http的站点建立单独一组配置文件,在frps所在的服务器的nginx上反代http到https
2.自动检测后端是否为只有http,这里可以直接调用frps提供的api,用lua批量处理
我个人目前使用后的是第二种,但无奈写blog的时间太少,相关方案的示例我会在下一次摸鱼时总结放出
前言
不知不觉也已经用frp两年了,但刚才在搜索引擎上仍不能找到完美的Nginx反代frp服务端实现https和泛域名/泛解析的方案,某站上甚至每一百余日出现一次解决了没的提问,大部分的实现都是反代了frp的http,在反代https时大多报了502错误,下面给出正确姿势。再次注意,502错误是后端https配置不正确造成的,完全可以避免,可以不暴露端口!
如果你不能看懂本文内容,请直接点击懒人配置文档,那里有全面的各个环节的配置文件示例
为什么多想了一步想给用户获得更好的体验的容差兼容整到最后大家以为是需要暴露端口
在开始之前先给出基础知识,觉得OK的同志可以跳过
基础知识1:nginx的https强制跳转
可在同一个server中同时listen http和ssl http2后通过nginx的if语句进行跳转
代码及解析如下
server
{
listen 80; #监听http端口,端口号80
listen 443 ssl http2; #监听https端口,端口号443
server_name *.domain.com; #填写你需要的泛域名
charset utf-8;
if ($server_port !~ 443){ #若端口号不为443
rewrite ^(/.*)$ https: #$host$1 permanent; #302跳转到https地址
error_page 497 https://$host$request_uri; #497用于http到https的强制跳转
ssl_certificate ./fullchain; #ssl证书的fullchain(含公钥的完整证书链)
ssl_certificate_key ./privkey; #ssl证书的privkey(私钥)
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
}
基础知识2:nginx的$host$uri$args$request_uri
$host代表请求的主机 $request_uri代表请求的uri $uri代表包含args的uri
如:
https://www.baidu.com/s?&wd=ray8.cc&ie=utf-8
$host为www.baidu.com
$request_uri为/s?&wd=ray8.cc&ie=utf-8
$uri为/
$args为s?&wd=ray8.cc&ie=utf-8
基础知识3:nginx的http_realip_module模块
准备专门开一篇文章,待填坑。
反向代理流程图
流程图中Server1部分为正常反向代理的https
Server2部分为后端使用http时的反向代理http到https
配置文件及解析
流程图中server1部分为
server
{
listen 80;
listen 443 ssl http2;
server_name *.domain.com; #填写你需要的泛域名
charset utf-8;
if ($server_port !~ 443){
rewrite ^(/.*)$ https:
error_page 497 https://$host$request_uri;
ssl_certificate ./fullchain; #需要修改成证书公钥对应位置
ssl_certificate_key ./privkey; #需要修改成证书私钥对应位置
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
}
location / {
resolver 8.8.8.8;
proxy_ssl_server_name on;
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_pass https://$host:5678; #端口号(5678)替换为你frps的https监听端口
error_page 502 http://$host:6666/$request_uri; #端口号(6666)替换为你下一个server的监听端口
#注意:这里的error_page 502是为了容差兼容后端的https配置不正确问题,不至于向用户直接抛出异常
#如果你被默认跳转,则证明你的后端https配置有误,并不是本方案必须暴露端口!!!!!!!!!x10086
#懒人模板中有三个环节全部需要遇到的配置文件,如果遇到默认跳转,可留言或比对文件中的配置信息,看差在哪里
}
#access_log /.log; #若去除行首的注释符,则需要修改成你想要存放日志的位置
}
流程图中server2部分为:
server
{
listen 6666;
listen 7777 ssl http2;
server_name *.domain.com; #填写你需要的泛域名
charset utf-8;
if ($server_port !~ 7777){
rewrite ^(/.*)$ https:
error_page 497 https://$host$request_uri;
ssl_certificate ./fullchain; #需要修改成证书公钥对应位置
ssl_certificate_key ./privkey; #需要修改成证书私钥对应位置
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
}
location / {
resolver 8.8.8.8;
proxy_ssl_server_name on;
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_pass https://$host:1234; #端口号(1234)替换为你frps的http监听端口
}
#access_log /.log; #若去除行首的注释符,则需要修改成你想要存放日志的位置
}
大神,我一直没能成功,家里有NAS装了nextcloud,也有一台阿里云的服务器,有没有方案能做到在局域网内用http,在外网用阿里云通过frp走https?是用frp的https2http插件吗?但是一直不成功。另外局域网内的https服务,比如webmin cockpit这类,在阿里云用ngingx反代也是一直报502,头疼
你好, 我最近正在搞类似 case3 的配置, 按照你的配置在 edge 里可以连上,但显示证书有问题,chrome里直接不给访问,但我的证书 用 acme.sh 申请的 泛域名证书,不知道怎么回事,可以的话请教下.
可以的可以的,欢迎互相交流,可以通过知乎找到我!!听你的描述认为应该是@域名(如本站的ray8.cc)与二级域名(blog.ray8.cc)之间的证书应用错误问题,是不是你签的是*.yourdomain.extension而用到了yourdomain.extension这个顶级域名上呢。
博主能帮我配置一下吗
可以的可以的,通过知乎私信我即可~
博主能给我配置一下吗 能打开https 自动跳到http 不显示小锁
流程图用什么工具画的?可否安利?
有点没看懂 error_page 以后 转到https 7777 端口的时候 这个时候的https 7777端口是暴露的?
https://github.com/fatedier/frp/issues/888
请参考此文,不需要暴露端口,起码我就是这样做的。
至于原理,正在研究中。OωO
https://$host:1234; --> 解析为https://127.0.0.1:8643;
原理如下:
$host首先匹配server_name,匹配失败再DNS解析。
原文:In this case, if an address is specified as a domain name, the name is searched among the described server groups, and, if not found, is determined using a resolver.
谷歌译文:在这种情况下,如果将地址指定为域名,则在所描述的服务器组中搜索名称,如果未找到,则使用解析器确定。
链接:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
勘误,扣鸡腿。
https://$host:1234;解析后是https://127.0.0.1:1234;
参考参考
能否做个视频?我用那个proxy pass浏览器显示域名+frps监听端口号,怎么也去不掉。
如果显示端口号的话多半是用了rewrite,贴一个完整的配置文件吧,或者知乎私信我
麻烦删掉,贴过来,自动变成这样了。。。不好意思
收悉你的评论,明早给你解答!
谢谢老大
还有就是如果你后端用的是apache的话需要把
proxy_set_header Host $host;改成
proxy_set_header Host $host:$server_port;
这样后端才能反应过来不给你跳转
老大,后端也是nginx也是宝塔。我试了下,还是不行,还是显示www.xxx.coom:7080。
这样,你知乎私信联系一下我,我帮你系统看看
你要做的是http反代对吧?假定你frps的http监听端口是8070
proxy_pass 要写成proxy_pass http://$host:5678;
这里不能写死
老大,试过了不行,提示502,老大有时间的话,给你宝塔账号,进去看看。我想先做http反代,然后申请免费ssl。
wow!真的可以用啊!超感谢!!!