2
4

More than 1 year has passed since last update.

CentOS8.2でhttpdとTomcat9を連携させる手順

Last updated at Posted at 2020-12-06
../

VPSサーバー(CentOS8.2)にTomcat9をインストールしている。インターネットからhttp(80ポート)やhttps(443ポート)で受けたリクエストを、Tomcat9で動的に制御できるようにしたい。AJPプロトコル(Apache Jserv Protocol)の実装であるmod_proxy_ajpを利用したい。その手順をメモしておく。

Tomcat9では、初期設定で、8080ポートで HTTP 1.1 の通信を受け付け、8009ポートで AJP 1.3 の通信を受け付けるようになっている。私の環境では、80ポートや443ポートで受け付けた通信は、バーチャルホストを使ってサイトごとに制御し、動的サイトはすべてTomcat9で処理するようにしようと考えている。例えば、kankeri.comはLet's Encyptでサーバー証明し、xxx.comはプライベートのサーバー証明とする。サーバー認証は、httpd側で行い、Tomcat9側では行わないようにする。

  • kankeri.com/ --> ようこそkankeriへ (Let's Encypt証明)
  • xxx.com/ --> ようこそxxxへ (プライベートサーバー証明)

バージョンの確認


$ httpd -version
Server version: Apache/2.4.37 (centos)
Server built:   Sep 15 2020 15:41:16

$ ${CATALINA_HOME}/bin/version.sh
...
Server version: Apache Tomcat/9.0.40
Server built:   Nov 12 2020 15:35:02 UTC
Server number:  9.0.40.0
OS Name:        Linux
OS Version:     4.18.0-193.28.1.el8_2.x86_64
Architecture:   amd64
JVM Version:    11.0.9+11-LTS
JVM Vendor:     Red Hat, Inc.

httpd:プロキシモジュールの確認

まず、00-proxy.conf に以下の設定が含まれていることを確認する。

$ vi /etc/httpd/conf.modules.d/00-proxy.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so

httpd:プロキシの設定

ProxyPassとProxyPassReverseの記述は、/etc/httpd/conf/httpd.confや/etc/httpd/conf.d/ssl.confにはしない。それぞれのバーチャルホストのconfファイルを作成し、そこに記述する方針とした。

  • vhost-02-kankeri.conf (kankeri.com:80用)
  • vhost-02-kankeri-le-ssl.conf (kankeri.com:443用)
  • vhost-03-xxx.conf (xxx.com:80用)
  • vhost-03-xxx-ssl.conf (xxx.com:443用)

vhost-02-kankeri.conf(kankeri.com:80用)

このconfファイルは、手作業で作成したもの。Rewriteの4行はCertbotで追記される。http:/のリクエストはhttps:/に置換される。

$ vi /etc/httpd/conf.d/vhost-02-kankeri.conf

<VirtualHost kankeri.com:80>
ServerName kankeri.com
ServerAlias www.kankeri.com
ServerAdmin webmaster@kankeri.com
DocumentRoot "/opt/tomcat9/webapps/kankeri"

<Directory "/opt/tomcat9/webapps/kankeri">
    Options FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

ErrorLog logs/kankeri-error_log
CustomLog logs/kankeri-access_log combined

RewriteEngine on
RewriteCond %{SERVER_NAME} =kankeri.com[OR]
RewriteCond %{SERVER_NAME} =www.kankeri.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

vhost-02-kankeri-le-ssl.conf(kankeri.com:443用)

Certbotで自動生成されたconfファイルを編集する。Let's EncyptのSSLサーバー証明を使う。 SSL証明書(Let's Encrypt)をセットアップする手順で作成する。そこに、mod_proxy_ajpで遷移できるようにProxyPassとProxyPassReverseを追記する。

$ vi /etc/httpd/conf.d/vhost-02-kankeri-le-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost kankeri.com:443>
ServerName kankeri.com
ServerAlias www.kankeri.com
ServerAdmin webmaster@kankeri.com
DocumentRoot "/opt/tomcat9/webapps/kankeri"

<Directory "/opt/tomcat9/webapps/kankeri">
    Options FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

ProxyPass / ajp://localhost:8009/kankeri/

ErrorLog logs/kankeri-error_log
CustomLog logs/kankeri-access_log combined

SSLCertificateFile /etc/letsencrypt/live/kankeri.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/kankeri.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

ProxyPassの末尾には/が必要だが、ProxyPassReverseの末尾には/は不要らしい。リダイレクト時にLocationヘッダを書き換える必要がないからだそうだ。

vhost-03-xxx.conf(xxx.com:80用)

このconfファイルは、手作業で作成したもの。vhost-02-kankeri.confをコピーして修正したものになる。

$ vi /etc/httpd/conf.d/vhost-03-xxx.conf

<VirtualHost xxx.com:80>
ServerName xxx.com
ServerAlias www.xxx.com
ServerAdmin webmaster@xxx.com
DocumentRoot "/opt/tomcat9/webapps/xxx"

<Directory "/opt/tomcat9/webapps/xxx">
    Options FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

ErrorLog logs/xxx-error_log
CustomLog logs/xxx-access_log combined

RewriteEngine on
RewriteCond %{SERVER_NAME} =xxx.com [OR]
RewriteCond %{SERVER_NAME} =www.xxx.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

vhost-04-xxx-ssl.conf(xxx.com:443用)

xxx.comはプライベートのSSLサーバー証明を使う。 SSL証明書(プライベート認証局)をセットアップする手順で行う。そこに、mod_proxy_ajpで遷移できるようにProxyPassとProxyPassReverseを追記する。

$ vi /etc/httpd/conf.d/vhost-04-xxx-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost xxx.com:443>
ServerName xxx.com
ServerAlias www.xxx.com
ServerAdmin webmaster@xxx.com
DocumentRoot "/opt/tomcat9/webapps/xxx"

<Directory "/opt/tomcat9/webapps/xxx">
    Options FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

ProxyPass / ajp://localhost:8009/xxx/

ErrorLog logs/xxx-error_log
CustomLog logs/xxx-access_log combined

SSLCertificateFile /etc/pki/tls/xxx.com/server.crt
SSLCertificateKeyFile /etc/pki/tls/xxx.com/server.key
</VirtualHost>
</IfModule>

Tomcat9:server.xmlの設定

続いて、Tomcat側の設定をする。server.xmlを編集するだけである。実は、結構苦戦させられたのだが、解決には、https://qiita.com/polarbear08/items/f016a0675e6c9637e7b8 の記事が参考になった。「Tomcat9では9.0.31以降からAJPでの通信をするためにはTomcat側で初期設定が必要となる」とのことだった。

$ vi ${CATALINA_HOME}/conf/server.xml

    <Connector protocol="AJP/1.3"
               address="::1"
               port="8009"
               redirectPort="8443" />
	↓
    <Connector protocol="AJP/1.3"
               address="localhost"
               secretRequired="false" 
               tomcatAuthentication="false" URIEncoding="UTF-8"
               port="8009"
               redirectPort="8443" />

address属性は、localhostにしておく。0.0.0.0を設定すると、全てのIPアドレスを許容するようになる。また、secretRequired="false" の属性を追加する必要がある。httpd側でパスワードを設定して、Tomcat9側で認証することもできるようだが、それは行わないことにした。

再起動と確認

それぞれのDocumentRootにダミーのHTMLを配置し、Apache httpdとTomcat9のサービスを再起動し、ブラウザからアクセスしてみる。

$ ls -la ${CATALINA_HOME}/webapps/kankeri
-rw-r--r--  1 tomcat9 tomcat9   98   2 11:58 index.html
$ ls -la ${CATALINA_HOME}/webapps/xxx
-rw-r--r--  1 tomcat9 tomcat9   98   2 11:58 index.html
$ systemctl restart httpd
$ systemctl restart tomcat9

http://xxx.com/ 
http://www.xxx.com/
https://xxx.com/	
https://www.xxx.com/

補足1: Tomcatのログ情報の使い方

当初、AJPの設定がよく分からず、以下のようなエラーがよく出ていた。

Service Unavailable
The server is temporarily unable to service your request 
due to maintenance downtime or capacity problems. Please try again later.

httpdの出力ログを見ると、以下のような感じである。

$ tail -50 /var/log/httpd/kankeri-error_log  | more
[Sun Dec 06 11:57:10.385924 2020] [proxy:error] 
[pid 400345:tid 140206267074304] (111)Connection refused: AH00957: AJP: attempt to connect to 127.0.0.1:8009 (localhost) failed
[Sun Dec 06 11:57:10.386019 2020] [proxy_ajp:error] 
[pid 400345:tid 140206267074304] [client 27.xx.xx.xx:51397] AH00896: failed to make connection to backend: localhost

この「AJP: attempt to connect to 127.0.0.1:8009 (localhost) failed」には、しばらく悩まされた。Tomcatのログ(catalina.out)で詳細をみるために、ログレベルをINFOからDEBUGに変更して、Tomcatを再起動し、再現させ、ログを眺めてみた。

$ vi ${CATALINA_HOME}/conf/logging.properties
 INFO
 ↓
 DEBUG
$ systemctl restart tomcat9

$ tail -50 ${CATALINA_HOME}/logs/catalina.out | more
06-Dec-2020 13:11:09.262 情報 [main] org.apache.catalina.util.LifecycleBase.handleSubClassException 
コンポーネント[Connector[AJP/1.3-8009]]の開始に失敗しました。
org.apache.catalina.LifecycleException: 
プロトコルハンドラの起動に失敗しました
Caused by: java.lang.IllegalArgumentException: 
AJP コネクタは secretRequired="true" として構成されていますが、
secret 属性は null または空文字列が設定されています。
この組み合わせは有効ではありません

この情報を元にsecretRequired="true"あたりの問題だとたどり着くことができた。また、ログレベルがDEBUGだと、server.xmlの記述ミスがあれば、詳細が出力され、分析が容易になる。

補足2: AJP:8009の前に8080ポートでの接続確認

また、ajp:8009ポートで接続できない場合、まず、http:8080ポートで接続できるかを先に確認した方がよい。原因の切り分けにはなるだろう。

    ProxyPass / http://localhost:8080/kankeri 
	↓
    ProxyPass / ajp://localhost:8009/kankeri

以上

../
2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4