Krzysztof Skrzynecki
Krzysztof Skrzynecki

Reputation: 2525

AJP in containerised Spring boot app doesn't work

I'm trying to use AJP protocol to communicate with the app created using Spring Boot 2.2.6 with embedded Tomcat and containerised using this official guide. My server uses Apache Server to proxy all requests to different apps and containerised Spring boot app is one of them. Communication works just fine when using http - AJP communication doesn't work though. Moreover, it works just fine when I didn't containerised the app and just launch it using java command-line tool.

I'm using AJPing script to check AJP access.

And here is AJP connector configuration:

@Configuration
public class TomcatConfiguration implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>
{
    @Value( "${tomcat.ajp.secret}" )
    String ajpSecret;

    @Override
    public void customize( TomcatServletWebServerFactory factory )
    {
        factory.addAdditionalTomcatConnectors( ajpConnector() );
    }

    private Connector ajpConnector()
    {
        Connector connector = new Connector( "AJP/1.3" );
        AjpNioProtocol protocol = (AjpNioProtocol) connector.getProtocolHandler();
        protocol.setSecret( ajpSecret );
        connector.setPort( 8009 );
        connector.setSecure( true );

        return connector;
    }
}

Upvotes: 1

Views: 3604

Answers (2)

SpringBoot2Migration
SpringBoot2Migration

Reputation: 11

Maybe

https://tomcat.apache.org/tomcat-9.0-doc/config/ajp.html

address

For servers with more than one IP address, this attribute specifies which address will be used for listening on the specified port. By default, the connector will listen on the loopback address. Unless the JVM is configured otherwise using system properties, the Java based connectors (NIO, NIO2) will listen on both IPv4 and IPv6 addresses when configured with either 0.0.0.0 or ::. The APR/native connector will only listen on IPv4 addresses if configured with 0.0.0.0 and will listen on IPv6 addresses (and optionally IPv4 addresses depending on the setting of ipv6v6only) if configured with ::.

Upvotes: 1

Krzysztof Skrzynecki
Krzysztof Skrzynecki

Reputation: 2525

So I investigated this issue by checking what ports are used in container:

docker ps
docker exec -it ${docker-id-from-previous-command} netstat -lntup

and here is a result I got:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.11:8009            0.0.0.0:*               LISTEN      1/java
tcp        0      0 127.0.0.11:37327        0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1/java
udp        0      0 127.0.0.11:55038        0.0.0.0:*   

So I could see that port 8009 used by AJP was there, but bind-address was different than the one used by port 8080. So setting up port address to "0.0.0.0" resolved my problem, but I can't say I fully understand it - here is the configuration with a fix:

@Configuration
public class TomcatConfiguration implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>
{
    @Value( "${tomcat.ajp.secret}" )
    String ajpSecret;

    @Override
    public void customize( TomcatServletWebServerFactory factory )
    {
        factory.addAdditionalTomcatConnectors( ajpConnector() );
    }

    private Connector ajpConnector()
    {
        Connector connector = new Connector( "AJP/1.3" );
        AjpNioProtocol protocol = (AjpNioProtocol) connector.getProtocolHandler();
        protocol.setSecret( ajpSecret );
        connector.setPort( 8009 );
        connector.setSecure( true );

        try
        {
            protocol.setAddress( InetAddress.getByName( "0.0.0.0" ) );
        }
        catch( UnknownHostException e )
        {
            e.printStackTrace();
        }

        return connector;
    }
}

Upvotes: 4

Related Questions