Spring BootアプリをAWSにデプロイする【後編】

## はじめに
Spring Bootで作成したCRUDアプリケーションをAWSにデプロイし、更にさくらレンタルサーバーで追加したサブドメインからHTTPS通信でアクセスできるようにする手順についてまとめます。

前編では、AWS環境の構築まで行いました。
- VPCの構築
- Webサーバーの構築
- DBサーバーの構築

https://qiita.com/ioaio/items/842dd02ce04d1778bf84

後編では、大きく以下2点についてまとめます。
- Spring Bootアプリケーションのデプロイ方法
- さくらのサブドメインからサイトへHTTPS通信でアクセスできるようにする方法

## 前提（この記事では触れない内容）
- AWSのアカウント登録
- さくらのドメイン取得
- Spring Bootアプリケーションの作成

## 構成図
今回構築する環境のイメージです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917178/be58041b-63b7-ab98-975c-d69bd6d2f94c.png)

## Spring Bootアプリケーションのデプロイ方法

作成したSpring BootアプリケーションをAWS上に構築したWebサーバーへデプロイします。

ここでは、以下の6つの作業を実施します。

- WebサーバーにJavaをインストール
- application.propaties の設定変更
- JARファイルの作成
- リバースプロキシの設定
- jarファイルの実行
- Springアプリケーションのサービス化

### 1. WebサーバーにJavaをインストール

WebサーバーにSSHログイン後、以下のコマンドを実行しJavaをインストールします。今回は、作成済みのSpring Bootアプリケーションに合わせて、Java17をインストールします。
```linux
$ sudo yum update -y
$ sudo yum search amazon-corretto
$ sudo yum install -y java-17-amazon-corretto.x86_64
```

以下のコマンドを実行し、Javaのバージョンが正しく表示されればインストール成功です。
```linux
$ java --version
```

### 2. application.propaties の設定変更

Spring Boot の `application.properties` ファイルは、アプリケーションの設定情報を外部化し、さまざまな構成オプションを提供するためのプロパティファイルです。

主な機能と用途として、以下3点が挙げられます。

- **アプリケーションの構成**：データベースの接続設定、サーバーポート、ログの設定など、アプリケーションのさまざまな構成オプションを指定する

- **プロファイルごとの設定**：開発環境や本番環境など、異なる設定を持つために、application-{profile}.propertiesという形式でプロファイルごとの設定ファイルを作成可能。例えば、application-dev.propertiesは開発環境用の設定を提供する

- **プロパティのオーバーライド**：同じプロパティがコマンドライン引数や環境変数で指定された場合、それらが優先される。これにより、異なる環境での設定を柔軟に管理可能

今回は、開発環境用と本番環境用で `application.propaties` を分けていきます。

**① application.properties の編集**
`spring.profiles.active` には、デフォルトで使用する `properties` ファイルを指定します。今回は、後述する `application-dev.properties` をデフォルトとする為、`dev` を指定します。 

```properties:application.properties
# Specify which properties file to use by default 
spring.application.name=vue-spring-syain
spring.profiles.active=dev
```

**② application-dev.properties の作成と編集**
開発環境用のプロパティファイルです。

```properties:application-dev.properties
## configuration file for development environment
spring.datasource.url=jdbc:mysql://localhost:3306/training
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update

spring.jpa.open-in-view=false

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate.validator=DEBUG

server.error.whitelabel.enabled=true
```

**③ aapplication-production.properties の作成と編集**
本番環境用のプロパティファイルです。
データーベースの接続設定の箇所を本番環境用に変更しています。今回は先ず動きを確認する為、プロパティに値を直接設定しています。
後程サービス化の際に、ここのプロパティを環境変数で指定するように変更します。

```properties:application-production.properties
## configuration file for production environment
spring.datasource.url=jdbc:mysql://サーバーのIPアドレス:3306/データベース名 
spring.datasource.username=DBのユーザー名
spring.datasource.password=DBのパスワード
spring.jpa.hibernate.ddl-auto=update

spring.jpa.open-in-view=false

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate.validator=DEBUG

server.error.whitelabel.enabled=true
```

### 3. JARファイルの作成
今回はSpring Tool Suite4で、Mavenを利用しているSpring BootプロジェクトのJARファイルを作成します。

`プロジェクト上で右クリック > [実行] > [Maven ビルド]` から [構成の編集] 画面を開きます。[ゴール] に「package」と入力し、ビルドを実行します。
ビルドが完了すると、`[プロジェクトフォルダ] > [target]` に「XXX.jar」ファイルが作成さます。 

 作成した JARファイルをWEBサーバーの `/var/www/html/` ディレクトリに配置します。Spring BootのHTTPポートはデフォルトでは `8080`ポートになっています。その為、セキュリティグループのインバウンドのルールに、Apacheと同様の手順で **「タイプ：カスタムTCP、ポート範囲：8080、ソース：Anywhere IPv4(0.0.0.0/0)」** の設定を追加後に、JARファイルを実行してあげることで、ブラウザから `http://<パブリックIPアドレス>:8080` で作成したSpring Bootアプリケーションへアクセスできるようになります。

 しかし、これだと毎回ポート番号を指定してあげないといけないので面倒です。そこで、Apacheの設定を更新して、**ポート80で受けたリクエストをSpring Bootアプリケーション（ポート8080）に転送** するよう設定していきます。

:::note warn
SpringBootは、Tomcatが内包されているJARファイルを起動するだけでWebアプリとして動作させることが可能です。

実際の運用（より大規模なシステムや特定の運用要件がある場合）では、組み込みTomcatは使わずに、外部のTomcatサーバーにWARファイルをデプロイすることもあります。
:::

### 4. リバースプロキシの設定
前述した通り、Apacheの設定を更新して、**ポート80で受けたリクエストをSpring Bootアプリケーション（ポート8080）に転送** するよう **リバースプロキシ** の設定を行っていきます。

`/etc/httpd/conf/httpd.conf` ファイルを以下のように編集していきます。

```conf:httpd.conf
<VirtualHost *:80>
    DocumentRoot /var/www/html

    # Reserve Proxy Configuration
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/

    ErrorLog /var/log/httpd/error.log
    CustomLog /var/log/httpd/access.log combined
</VirtualHost>
```

Apacheの設定ファイルに問題がないか確認します。正常な場合は `Syntax OK` が、エラーがある場合は、どの部分にエラーがあるかメッセージが表示されます。
```linux
$ sudo service httpd configtest
```

設定を反映する為に、Apacheを再起動します。
```linux
$ sudo systemctl restart httpd
$ sudo systemctl status httpd
```

### 5. jarファイルの実行

以下のように本番環境用のプロパティファイルを指定し、JARファイルを実行します。
```
java -jar <JARファイル名> --spring.profiles.active=production
```

ブラウザで `http://<パブリックIPアドレス>` にアクセスすると、Spring Bootアプリケーションが表示されることを確認できるはずです。

### 6. Springアプリケーションのサービス化

JARファイルを実行することで、Spring Bootアプリケーションへアクセスできるようになりました。しかし、今の状態だと接続を切断するとアプリケーションも落ちてしまいます。そこで、SpringBootアプリケーションをサービス化 ( デーモン化 ) して常駐させられるように設定していきます。

Spring Bootアプリケーションをデーモン化するには、Linux の `systemd` を利用してアプリケーションをサービスとして登録する方法が一般的です。次の手順を実施します。

#### ① JARファイルの設置場所を確認

`/opt/<app-name>` にJARファイルを配置します。
```linux
$ sudo mkdir -p /opt/my-spring-app
$ sudo mv /var/www/html/<your-app>.jar /opt/my-spring-app/
```

#### ② aapplication-production.properties の編集と再ビルド

本番環境用のプロパティファイルを編集します。
データベースの接続設定のプロパティに値を直接設定していた部分を、環境変数で指定するように変更します。

```properties:aapplication-production.properties
## configuration file for production environment
spring.datasource.url=${DB_URL}                  # ここを変更
spring.datasource.username=${DB_USERNAME}        # ここを変更
spring.datasource.password=${DB_PASSWORD}        # ここを変更
spring.jpa.hibernate.ddl-auto=update

spring.jpa.open-in-view=false

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate.validator=DEBUG

server.error.whitelabel.enabled=true
```

プロパティファイルの編集が完了したら、プロジェクトを再ビルドし、上記で作成した `/opt/my-spring-app` ディレクトリ配下のJARファイルを上書きします。

#### ③ systemd用のサービスファイルを作成

以下のコマンドでサービス定義ファイルを作成します。
```linux
$ sudo vim /etc/systemd/system/my-spring-app.service
```

以下の内容をファイルに記述します。
```ini:my-spring-app.service
[Unit]
Description=Spring Boot Application
After=network.target

[Service]
User=ec2-user  # 実行ユーザー（必要に応じて変更）
WorkingDirectory=/opt/my-spring-app
ExecStart=/usr/bin/java -jar /opt/my-spring-app/<your-app>.jar  # jarファイルのパスに合わせて変更
Restart=always
SuccessExitStatus=143

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

#### ④ サービスの登録と起動

作成したサービスファイルの権限を正しく設定します。
```linux
$ sudo chmod 644 /etc/systemd/system/my-spring-app.service
```

以下のコマンドでサービスを登録し、起動します。
```linux
# サービスのリロード
$ sudo systemctl daemon-reload

# サービスの起動
$ sudo systemctl start my-spring-app

# サービスを自動起動に登録
$ sudo systemctl enable my-spring-app
```

サービスが正常に動作しているか確認します。
```linux
$ sudo systemctl status my-spring-app
```

これで、SSH接続を切断してもアプリケーションが常時動作するようになります。

#### ⑤ 補足

**ログの確認：**
Spring Bootアプリケーションのログを確認するには、`journalctl` を使用します。
```linux
$ sudo journalctl -u my-spring-app -f
```

**アプリケーションの停止：**
```linux
$ sudo systemctl stop my-spring-app
```

**アプリケーションの再起動：**
```linux
$ sudo systemctl restart my-spring-app
```

**別のJARに差し換えたい場合：** 
新しいJARファイルを配置して、以下を実行します。
```linux
$ sudo systemctl restart my-spring-app
```

## さくらのVPSで設定したサブドメインをEC2に紐付ける

次に、EC2のパブリックDNSを、さくらのVPSで設定済みのサブドメインに変更する為の、DNS設定を行います。

### 1. さくらのVPSでDNSレコードを設定
さくらのDNS管理画面で、サブドメイン（例: app.example.com）をEC2のIPアドレスに紐付けます。以下の手順で設定します。

**① さくらのDNS管理画面にログイン**
さくらのレンタルサーバーにアクセスし、DNSゾーンの設定画面に進みます。

**② サブドメインのAレコードを追加**
以下の情報を入力して、Aレコードを追加し、設定を保存します。

ホスト名: app（サブドメイン部分）
種別: A
値: EC2のパブリックIPアドレス

:::note warn
反映には数分から最大48時間程度かかる場合がありますが、通常は数時間以内に有効になります。
:::

### 2. Apacheの設定を編集
`/etc/httpd/conf/httpd.conf` ファイルに設定した独自ドメインの情報を追加します。

```conf:httpd.conf
<VirtualHost *:80>
    ServerName <サブドメイン>    // ここを追加
    DocumentRoot /var/www/html

    # Reserve Proxy Configuration
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/

    ErrorLog /var/log/httpd/error.log
    CustomLog /var/log/httpd/access.log combined
</VirtualHost>
```

Apacheを再起動し、設定を反映します。
```linux
$ sudo systemctl restart httpd
```

ブラウザでサブドメイン（例: `http://app.example.com`）にアクセスすると、Spring Bootアプリケーションが表示されるようになります。

## HTTPSの設定
サブドメインをSSL化し、`https://<サブドメイン>` でアクセスできるようにします。

### 1. EC2インスタンスのセキュリティグループを確認

`AWSコンソール → EC2 → セキュリティグループ` から対象のセキュリティグループを選択し、インバウンドルールにポート443のルールを追加します。

**ルールの追加：**
- タイプ：HTTPS
- プロトコル：TCP
- ポート範囲：443
- 送信元：0.0.0.0/0（すべてのIPアドレスを許可）

### 2. HTTPS 用の VirtualHost を設定

`/etc/httpd/conf/httpd.conf` を編集し、HTTPS用の `VirtualHost` を設定します。
```linux
$ sudo vim /etc/httpd/conf/httpd.conf
```

**HTTP（80ポート）** でアクセスされた場合に **HTTPS（443ポート）** へリダイレクトするように設定を変更します。

```conf:httpd.conf
<VirtualHost *:80>
    ServerName <サブドメイン>
    Redirect permanent / https://<サブドメイン>/
</VirtualHost>

<VirtualHost *:443>
    ServerName <サブドメイン>

    # Reserve Proxy Configuration
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/

    # Logs
    ErrorLog /var/log/httpd/error.log
    CustomLog /var/log/httpd/access.log combined
</VirtualHost>
```

ファイルを保存したら Apacheを再起動し、設定を反映します。
```linux
$ sudo systemctl restart httpd
```

### 3. SSL証明書の準備（Let's Encrypt）

以下の手順で Let's Encryptを使用し、SSL証明書を取得します。

**① Certbotをインストール：**
```linux
$ sudo yum install certbot python3-certbot-apache
```

**② SSL証明書を取得：**
```linux
$ sudo certbot --apache -d app.example.com
```

**③ SSL証明書を自動更新できるように設定（SSL証明書の有効期限は３カ月）：**
```linux
$ sudo systemctl enable certbot-renew.timer
```

CertbotはSSL証明書と秘密鍵を取得し、自動的にApacheの設定を更新し、HTTPSを有効化します。（Certbotにより、`httpd.conf` に `SSLCertificateFile` と`SSLCertificateKeyFile` のファイルパスなど、SSLの設定が自動生成されます）

ブラウザで `https://<サブドメイン>` にアクセスすると、Spring Bootアプリケーション画面が正しく表示されることを確認できます。また、HTTPでアクセスしても、自動的にHTTPSにリダイレクトされるようになります。

## 最後に
後編では、構築したAWS環境にSpring Bootアプリケーションをデプロイする方法と、さくらのサブドメインからサイトへHTTPS通信でアクセスできるようにする方法についてまとめした。
環境構築の一助となれば幸いです。

前編では、AWS環境の構築（WebサーバーとDBサーバーの構築と各種設定）についてまとめています。

https://qiita.com/ioaio/items/842dd02ce04d1778bf84