You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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. 验证配置

  1. 重启Azure App Service和WordPress站点
  2. 测试WordPress后台表单提交、分页功能,检查控制台资源加载错误
  3. 直接访问https://blog.example.com,确认重定向正常且无循环

内容的提问来源于stack exchange,提问作者ajbeaven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:25:43