NginxProxyManager的默认域名及跳转配置
背景
国内的大环境下, 公网IP出口的80,443两个默认端口是被禁止的, 导致NginxProxyManage的很多官方默认跳转都无法生效. 本文便是致力于解决这种情况下的跳转问题;
非常用端口下的http跳转到https
现如今 let's encrypt 形势一片大好的时候, 谁还不整个免费正版的SSL证书用用呢. 因此我的私有服务器也全面搭配了https提供对外访问. 但443端口被封了, 只能在路由器上把公网的60443端口NAT到NPM的443端口提供服务.
但是在浏览器中直接输入 ysslang.com 的话, 在没有历史地址补齐的情况下. 浏览器哪怕是chrome都会默认以http去访问.
还好NPM默认每一个http proxy 都是同时监听了80和443端口的. 并且勾选了Force SSL后
NPM会提供一个http向https的301跳转,
if ($scheme = "http") {
return 301 https://$host$request_uri;
}
但这个跳转存在一个问题, 这个301的跳转只适用于标准端口(80/443), 除此以外的其他端口, 是无法识别并正确跳转的. 然后便会得到一个400的响应页面
通过497跳转解决非常用端口下的http跳转https
经过好一番google, 终于找到了一个 类似的问题 有一个大佬提示, 通过响应497错误页可以将http跳转到https下, 对非常用端口也生效. 497代码是一个nginx的专用响应码, 作用就是跳转到https.
于是从docker中将 /etc/nginx/conf.d/include/force-ssl.conf
映射出来, 修改其内容为
#if ($scheme = "http") {
# return 301 https://$host$request_uri;
#}
error_page 497 https://$http_host$request_uri;
即可实现非常用端口下的http跳转https
PS: 针对这个问题给NPM提了个issue, 然而开发者认为这个场景过小不予支持, 可惜.
非常用端口下的默认服务器拦截
解决了https跳转问题后, 开开心心的用了一阵儿, 又遇到一个头疼的问题
NPM提供了非常灵活的禁用启用机制, 可以将一些偶尔开放的测试地址, 或者临时需要下线的地址给直接禁用掉, 非常方便. 我现在已配置的代理达到96个, 其中真正常用的只有二十几个, 剩下的其中五十个, 都被我禁用掉了, 一方面是关闭未上线服务, 另一方面有一些服务可能会被攻击啊什么的, 禁用掉保安全.
这些禁用掉的域名, 以及一些根本没有配置的域名, 在访问的时候, 还是会出现上面的 400 Bad Request 的报错页面, 看着很难受, 因为http向https的跳转, 只有走进proxy的server块后, 才会生效, 而禁用掉的proxy, 是没法走进的.
如果以https访问的话, 效果就更难受了, 会默认走到NPM的两个默认服务下面, 一个是http的在80上, 一个是https的在443上, 并且这个https的用的是一个localhost的dummycert, 一定会在浏览器端爆出一个证书信息不匹配. 体验很差
但其实, NPM是提供了default_server的拦截的, 可以拦截到未识别的proxy的访问, 然后可以配置重定向到默认地址下面.
但, 这个拦截, 也只有http下或标准端口下才会有较好的体验, 如果走https或者https的端口访问, 一定会导致https的证书不匹配或者http无法跳转https的问题. 然而国内的大环境下, 访问私有服务时一定是带有端口的, 而且肯定不会写http的端口. 所以每次看到证书信息不匹配的问题就想把它解决掉.
利用通配符server_name实现拦截跳转
查了一番资料后, 判断可以有如下解决办法:
- 修改NPM的default配置, 把443的默认服务的证书变成自己签名的有效证书;
- 修改某一个proxy的配置, 在listen后面添加 default_server , nginx便会将它作为这个ip端口下的默认地址进行拦截;
- 配置 redirect proxy 实现跳转
- 利用带通配符的server_name实现拦截;
方案1,2的问题都在于, 这两个配置项都是跟NPM的后端代码逻辑高度耦合的, 直接修改后台文件的话, 前端的UI操作或者是定时更新可能会刷新后台文件, 导致配置失效, 甚至NPM都进不去.
方案3是可行, 但需要每一个需要拦截的域名都配置一个规则, 也不太行;
方案4有一个难点在于, 不确定 通配符server_name 和准确的 server_name 都存在的情况下, 会先走进哪个, 是更准确的那个呢, 还是先匹配上的那个. 简单测试了下, 应该是走进了更准确地那个.
于是便可以直接在需要跳转到的域名处多加一个 *.ysslang.com
的泛域名, 从而拦截到所有的未匹配地址.
其实, 可以把方案3和方案4结合起来, 把这个拦截跳转作为一条单独的跳转规则配置. 这样这个配置也可以更方便地管理, 禁用启用啥的.
配置一条这样的规则即可实现拦截跳转
推荐使用307临时跳转, 因为如果用301或者308的话, 可能会被浏览器端缓存住, 之后这个地址如果被启用了的话, 浏览器会不请求nginx直接自动跳转走, 再清缓存怪麻烦的.
Member discussion