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

Apache反向代理:本地同端口多虚拟主机代理异常排查与解决

问题

在本地Docker容器部署了HTTPD Apache反向代理,对接OpenID Connect SSO认证,需要配置3个不同的SSO,因此在httpd.conf中配置了3个VirtualHost,期望第一个VirtualHost根据子路径转发到另外两个。但实际访问/api/sso2/login或/api/sso3/login时,均转发到第二个VirtualHost(调整VirtualHost顺序则都转到第三个)。以下是配置及/etc/hosts内容,求问题原因及正确配置方法。

现有配置

<VirtualHost *:80>
    ServerName ${MON_IP_HOST}
    OIDCProviderMetadataURL http://SSO1…….
    <Location />
        #public
    </Location>
    <Location /api/SSO1/login>
        AuthType openid-connect
        Require valid-user
    </Location>
    ProxyPreserveHost On
    ProxyPass /api/sso2/login  http://internal_sso2/api/sso2/login
    ProxyPassReverse /api/sso2/login  http://internal_sso2/api/sso2/login

    ProxyPass /api/sso3/login  http://sso3_local/api/sso3/login
    ProxyPassReverse /api/sso3/login  http://sso3_local/api/sso3/login

    #--- main proxy pass ---
    ProxyPass / ${banckendapiurl}
    ProxyPassReverse / ${banckendapiurl}  
</VirtualHost>

<VirtualHost internal_sso2:80>
    ServerName internal_sso2
    OIDCProviderMetadataURL http://SSO2 ……
    <Location />
        AuthType openid-connect
        Require valid-user
    </Location>
    ProxyPreserveHost On
   ProxyPass / ${banckendapiurl}
   ProxyPassReverse / ${banckendapiurl}   
</VirtualHost>

<VirtualHost sso3_local:80>
    ServerName sso3_local
    OIDCProviderMetadataURL http://SSO3….
    <Location />
        AuthType openid-connect
        Require valid-user
    </Location>
    ProxyPreserveHost On
    ProxyPass / ${banckendapiurl}
    ProxyPassReverse / ${banckendapiurl}   
</VirtualHost>

/etc/hosts内容

127.0.0.1   localhost  sso3_local  internal_sso2

问题分析与解决方案

问题根源

  1. ProxyPreserveHost On的误用:第一个VirtualHost中开启该配置后,代理请求会把原始Host头(即${MON_IP_HOST})传递给后端虚拟主机。而Apache虚拟主机匹配逻辑是:当请求Host头与虚拟主机ServerName不匹配时,默认使用配置文件中第一个匹配端口的虚拟主机,这就是调整顺序后跳转目标变化的原因。
  2. 内部虚拟主机监听范围限制:内部两个虚拟主机仅监听internal_sso2:80和sso3_local:80,但代理请求的Host头被篡改后,无法触发对应虚拟主机的匹配规则,只能 fallback 到第一个匹配端口的虚拟主机。

正确配置方法

方案1:针对内部代理请求关闭ProxyPreserveHost

保留内部虚拟主机的监听配置,仅在第一个虚拟主机中针对sso2、sso3的代理请求关闭ProxyPreserveHost,让后端虚拟主机能通过正确的Host头(internal_sso2/sso3_local)匹配到对应配置:

<VirtualHost *:80>
    ServerName ${MON_IP_HOST}
    OIDCProviderMetadataURL http://SSO1…….
    <Location />
        #public
    </Location>
    <Location /api/SSO1/login>
        AuthType openid-connect
        Require valid-user
    </Location>

    # 针对sso2代理关闭PreserveHost
    <Proxy http://internal_sso2/api/sso2/login>
        ProxyPreserveHost Off
    </Proxy>
    ProxyPass /api/sso2/login  http://internal_sso2/api/sso2/login
    ProxyPassReverse /api/sso2/login  http://internal_sso2/api/sso2/login

    # 针对sso3代理关闭PreserveHost
    <Proxy http://sso3_local/api/sso3/login>
        ProxyPreserveHost Off
    </Proxy>
    ProxyPass /api/sso3/login  http://sso3_local/api/sso3/login
    ProxyPassReverse /api/sso3/login  http://sso3_local/api/sso3/login

    #--- main proxy pass ---
    ProxyPreserveHost On
    ProxyPass / ${banckendapiurl}
    ProxyPassReverse / ${banckendapiurl}  
</VirtualHost>

方案2:统一内部虚拟主机监听范围,通过ServerName精准匹配

将内部两个虚拟主机的监听地址改为*:80,让Apache通过Host头匹配对应虚拟主机,同时在代理时显式设置Host头:

修改内部虚拟主机配置

<VirtualHost *:80>
    ServerName internal_sso2
    OIDCProviderMetadataURL http://SSO2 ……
    <Location />
        AuthType openid-connect
        Require valid-user
    </Location>
    ProxyPreserveHost On
    ProxyPass / ${banckendapiurl}
    ProxyPassReverse / ${banckendapiurl}   
</VirtualHost>

<VirtualHost *:80>
    ServerName sso3_local
    OIDCProviderMetadataURL http://SSO3….
    <Location />
        AuthType openid-connect
        Require valid-user
    </Location>
    ProxyPreserveHost On
    ProxyPass / ${banckendapiurl}
    ProxyPassReverse / ${banckendapiurl}   
</VirtualHost>

修改第一个虚拟主机的代理配置

# 针对sso2的代理,显式设置Host头
ProxyPass /api/sso2/login  http://internal_sso2/api/sso2/login
ProxyPassReverse /api/sso2/login  http://internal_sso2/api/sso2/login
RequestHeader set Host "internal_sso2"

# 针对sso3的代理,显式设置Host头
ProxyPass /api/sso3/login  http://sso3_local/api/sso3/login
ProxyPassReverse /api/sso3/login  http://sso3_local/api/sso3/login
RequestHeader set Host "sso3_local"

#--- main proxy pass ---
ProxyPreserveHost On
ProxyPass / ${banckendapiurl}
ProxyPassReverse / ${banckendapiurl}  

额外注意事项

  • 确保Apache已启用mod_proxy、mod_proxy_http、mod_headers(使用RequestHeader时)和mod_auth_openidc模块。
  • 测试时可通过curl -v http://${MON_IP_HOST}/api/sso2/login查看请求头和跳转过程,确认Host头是否正确传递。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 03:38:14