【问题标题】:Apache can't connect to new tomcat 9 ajpApache 无法连接到新的 tomcat 9 ajp
【发布时间】:2020-12-09 19:48:45
【问题描述】:

在将 Spring boot 的版本从 2.1.4 升级到 2.3.2 后,我的 apache2 无法再(通过 ajp)连接到 Spring boot 的嵌入式 tomcat。

它显示以下错误:

[proxy:error] [pid xxxx ] (111)Connection refused: AH00957: AJP: attempt to connect to 10.0.75.1:8500 (10.0.75.1) failed
[proxy_ajp:error] [pid xxxx ] [client xxx ] AH00896: failed to make connection to backend: 10.0.75.1, referer: http://myapp.develop/home/

我的开发环境是这样设置的:

  • 一个 Angular 应用程序(运行在 4200 上的节点服务器)

  • 一个 Spring Boot 后端(在端口 8500 上的 tomcat 上设置 ajp 连接器)

  • 一个前端 apache2 服务器(在一个 docker 容器上)设置为将请求重定向到两个应用程序:

    <VirtualHost *:80>
    ServerName myapp.develop
    
    ProxyPass "/home" "http://10.0.75.1:4200/home"
    ProxyPassReverse "/home" "http://10.0.75.1:4200/home"
    
    ProxyPass "/backend" "ajp://10.0.75.1:8500/backend"
    ProxyPassReverse "/backend" "ajp://10.0.75.1:8500/backend"
    

我通过 /etc/hosts 上的域名访问我的网络应用程序:myapp.develop

这是我的spring boot tomcat的配置

   Connector connector = new Connector("AJP/1.3");
   connector.setScheme("http");
   connector.setPort(8500);
   connector.setSecure(false);
   connector.setAllowTrace(false);
   ((AbstractAjpProtocol) connector.getProtocolHandler()).setSecretRequired(false);

在 app.properties 中:

tomcat.ajp.port=8500
tomcat.ajp.remoteauthentication=false
tomcat.ajp.enabled=true

这是 tomcat 日志:

o.s.b.w.e.t.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http) 8500 (http)
o.a.c.h.Http11NioProtocol    : Initializing ProtocolHandler ["http-nio-8080"]
o.a.c.a.AjpNioProtocol       : Initializing ProtocolHandler ["ajp-nio-127.0.0.1-8500"]
o.a.c.c.StandardService      : Starting service [Tomcat]
o.a.c.c.StandardEngine       : Starting Servlet engine: [Apache Tomcat/9.0.37]

我怀疑这种变化:

  • 从 8.5.51 开始,AJP 连接器的默认侦听地址更改为环回地址,而不是所有地址。

是什么导致了我这个问题,但我不知道如何解决它。

【问题讨论】:

    标签: spring-boot apache tomcat


    【解决方案1】:

    我在升级 tomcat 版本时遇到了类似的问题。将下面提到的属性添加到 ajp 连接器有助于我的情况。

    connector.setProperty("address","0.0.0.0");
    connector.setProperty("allowedRequestAttributesPattern",".*");
    ((AbstractAjpProtocol)connector.getProtocolHandler()).setSecretRequired(false);
    

    详细说明:

    你的疑问:

    从 8.5.51 开始,AJP 连接器的默认监听地址是 改为环回地址而不是所有地址。

    在此更新之前,tomcat AJP 连接器愿意接受来自任何 IP 地址的请求,因此不需要显式指定“地址”属性。但在此更新之后,默认行为是 AJP 连接器愿意接受仅作为 localhost(环回)发出的请求。使用下面列出的“地址”属性将侦听范围扩展到环回地址

    connector.setProperty("address","0.0.0.0"); // OR connector.setProperty("address","::");
    

    使用下面的属性来启用所有类型的请求属性(除非你有标题信息,在这种情况下启用特定的)。具有无法识别的请求属性的请求将被拒绝并返回 403 响应:

    connector.setProperty("allowedRequestAttributesPattern",".*"); 
    

    使用“secretRequired”属性来定义是否需要与 HTTP 服务器交换密钥以允许通过 ajp 的请求。如果是,那么也设置“秘密”属性。否则请求将失败并返回 403。

    ((AbstractAjpProtocol)connector.getProtocolHandler()).setSecretRequired(false);
    

    参考:Apache Tomcat 8 Configuration Reference

    使用 AJP 协议需要额外的安全考虑 因为它允许更直接地操作 Tomcat 的内部 数据结构比 HTTP 连接器。应特别注意 支付给 addresssecretsecretRequiredallowedRequestAttributesPattern 属性。

    【讨论】:

      【解决方案2】:

      我从未见过在这样的代码中设置连接器,而是在 server.xml 中声明

      但是,您的代码是

      Connector connector = new Connector("AJP/1.3");
      connector.setScheme("http");
      connector.setPort(8500);
      connector.setSecure(false);
      connector.setAllowTrace(false);
      ((AbstractAjpProtocol) connector.getProtocolHandler()).setSecretRequired(false);
      

      后来你说你知道这个重大变化

      从 8.5.51 开始,AJP 连接器的默认侦听地址更改为环回地址,而不是所有地址。

      结合两者:您从未在代码中设置侦听地址 - 因此您可能会使用默认值。当您尝试转发到非环回地址时,将无法以这种方式到达服务器。

      此答案的匿名编辑建议 connector.setAttribute("address", "0.0.0.0");,但就我个人而言,我更愿意将其保存在 server.xml 中:连接器通常不会在运行时配置和更改,并且让您的管理员编辑文本文件非常重要日常操作更方便。

      【讨论】:

      • 在 Spring Boot 中,Tomcat 是嵌入在 webapp 中的,所以没有 server.xml 可以编辑。 OP 没有其他选择,只能以编程方式创建连接器。
      • 当然,他仍然应该通过应用程序属性使连接器可配置。他似乎已经声明了一些,但从未在代码中使用它们。
      猜你喜欢
      • 2012-11-01
      • 2018-03-31
      • 2022-08-22
      • 2012-09-09
      • 2012-01-02
      • 2020-06-29
      • 2017-12-08
      • 2021-10-27
      • 2021-06-14
      相关资源
      最近更新 更多