环境信息:
- Windows Server 2012 R2
- 微软 IIS 8 新功能
- IIS URL 重写模块 2 (2015 年 4 月 13 日) 7.2.2
- Umbraco 7.11.1
配置说明
我们有一个 Umbraco 网站,它绑定到两个主域名,我们称之为sitea.com
和siteb.com
- 这两个网站的源代码和部署相同,但内容完全不同。在 IIS 中,这两个网站还绑定到www.sitea.com
和www.siteb.com
此外,我们已使用 LetsEncrypt 保护所有 4 个域名的网站安全。
该网站应该使用 HTTPS,并且我们还将 useSSL 的 umbraco 键设置为 true。
<add key="umbracoUseSSL" value="true" />
重写配置
我们已经设置了许多重定向,整个重写配置已匿名粘贴如下:
<rewrite>
<rules>
<rule name="Allow LetsEncrypt" patternSyntax="Wildcard" stopProcessing="true">
<match url=".well-known/*" />
<action type="None" />
</rule>
<rule name="Remove WWW" patternSyntax="Wildcard" stopProcessing="false">
<match url="*" />
<conditions>
<add input="{CACHE_URL}" pattern="*://www.*" />
</conditions>
<action type="Redirect" url="{C:1}://{C:2}" redirectType="Permanent" />
</rule>
<rule name="HTTPS" patternSyntax="Wildcard" stopProcessing="false">
<match url="*" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
总结一下,有 3 条规则
- 绕过规则,这样当 LetsEncrypt 验证 ~/.well-known 时,它不会被重定向捕获
- 如果您访问 www.sitea.com 或 www.siteb.com,您将被重定向到 {protocol}://sitea.com,具体取决于您通过哪种协议进入网站
- 进一步的重定向将检测 HTTPS 是否开启,如果没有开启,则将您重定向到 https://{domain}/{path}
问题
偶尔,正如我们的监控和手动验证所指出的那样,如果你访问http://sitea.com
,你会被重定向到https://sitea.com:80
请注意,重定向 URL 上添加了端口 80。这会导致网站无法加载,因为我们指定了 https,但点击了 http 绑定。
如果我们重置网站的应用程序池,问题会立即解决。此问题可能会持续几个小时,然后可以自行解决,但这可能是由于应用程序池在绝对时间重置或根据应用程序的请求重置所致(我们尚未调查此问题)
我没有发现重定向配置中存在任何可能导致此问题的错误,而且这个问题只会定期发生。我们在 IIS 中的同一台服务器上有其他网站,它们的重定向和绑定结构非常相似,但它们没有表现出相同的症状。
如果相关的话,在 Umbraco 中,有两个内容树,每个都分别绑定到 sitea.com 和 siteb.com。我只会在问题出在应用程序而不是 URL 重写配置中时才提到这一点。
有人见过这个错误吗?有简单的解决方案吗?
调整重写规则以包含端口和 FRT
根据我的问题评论中的建议,我使用以下方式启用了 FRThttps://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-failed-request-tracing-to-trace-rewrite-rules
我首先必须将其安装为 IIS 模块,然后“修复”URL 重写器模块以使跟踪选项可用。我使用响应 300-301 对此进行了配置。
我等待问题再次出现,然后当它再次出现时,我检查了日志。
我看到在发生故障后REDIRECT_FROM_CACHE_ACTION
,URL 重写数据中有一个CachedRedirectedUrl
值为https://sitea.com:80/
on request 的条目。这解释了为什么问题开始出现,然后直到应用程序池重置、重定向输出被缓存并且重置清除缓存后才会自动解决。
检查早期的 FRT 日志(以查找请求的缓存位置)让我发现以下情况:
在这里我们可以看到 HTTPS 规则评估已开始、匹配,但替换标记后生成的重定向 URL<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" />
是https://sitea.com:80
(条目 #28,RedirectURL)
我修改了重写规则,使 HTTPS 规则如下
<rule name="HTTPS" patternSyntax="Wildcard" stopProcessing="false">
<match url="*" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}:443{REQUEST_URI}" redirectType="Permanent" />
</rule>
这似乎没有必要,因为当未指定端口时,应该从协议中推断端口,但也许是 URL 重写中的一个错误?几天后,最初的问题又出现了,这次发出了重定向https://sitea.com:80:443/(这是具有两个端口的无效重定向)。**
编辑 1:我提取了 u7.11.1 的源代码并检查了 umbracoUseSSL 的使用情况,发现它似乎只在后台、一些通知和 api 路由中使用。前端页面渲染不会检查此变量,也不会尝试 https 重定向。因此,这表明问题出在应用程序的上游。
编辑 2:将我建议的答案与原始问题合并,因为它没有解决问题(它使情况变得更糟)
答案1
服务器变量{HTTP_HOST}
包含端口号。您可以尝试{SERVER_NAME}
这样做,或者编写一个正则表达式条件来仅捕获{HTTP_HOST}
变量的主机名。以下是后者的示例。确保trackAllCaptures="true"
<rewrite>
<rules>
<rule name="Allow LetsEncrypt" patternSyntax="Wildcard" stopProcessing="true">
<match url=".well-known/*" />
<action type="None" />
</rule>
<rule name="Remove WWW" patternSyntax="Wildcard" stopProcessing="false">
<match url="*" />
<conditions>
<add input="{CACHE_URL}" pattern="*://www.*" />
</conditions>
<action type="Redirect" url="{C:1}://{C:2}" redirectType="Permanent" />
</rule>
<rule name="HTTPS" patternSyntax="Wildcard" stopProcessing="false">
<match url="*" />
<conditions trackAllCaptures="true">
<add input="{HTTPS}" pattern="off" />
<add input="{HTTP_HOST}" pattern="(.*):?\d*" />
</conditions>
<action type="Redirect" url="https://{C:1}{REQUEST_URI}" redirectType="Permanent" appendQueryString="false" />
</rule>
</rules>
</rewrite>
还添加appendQueryString="false"
因为{REQUEST_URI}
已经包含查询字符串。