リモート開発メインのソフトウェア開発企業のエンジニアブログです

CentOS 7で Tomcat 9 + Apache を動かす

2020年になって再び Tomcat を触る事になるとは思いませんでしたが、とあるプロジェクトで以下の構成のシステムを立ち上げることになりました。

  • CentOS 7
  • Tomcat 9
  • Apache 2.4

yum コマンドでインストールできる Tomcat は7系なので、Tomcat 9 は公式サイトからダウンロードしてきてインストールしました。

簡単だろうと思ってたのですが、意外なところでハマって2時間くらい費やしてしまったので、念のためメモしておきます。

手順概要

まずは、やったことを大まかにまとめておきます。

  • SELinux を無効化
  • 各種ソフトのインストール
    • Apache、Java を yum でインストール
    • Tomcat をダウンロードして適当な場所に配置
  • Tomcat の設定
    • tomcat ユーザー・グループの作成
    • systemd への登録
    • server.xml を修正
  • Apache の設定
  • サービスの起動設定

手順詳細

SELinux の無効化

仕事でLinuxを使い始めて20年になりますが、いまだに SELinux を有効化している商用システムに関わったことがありません。

何はともあれ、今回のプロジェクトでも SELinux を使う要件はありませんので、以下のファイルを修正してサクッと無効化します。

sudo vi /etc/sysconfig/selinux

各種ソフトのインストール

yum でインストールできるものは、以下の通りインストールします。

sudo yum install httpd wget java-1.8.0-openjdk

Tomcat は、公式サイトから落としてきて、/opt 配下に配置します。

wget https://downloads.apache.org/tomcat/tomcat-9/v9.0.33/bin/apache-tomcat-9.0.33.tar.gz

tar zxvf apache-tomcat-9.0.33.tar.gz
sudo mv apache-tomcat-9.0.33 /opt/
cd /opt/
sudo ln -s apache-tomcat-9.0.33/ tomcat9

Tomcat の設定

RPM でインストールする時は気にする必要がありませんが、手動でインストールする場合には各種設定を自分でやる必要があります。

まずは、ユーザーとグループを作成します。また、/opt 配下に配置したファイルの所有者も変更しておきます。

sudo groupadd --system tomcat
sudo useradd -M -d /opt/tomcat9 -g tomcat tomcat
sudo chown -R tomcat: /opt/apache-tomcat-9.0.33/

次に、/etc/systemd/system/tomcat9.service というファイルを、以下の内容で作成します。

[Unit]
Description=Tomcat 9 servlet container
After=network.target

[Service]
Type=forking

User=tomcat
Group=tomcat

Environment="JAVA_HOME=/usr/lib/jvm/jre"
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom"

Environment="CATALINA_BASE=/opt/tomcat9"
Environment="CATALINA_HOME=/opt/tomcat9"
Environment="CATALINA_PID=/opt/tomcat9/temp/tomcat.pid"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"

ExecStart=/opt/tomcat9/bin/startup.sh
ExecStop=/opt/tomcat9/bin/shutdown.sh

[Install]
WantedBy=multi-user.target

次に、server.xml で、AJPリスナーを有効化し、普通の HTTP リスナーは不要なので無効化します。変更前後の diff を以下に示します。

--- /opt/tomcat9/conf/server.org.xml    2020-03-26 02:09:44.739733134 +0000
+++ /opt/tomcat9/conf/server.xml        2020-03-26 02:49:31.395688240 +0000
@@ -66,9 +66,11 @@
          APR (HTTP/AJP) Connector: /docs/apr.html
          Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
     -->
+    <!--
     <Connector port="8080" protocol="HTTP/1.1"
                connectionTimeout="20000"
                redirectPort="8443" />
+    -->
     <!-- A "Connector" using the shared thread pool-->
     <!--
     <Connector executor="tomcatThreadPool"
@@ -113,12 +115,11 @@
     -->

     <!-- Define an AJP 1.3 Connector on port 8009 -->
-    <!--
     <Connector protocol="AJP/1.3"
+               secretRequired="false"
                address="::1"
                port="8009"
                redirectPort="8443" />
-    -->

     <!-- An Engine represents the entry point (within Catalina) that processes
          every request.  The Engine implementation for Tomcat stand alone

ポイントは secretRequires="false" というところです。

Apache の設定

今回のプロジェクトでは OpenAM というソフトウェアを Tomcat で動かしたのですが、/openam にアクセスすると Tomcat の /openam を見に行くようにしたいので、/etc/httpd/conf.d/openam.conf というファイルを以下の内容で作成しました。

<VirtualHost *:80>
    ServerName openam.example.com
    ProxyPass /openam ajp://localhost:8009/openam
</VirtualHost>

起動設定

最後に、Apache と Tomcat を自動的に起動するように設定し、reboot すれば完了です。

sudo systemctl daemon-reload
sudo systemctl enable tomcat9
sudo systemctl enable httpd
sudo shutdown -r now

途中で出たエラーの内容

上の方で「ポイントは secretRequires="false" というところです」と書きましたが、その記述が無いと、以下のようなエラーが出ました。

26-Mar-2020 02:11:55.791 SEVERE [main] org.apache.catalina.util.LifecycleBase.handleSubClassException Failed to start component [Connector[AJP/1.3-8009]]
        org.apache.catalina.LifecycleException: Protocol handler start failed
                at org.apache.catalina.connector.Connector.startInternal(Connector.java:1038)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
                at org.apache.catalina.core.StandardService.startInternal(StandardService.java:438)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
                at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
                at org.apache.catalina.startup.Catalina.start(Catalina.java:633)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.lang.reflect.Method.invoke(Method.java:498)
                at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:343)
                at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:474)
        Caused by: java.lang.IllegalArgumentException: The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "". This combination is not valid.
                at org.apache.coyote.ajp.AbstractAjpProtocol.start(AbstractAjpProtocol.java:264)
                at org.apache.catalina.connector.Connector.startInternal(Connector.java:1035)
                ... 12 more

エラーメッセージで検索したところ、以下のサイトが引っかかって、そこで解決策を知りました。

Upgrading Apache Tomcat to version 8.5.51 can s… | BMC Communities

参照したログファイルは /opt/tomcat9/logs/catalina.log です。

secretRequires の説明などは、公式サイトの以下のページを参照して下さい。

Apache Tomcat 9 Configuration Reference (9.0.33) – The AJP Connector

まとめ

Tomcat 9 + Apache 2.4 on CentOS 7 というのはあまり人気の無い組み合わせなのでしょう。今回のエラーの原因となった secretRequires に関して記載しているサイトは少なかったため、最初は動かなくて迷いました。

もし同じような問題ではまっている人の参考になれば、と思い本記事を書きました。

最後に完全な余談ですが、古参開発者にとって、Catalina といえば macOS ではなくて Tomcat です。

← 前の投稿

AWS CLI のプロファイル切り替え関連

次の投稿 →

AWS CLI v2の公式Dockerイメージが出たみたいなので使ってみた

コメントを残す