WildFlyにAJP Listenerを設定して、Apache（mod_proxy_ajp）と連携する

# What's？

WildFlyでAJPが使えるように設定してみよう、ということで。

WildFlyにAJPを設定して、Apacheのmod_proxy_ajpで連携するところまでやってみたいと思います。

# 環境

今回の環境はこちら。CentOS 8です。

```shell
$ cat /etc/redhat-release
CentOS Linux release 8.4.2105


$ uname -srvmpio
Linux 4.18.0-305.12.1.el8_4.x86_64 #1 SMP Wed Aug 11 01:59:55 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
```

Javaはこちら。

```shell
$ java --version
openjdk 11.0.12 2021-07-20 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.12+7-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.12+7-LTS, mixed mode, sharing)
```

# WildFlyでAJPを設定するための情報

設定方法は、ドキュメントを見るのが筋でしょうということで。

こちらを見ればよさそうです。

[AJP listeners](https://docs.wildfly.org/24/Admin_Guide.html#Undertow_AJP_listeners)

手順的には、以下のようです。

- AJP用の`socket-binding`の定義
- `ajp-listener`を追加

こちらに沿ってやっていきましょう。

# サンプルアプリケーション

動作確認をするためのアプリケーションが必要ですね、サンプルを作りましょう。

Mavenプロジェクトで、JAX-RSを使ったアプリケーションにします。

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>simple-jaxrs</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>

    <dependencies>
        <dependency>
            <groupId>jakarta.platform</groupId>
            <artifactId>jakarta.jakartaee-web-api</artifactId>
            <version>8.0.0</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>ROOT</finalName>
    </build>
</project>
```

JAX-RSリソースクラス。

```java:src/main/java/com/example/MessageResource.java
package com.example;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("message")
public class MessageResource {
    @GET
    @Path("hello-world")
    @Produces(MediaType.TEXT_PLAIN)
    public String helloWorld() {
        return "Hello World!!";
    }

    @GET
    @Path("build")
    @Produces(MediaType.TEXT_PLAIN)
    public String build(@QueryParam("word") String word) {
        return String.format("Hello %s!!", word);
    }
}
```

JAX-RSの有効化。

```java:src/main/java/com/example/JaxrsApp.java
package com.example;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("")
public class JaxrsApp extends Application {
}
```

パッケージング。

```shell
$ mvn package
```

`ROOT.war`というファイルができあがるので、こちらを使います。

# WildFlyのインストール

まずはWildFlyをインストールをします。24.0.1を使います。

```shell
$ curl -LO https://download.jboss.org/wildfly/24.0.1.Final/wildfly-24.0.1.Final.zip
$ unzip wildfly-24.0.1.Final.zip
$ cd wildfly-24.0.1.Final
```

スタンドアロンサーバーとして起動。

```shell
$ bin/standalone.sh
```

管理CLIに接続。

```shell
$ bin/jboss-cli.sh -c
```

アプリケーションをデプロイ。

```shell
[standalone@localhost:9990 /] deploy /path/to/target/ROOT.war
```

まずは動作確認。

```shell
$ curl localhost:8080/message/hello-world
Hello World!!


$ curl localhost:8080/message/build?word=WildFly
Hello WildFly!!
```

ここまでで、AJPを設定する前までの準備は完了です。

# WildFlyにAJPリスナーを設定する

最初に`socket-binding`の設定を見てみます。

デフォルトで、AJP用の`socket-binding`の定義が入っているようです。

```shell
[standalone@localhost:9990 /] /socket-binding-group=standard-sockets/socket-binding=ajp:read-resource(include-runtime)
{
    "outcome" => "success",
    "result" => {
        "bound" => false,
        "bound-address" => undefined,
        "bound-port" => undefined,
        "client-mappings" => undefined,
        "fixed-port" => false,
        "interface" => undefined,
        "multicast-address" => undefined,
        "multicast-port" => undefined,
        "name" => "ajp",
        "port" => expression "${jboss.ajp.port:8009}"
    }
}

```

`8009`ポートを使うようですが、リッスンはしていないようです。

```shell
$ sudo ss -tnlp | grep java
LISTEN 0      128        127.0.0.1:8080      0.0.0.0:*    users:(("java",pid=1409,fd=489))
LISTEN 0      128        127.0.0.1:8443      0.0.0.0:*    users:(("java",pid=1409,fd=379))
LISTEN 0      50         127.0.0.1:9990      0.0.0.0:*    users:(("java",pid=1409,fd=510))
```

実際にAJPでリッスンさせるためには、Undertowサブシステムにajp-listenerを追加する必要があります。

```shell
[standalone@localhost:9990 /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding=ajp)
{"outcome" => "success"}

```

これで、AJPでリッスンするようになりました。

```shell
$ sudo ss -tnlp | grep java
LISTEN 0      128        127.0.0.1:8080      0.0.0.0:*    users:(("java",pid=1409,fd=489))
LISTEN 0      128        127.0.0.1:8443      0.0.0.0:*    users:(("java",pid=1409,fd=379))
LISTEN 0      50         127.0.0.1:9990      0.0.0.0:*    users:(("java",pid=1409,fd=510))
LISTEN 0      128        127.0.0.1:8009      0.0.0.0:*    users:(("java",pid=1409,fd=554))
```

# Apache＋mod_proxy_ajpを設定する

次は、ApacheからWildFlyにプロキシするように設定してみましょう。

Apacheをインストール。

```shell
$ sudo dnf install httpd
```

バージョンはこちら。

```shell
$ httpd -V
Server version: Apache/2.4.37 (centos)
Server built:   May 20 2021 04:33:06
Server's Module Magic Number: 20120211:83
Server loaded:  APR 1.6.3, APR-UTIL 1.6.1
Compiled using: APR 1.6.3, APR-UTIL 1.6.1
Architecture:   64-bit
Server MPM:     event
  threaded:     yes (fixed thread count)
    forked:     yes (variable process count)
Server compiled with....
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=256
 -D HTTPD_ROOT="/etc/httpd"
 -D SUEXEC_BIN="/usr/sbin/suexec"
 -D DEFAULT_PIDLOG="run/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"
```

`httpd.conf`に以下の設定を追加。

```shell:/etc/httpd/conf/httpd.conf
ProxyPass / ajp://localhost:8009/
ProxyPassReverse / http://localhost:8009/
```

で、アクセスすると`503`になり、こんなエラーがApacheのエラーログに記録されます。

```shell:/var/log/httpd/error_log
[Sun Aug 15 21:22:03.317824 2021] [proxy:error] [pid 2508:tid 139935789078272] (13)Permission denied: AH00957: AJP: attempt to connect to 127.0.0.1:8009 (localhost) failed
```

`/var/log/audit/audit.log`を見ると、こんな感じに。

```shell:/var/log/audit/audit.log
type=AVC msg=audit(1629030335.451:283): avc:  denied  { name_connect } for  pid=2510 comm="httpd" dest=8009 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket permissive=0
type=SYSCALL msg=audit(1629030335.451:283): arch=c000003e syscall=42 success=no exit=-13 a0=10 a1=55e68b55ddb0 a2=10 a3=7f45637fd82c items=0 ppid=2506 pid=2510 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)ARCH=x86_64 SYSCALL=connect AUID="unset" UID="apache" GID="apache" EUID="apache" SUID="apache" FSUID="apache" EGID="apache" SGID="apache" FSGID="apache"
type=PROCTITLE msg=audit(1629030335.451:283): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
type=AVC msg=audit(1629030335.451:284): avc:  denied  { name_connect } for  pid=2510 comm="httpd" dest=8009 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket permissive=0
type=SYSCALL msg=audit(1629030335.451:284): arch=c000003e syscall=42 success=no exit=-13 a0=10 a1=55e68b55de80 a2=10 a3=7f45637fd82c items=0 ppid=2506 pid=2510 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)ARCH=x86_64 SYSCALL=connect AUID="unset" UID="apache" GID="apache" EUID="apache" SUID="apache" FSUID="apache" EGID="apache" SGID="apache" FSGID="apache"
type=PROCTITLE msg=audit(1629030335.451:284): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
```

SELinuxに阻まれているようなので、以下のように設定します。

```shell
$ sudo setsebool -P httpd_can_network_connect 1
```

これで、Apache（mod_proxy_ajp） → WildFly（AJP）にアクセスできるようになりました。

```shell
$ curl localhost/message/hello-world
Hello World!!


$ curl localhost/message/build?word=WildFly
Hello WildFly!!
```

これで、やりたい構成はできました、と。

# AJPの設定を自分でしてみる

デフォルトで`socket-binding`が入っていたので、これを自分で追加するところからやってみましょう。

まずは、ここまでに定義した`ajp-listener`を削除、`socket-biding`も削除。

```shell
[standalone@localhost:9990 /] /subsystem=undertow/server=default-server/ajp-listener=ajp:remove()
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}

[standalone@localhost:9990 /] /socket-binding-group=standard-sockets/socket-binding=ajp:remove()
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
```

追加は、こうですね。

```shell
[standalone@localhost:9990 /] /socket-binding-group=standard-sockets/socket-binding=ajp:add(port=8009,interface=public)
{"outcome" => "success"}


[standalone@localhost:9990 /] /subsystem=undertow/server=default-server/ajp-listener=ajp:add(socket-binding=ajp)
{"outcome" => "success"}

```