Azure App Service反向代理配置问题:子目录转子域名异常排查
问题
我有一个WordPress站点部署在https://blog.example.com,另一个站点部署在Azure App Service(Windows)的https://www.example.com,两者均由Cloudflare提供前置代理。
已配置反向代理将https://www.example.com/blog的请求转发至https://blog.example.com,博客文章可正常显示在预期URL下,但存在以下异常:
- 在WordPress后台提交部分表单(如常规设置)时,用户会话被强制退出并跳转到登录页(URL参数包含
blog.example.com) - WordPress后台分页功能会跳转到
https://blog.example.com对应的页面 - WordPress后台部分页面存在控制台错误,提示无法从
https://blog.example.com加载资源 - 配置从
https://blog.example.com到https://www.example.com/blog的301重定向时,会陷入无限重定向循环
经排查,推测上述问题均因WordPress服务器接收到的Host头为https://blog.example.com而非https://www.example.com,WordPress部分功能会基于Host头构建URL,而非已设置的Website URL或Home URL(均为https://www.example.com/blog)。微软建议保留原始Host头以解决此类问题。
启用IIS的ARR的preserveHostHeader选项后,代理完全失效:
- 访问
https://www.example.com/blog显示https://www.example.com的首页 - 访问
https://www.example.com/blog/a-blog-post返回404错误(由https://www.example.com站点生成)
当前配置如下:
applicationHost.xdt(用于在Azure App Service中启用默认禁用的ARR)
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <system.webServer> <proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false"/> <rewrite xdt:Transform="InsertIfMissing"> <allowedServerVariables xdt:Transform="InsertIfMissing"> <add name="HTTP_X_ORIGINAL_HOST" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> <add name="HTTP_X_UNPROXIED_URL" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> <add name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> <add name="HTTP_ACCEPT_ENCODING" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> </allowedServerVariables> </rewrite> </system.webServer> </configuration>
web.config(用于将子目录请求重写至子域名)
<?xml version="1.0" encoding="utf-8"?> <configuration> <location path="." inheritInChildApplications="false"> <system.webServer> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> </handlers> <aspNetCore processPath="dotnet" arguments=".\Example.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" /> <rewrite> <rules> <clear /> <rule name="Blog Proxy" stopProcessing="false"> <match url="^blog(?:$|/)(.*)" /> <action type="Rewrite" url="https://blog.example.com/{R:1}" appendQueryString="true" logRewrittenUrl="false" /> <serverVariables> <set name="HTTP_X_UNPROXIED_URL" value="https://blog.example.com/{R:1}" /> <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" /> <set name="HTTP_X_ORIGINAL_HOST" value="{HTTP_HOST}" /> <set name="HTTP_ACCEPT_ENCODING" value="" /> </serverVariables> </rule> </rules> </rewrite> </system.webServer> </location> </configuration>
请问是否因Cloudflare导致?preserveHostHeader在Azure App Service中是否无法正常工作?如何正确配置以满足需求?
解决方案
1. Cloudflare与preserveHostHeader的问题分析
Cloudflare作为前置代理会修改部分请求头,但核心问题并非由它直接导致——当前代理配置未正确传递原始Host头到WordPress站点,同时启用preserveHostHeader后,ARR的规则匹配逻辑与后端WordPress的站点绑定规则冲突,才引发代理失效。
preserveHostHeader="true"时,ARR会将原始请求的Host头(www.example.com)传递给后端WordPress,但你的重写规则将请求转发到https://blog.example.com,此时WordPress站点绑定的是blog.example.com,会认为请求不匹配自身域名,导致路由失败,这就是启用后代理失效的原因。
2. 正确配置步骤
步骤1:调整ARR的代理配置
修改applicationHost.xdt,启用preserveHostHeader并开启reverseRewriteHostInResponseHeaders,确保后端返回的响应头Host被重写为原始Host:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <system.webServer> <proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="true" reverseRewriteHostInResponseHeaders="true"/> <rewrite xdt:Transform="InsertIfMissing"> <allowedServerVariables xdt:Transform="InsertIfMissing"> <add name="HTTP_X_ORIGINAL_HOST" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> <add name="HTTP_X_UNPROXIED_URL" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> <add name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> <add name="HTTP_ACCEPT_ENCODING" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> <add name="HTTP_X_FORWARDED_HOST" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> <add name="HTTP_X_FORWARDED_PROTO" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/> </allowedServerVariables> </rewrite> </system.webServer> </configuration>
步骤2:更新web.config的代理规则
调整重写规则,添加转发头变量,确保WordPress识别真实请求来源:
<?xml version="1.0" encoding="utf-8"?> <configuration> <location path="." inheritInChildApplications="false"> <system.webServer> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> </handlers> <aspNetCore processPath="dotnet" arguments=".\Example.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" /> <rewrite> <rules> <clear /> <rule name="Blog Proxy" stopProcessing="true"> <match url="^blog(?:$|/)(.*)" /> <action type="Rewrite" url="https://blog.example.com/{R:1}" appendQueryString="true" logRewrittenUrl="false" /> <serverVariables> <set name="HTTP_X_UNPROXIED_URL" value="https://{HTTP_HOST}/blog/{R:1}" /> <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" /> <set name="HTTP_ACCEPT_ENCODING" value="" /> <set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" /> <set name="HTTP_X_FORWARDED_PROTO" value="https" /> </serverVariables> </rule> <!-- 保留主站的其他规则 --> </rules> </rewrite> </system.webServer> </location> </configuration>
- 设置
stopProcessing="true",避免后续规则干扰代理逻辑 - 修正
HTTP_X_UNPROXIED_URL为用户真实访问的URL - 添加
HTTP_X_FORWARDED_HOST传递原始Host,HTTP_X_FORWARDED_PROTO确保WordPress识别HTTPS协议
步骤3:配置WordPress识别代理头
在WordPress的wp-config.php中添加以下代码,强制WordPress使用转发的头信息构建URL:
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST']; } if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; } define('WP_HOME', 'https://www.example.com/blog'); define('WP_SITEURL', 'https://www.example.com/blog'); define('FORCE_SSL_ADMIN', true);
步骤4:修复无限重定向循环
在blog.example.com的服务器配置(如web.config)中添加条件重定向,仅当请求非来自Azure代理时才跳转:
<rule name="Redirect to Proxy URL" stopProcessing="true"> <match url="(.*)" /> <conditions> <add input="{HTTP_HOST}" pattern="^blog\.example\.com$" /> <add input="{HTTP_X_FORWARDED_HOST}" pattern="^www\.example\.com$" negate="true" /> </conditions> <action type="Redirect" url="https://www.example.com/blog/{R:1}" redirectType="Permanent" /> </rule>
3. 验证配置
- 重启Azure App Service和WordPress站点
- 测试WordPress后台表单提交、分页功能,检查控制台资源加载错误
- 直接访问
https://blog.example.com,确认重定向正常且无循环
内容的提问来源于stack exchange,提问作者ajbeaven

