Tomcat за Apache, используя ajp для Spring загрузочного приложения

Я пытаюсь настроить веб-сервер Apache с помощью приложения Spring Boot, которое использует встроенный Tomcat. До Spring Загрузка я использовал для создания файла ajp.conf, например:

<VirtualHost *:80>
   ServerName localhost
   <Proxy *>
      AddDefaultCharset Off
      Order deny,allow
      Allow from all
   </Proxy>

   ProxyPass /app ajp://localhost:8009/app
   ProxyPassReverse /app ajp://localhost:8009/app

 </VirtualHost>

И включите в файл httpd.conf, например

Include /opt/lampp/apache2/conf/ajp.conf

И в файле Tomcat server.xml я использовал его для прослушивания порта 8009

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" connectionTimeout="5000"

Эта настройка работает. Но теперь, используя Spring Boot, я пытаюсь добиться чего-то подобного со встроенным tomcat. Я прочитал Spring Загрузочная документация здесь и добавил в файл application.yml следующие свойства:

server:
    port: 8080
    tomcat:
        remote_ip_header: x-forwarded-for
        protocol_header: x-forwarded-proto

Мой файл ajp.conf выглядит так:

<VirtualHost *:80>
   ServerName localhost
   <Proxy *>
      AddDefaultCharset Off
      Order deny,allow
      Allow from all
   </Proxy>

   ProxyPass /app ajp://localhost:8009/
   ProxyPassReverse /app ajp://localhost:8009/

 </VirtualHost>

У меня есть мой Spring класс конфигурации загрузки tomcat как

@Configuration
public class TomcatConfiguration {

private final Logger log = LoggerFactory.getLogger(TomcatConfiguration.class);

@Bean
public EmbeddedServletContainerFactory servletContainer() {
    TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
    tomcat.addAdditionalTomcatConnectors(createConnector());
    tomcat.addContextValves(createRemoteIpValves());
    return tomcat;
}

private RemoteIpValve createRemoteIpValves(){
    RemoteIpValve remoteIpValve = new RemoteIpValve();
    remoteIpValve.setRemoteIpHeader("x-forwarded-for");
    remoteIpValve.setProtocolHeader("x-forwarded-protocol");
    return remoteIpValve;
}

private Connector createConnector() {
    Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
    Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
    connector.setScheme("ajp");
    connector.setProtocol("AJP/1.3");
    connector.setRedirectPort(8443);
    //connector.setSecure(true);
    connector.setPort(8009);
    return connector;
}

В моих журналах ошибок apache я вижу:

AH01080: ajp_msg_check_header() got bad signature 4854
[proxy_ajp:error] [pid 24073] AH01031: ajp_ilink_receive() received bad header
[proxy_ajp:error] ajp_read_header: ajp_ilink_receive failed
[proxy_ajp:error] (120007)APR does not understand this error code: [client xx.xx.xx.xx:60916] AH00878: read response failed from (null) (*)

Не уверен, что происходит здесь. Я много раз искал в Интернете, но не мог найти хорошую документацию о том, как обслуживать tomcat за apache с помощью загрузочных приложений Spring. В конце концов, я хотел бы также загрузить несколько экземпляров tomcat.

Ответ 1

Выведено из комментариев выше:

@Configuration
public class TomcatAjpConfig {

@Bean
@SuppressWarnings("static-method")
public EmbeddedServletContainerFactory servletContainer() {
    TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
    tomcat.addAdditionalTomcatConnectors(createConnector());
    tomcat.addContextValves(createRemoteIpValves());
    return tomcat;
}

private static RemoteIpValve createRemoteIpValves() {
    RemoteIpValve remoteIpValve = new RemoteIpValve();
    remoteIpValve.setRemoteIpHeader("x-forwarded-for");
    remoteIpValve.setProtocolHeader("x-forwarded-proto");
    return remoteIpValve;
}

private static Connector createConnector() {
    Connector connector = new Connector("AJP/1.3");
    connector.setPort(8009);
    return connector;
}

}

Ответ 2

Имел аналогичную проблему, но с HTTP-прокси. После некоторой отладки Spring Boot 1.3 я нашел следующее решение. Он должен быть похож на прокси AJP.

1. Вам нужно настроить заголовки на своем прокси-сервере Apache:

<VirtualHost *:443>
    ServerName www.myapp.org
    ProxyPass / http://127.0.0.1:8080/
    RequestHeader set X-Forwarded-Proto https
    RequestHeader set X-Forwarded-Port 443
    ProxyPreserveHost On
    ... (SSL directives omitted for readability)
</VirtualHost>

2. Вы должны сообщить своему приложению Spring Boot, чтобы использовать эти заголовки. Поэтому введите следующую строку в свой application.properties(или в любое другое место, где Spring Boots понимает свойства):

server.use-forward-headers=true

Если вы правильно выполняете эти две вещи, каждое перенаправление отправки вашего приложения будет не переходить на http://127.0.0.1:8080/[path], но автоматически https://www.myapp.com/[path]

Обновление 1. Документация по этой теме здесь. Вы должны прочитать это, по крайней мере, чтобы узнать о свойстве server.tomcat.internal-proxies, которое определяет диапазон IP-адресов для прокси-серверов, которым можно доверять.

Ответ 3

Настраиваемые свойства throught или yml файл.

@Configuration
@ConfigurationProperties(prefix = "tomcat")
public class TomcatConfiguration {
   private int ajpPort = 8009;

   private boolean ajpAllowTrace = false;
   private boolean ajpSecure = false;
   private String ajpScheme = "http";
   private boolean ajpEnabled;


  @Bean
  public EmbeddedServletContainerFactory servletContainer() {

    TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
    if (isAjpEnabled()) {
        Connector ajpConnector = new Connector("AJP/1.3");
        ajpConnector.setProtocol("AJP/1.3");
        ajpConnector.setPort(getAjpPort());
        ajpConnector.setSecure(isAjpSecure());
        ajpConnector.setAllowTrace(isAjpAllowTrace());
        ajpConnector.setScheme(getAjpScheme());
        tomcat.addAdditionalTomcatConnectors(ajpConnector);
    }

    return tomcat;
    }
// ... Get/Set
}

application.yml

tomcat:
  ajpEnabled: true
  ajpPort: 9009
  ...