VPSにJavaアプリをデプロイする(Apache/Tomcat導入・連携)

#１．はじめに
　先日サーブレットアプリを制作したので、アプリをWeb上にデプロイしようと思いVPSサーバーをレンタルしたのですが、Linux,サーバーの知識がほぼ全くないために、環境構築にとんでもなく苦戦しました。ここでは、実際の手順に加え「Javaアプリをデプロイするには何が必要なのか？」「ajp連携とはなんなのか？」といったことにも触れて、備忘録としてまとめたいと思います。

#２．環境
参考までに、今回の私の環境を載せておきます。

＜VPS＞
　・さくらのVPS
　・OS:CentOS Linux release 7.8.2003
＜JDK＞
　・バージョン：1.8.0_262
＜Apache＞
　・バージョン:Apache2.4.6
＜Tomcat＞
　・バージョン:apache-tomcat9.0.37　

#３．JavaアプリをWeb上にデプロイするには？
##Javaアプリをデプロイするための環境
動的コンテンツ（Javaアプリ等）は、静的コンテンツ（HTMLファイル等）と異なり、**Webサーバーに加えて「アプリケーションサーバー」を導入しなければ処理できません。**（また、Javaファイルを実行するためにJDKの導入も必要となります）
今回はWebサーバーとして「Apache」、アプリケーションサーバーとして「Tomcat」を使用します。

![server1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673146/7392a6f2-1104-be32-9b71-ed39f2ca3430.png)
一般的なレンタルサーバーは、自分で好きなようにサーバー環境を整えることができないので、VPS（仮想専用サーバー）等、自分で環境構築ができるサーバーを使用する必要があります。
では、↑の図のように、**Webサーバー(Apache)とアプリケーションサーバー(Tomcat)を連携させるにはどうすればいいのか？**その際に用いられるのが「AJP (Apache JServ Protocol)」です。

##ajp(Apache JServ Protocol)とは？　
　ajpとはApacheとTomcatを連携させるためのプロトコルですが、そもそもajpとはなんなのか？こちらのサイトの説明がわかりやすかったので引用させてもらいます。

>ajpとは、Apache Jserv Protocolの略でApache HTTP ServerとApache Tomcatと連携する際に使うプロトコルです。ajpは、TomcatのajpサーバポートとTCP経由で接続するためのプロトコルです。 クライアントよりApacheが受け付けたリクエストをajpでTomcatのajpサーバプログラムに転送され、TomcatはServletなどの処理結果をApacheにレスポンスし、Apacheがレスポンスをクライアントにレスポンスします。

[Apache／Tomcatのajp連携―httpdのmod_proxy_ajp、プロトコル、設定方法。]
(https://www.zealseeds.com/SysDevTech/apache_tomcat/connect/ajp/index.html)

　Tomcatは8080番ポートで HTTPの通信を受け付け8009番ポートで AJP の通信を受け付けています。そのため、```http://IPアドレス:8080```でApacheを介さず、Tomcatに直接アクセスすることができますが、アプリを実際に運用する際にこのポートを使用することはほとんどありません。必ずWebサーバーを介します。**Tomcat は8009番ポートで AJP 1.3 の通信を受け付けているので、Apacheからは、この8009番ポートにAJP通信をすれば良い**ということになります。
![server2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673146/903c1405-2bc7-b4d9-0c5d-6aeb584c187b.png)



##では、実際何をすればいいのか？
今までの話を踏まえて、実際の手順を大まかに羅列すると、

**１　VPSにJDK,Webサーバー(Apache),アプリケーションサーバー(Tomcat)をインストールする。**
**２　ApacheとTomcatを連携するため、以下の処理を行う。**
**（１）(Tomcat側)8080番ポートの設定を無効化し、8009番ポートの設定を有効化する。**
**（２）(Apache側)どんなパスにアクセスされた時にTomcatを連携するのかを設定する。**

となります。

#４．VPSにApache,Tomcatを導入する
##Java８をインストールする（OpenJDK）
　ローカルPCでの環境構築と同様で、これを導入しないとVPSでJavaアプリが動きません。VPS上で開発する予定がないのなら、ランタイムのみのインストールで十分です。
　
〇　ランタイムをインストールする場合

```
# yum install java-1.8.0-openjdk
```

〇　開発環境をインストールする場合


```
# yum install java-1.8.0-openjdk-devel
```
正常にインストールできているか確認します。
しっかり導入できていれば、以下のコマンドを入力すると

```
$ java -version
```
↓のように、JDKのバージョンが表示されます。

```
openjdk version "1.8.0_262"
OpenJDK Runtime Environment (build 1.8.0_262-b10)
OpenJDK 64-Bit Server VM (build 25.262-b10, mixed mode)
```

これでJavaのインストールが完了。

##Apacheをインストールする
前述の通り、ApacheとはWebサーバーです。今回はバージョン「2.4.6」をインストールします。
　
（１）インストールする

```
# yum install httpd
```

（２）Apacheを起動する

```
# systemctl start httpd.service
```

※　システム起動時にApacheも自動起動するには、以下のコマンドを入力する。

```
# systemctl enable httpd.service
```
※　なお、Apacheの状態を確認するには以下のコマンド。

```
# systemctl status http.service
```
　
（３）ファイアウォールを設定する
　デフォルトのファイアウォール設定では、Webサーバーへのアクセスが弾かれるようになっているので、80番ポートへのアクセスを許可します。

```
# firewall-cmd --permanent --add-service=http
```

「success」と表示されたら、以下のコマンドでリロードする。

```
# firewalld-cmd --reload
```
※　ファイアウォールの状態を確かめるには

```
$ systemctl status firewalld
```

※　また、どのサービスが許可されてるのか確かめるには

```
# firewall-cmd --list-all
```
これでApacheの導入が完了しました。
この時点で、```http://VPSのIPアドレス/```にアクセスすると、Apacheのテストページ（↓のページです）が表示されるようになります。
![apachetest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673146/419d8e48-7056-0c38-4d0d-f3b2b95e607a.png)

##Tomcatをインストールする
（１）任意のフォルダにTomcatをインストールします。（今回は```/opt```にします）現時点の最新版「9.0.37」をインストールします。（なお、最新版を確認するには```http://tomcat.apache.org/download-90.cgi```を参照してください）

```
$ cd /opt
# wget http://ftp.riken.jp/net/apache/tomcat/tomcat-9/v9.0.37/bin/apache-tomcat-9.0.37.tar.gz
```
（２）ダウンロードした```apache-tomcat9.0.37.tar.gz```はgzip形式で圧縮されてるので、次のコマンドで解凍します。

```
$ tar -xzvf ~/apache-tomcat-9.0.37.tar.gz
```
（３）Tomcatを動作させるための専用ユーザーを追加する。

```
# useradd -s /sbin/nologin tomcat
```

※　このユーザーはtomcat専用で、このユーザーで実際にログインして何かやるということはありません。

（４）```tomcat9.0.37```の所有者を```tomcat```に変更する。

```
$ chown -R tomcat:tomcat /opt/apache-tomcat-9.0.37
```
（５）Tomcatのユニットファイルを作成します。このファイルは、Linuxの```Systemd```というサービスを管理する機能を利用していて、プログラムを自動起動させたりするのに必要になります。
```/etc/systemc/system/tomcat.service```ファイルを、以下の内容で作成します。

```tomcat.service
[Unit]
Description=Apache Tomcat 9
After=network.target

[Service]
User=tomcat
Group=tomcat
Type=oneshot
PIDFile=/opt/apache-tomcat-9.0.37/tomcat.pid
RemainAfterExit=yes

ExecStart=/opt/apache-tomcat-9.0.37/bin/startup.sh
ExecStop=/opt/apache-tomcat-9.0.37/bin/shutdown.sh
ExecReStart=/opt/apache-tomcat-9.0.37/bin/shutdown.sh;/opt/apache-tomcat-9.0.37/bin/startup.sh

[Install]
WantedBy=multi-user.target
```

次に、このファイルの権限を変更します。

```
$ chmod 755 /etc/systemd/system/tomcat.service
```

ここまできたら、以下のコマンドを打ってtomcatを有効にします。

```
$ systemctl enable tomcat
```

（６）ファイアウォールの設定
　Apacheと同様、tomcatについてもファイアウォールの設定を行います。ユーザーがfirewallを適用するサービスを追加するには、xmlファイルを```/etc/firewalld/services```内に設置しなければなりません。というわけで、```/etc/firewalld/services/tomcat.xml```ファイルを以下の内容で作成します。


```tomcat.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Apache Tomcat 9</short>
  <description>Apache Tomcat 9</description>
  <port protocol="tcp" port="8080"/>
</service>
```

その上で、tomcatの通信を許可させるために以下のコマンドを入力します。

```
# firewalld-cmd --add-service=tomcat --zone=public --permanent
# firewall-cmd --reload
```

※　Apacheの時にも紹介しましたが、以下のコマンドで許可されているサービスを確認できます。

```
# firewall-cmd --list-services --zone=public --permanent
```

ここに「tomcat」の表示があればOKです。

これでTomcatの導入も完了。　
```http://VPSのIPアドレス:8080```でtomcatのテストページが表示されるようになります。
![tomcat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673146/a27ef129-fffe-407e-4278-7f1b802adf53.png)

#５．ApacheとTomcatを連携させる
##Tomcat側の設定
```opt/apache-tomcat9.0.37/conf/server.xml``` を以下の様に修正します。

　**〇 8080番ポートの設定をコメントアウト、8009番ポートの設定のコメントアウトを解除する。**
　**〇 8009番ポートの設定を編集する。**

実際のコードはこちらになります。
　
＜修正前＞

```server.xml
<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

<!--
<Connector protocol="AJP/1.3"
               address="::1"
               port="8009"
               redirectPort="8443" />
-->
```

＜修正後＞

```server.xml
<!--
<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
-->

<Connector protocol="AJP/1.3"
               address="0.0.0.0"
               port="8009"
               secretRequired="false"
               redirectPort="8443" />
```

**※備考１**　「address」欄を「::1」から「0.0.0.0」に変更する理由
　「::1」というのはIPv6のアドレスで、IPv6をサポートしていないサーバーだと、この部分が原因でエラーになってしまう。（ちなみに、「0.0.0.0」はすべてのホストからのアクセスを許可するという意味になります）
　
**※備考２**　「secretRequired="false"」を追記する理由
　これが最初よくわからなかったですが、答えはTomcatのchangelogに書いてありました。

>Rename the requiredSecret attribute of the AJP/1.3 Connector to secret and add a new attribute secretRequired that defaults to true. **When secretRequired is true the AJP/1.3 Connector will not start unless the secret attribute is configured to a non-null, non-zero length String.** (markt)

[Apache Tomcat 9 (9.0.38) - Changelog](http://tomcat.apache.org/tomcat-9.0-doc/changelog.html#Tomcat_9.0.31_(markt))
　
太字にしている箇所は「secretが設定されていない場合、secretRequiredがtrueだとAJPコネクターは動作しません」といった意味になります。つまり、secret（何らかのパスワード）を設定していない場合、「secretRequired="false"」を設定しないとエラーになります。

#Apache側の設定
　Apache側では、TomcatへのProxyPassを設定します。
```/etc/httpd/conf/httpd.conf```ファイル内に、以下のような記述があります。

```
# Load config files in the "/etc/httpd/conf.d" directory, if any.
IncludeOptional conf.d/*.conf
```
「conf.dディレクトリ内のconfファイルであれば読み込みますよ」という感じのことを言っています。よって、```etc/httpd/conf.d/proxy-ajp.conf```ファイル（ファイル名は```.conf```形式なら任意でOK）を以下の内容で作成し、Proxypassを設定します。

```proxy-ajp.conf
<Location /examples/>
  ProxyPass ajp://127.0.0.1:8009/examples/
</Location>
```

これで、```http://IPアドレス/examples```でTomcatのexamplesページが表示されるようになるはずです。
#６．参考
[Apache Tomcat 9 を CentOS 7 にインストールする手順](https://weblabo.oscasierra.net/installing-tomcat9-centos7-1/)
[Apache httpd と Tomcat を連携させる方法](https://weblabo.oscasierra.net/tomcat-mod-proxy-ajp/)
[Linux(CentOS)にApacheとTomcatをインストールしてJavaアプリをデプロイするまで](https://qiita.com/taumax/items/11a3e67c265b6ba71838)
[8080番ポートの停止とAJP/1.3プロトコルの確認](https://www.adminweb.jp/apache/tomcat/index2.html
)