EC2(Amazon Linux 2023)  Nginx1.26 MySQL8.4 PHP8.3 Laravelデプロイ

## 目的
今回は、AWSを使ってEC2インスタンスにLaravelアプリをデプロイしていきます。

![スクリーンショット 2024-11-28 10.33.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821993/d768c5fc-ff98-a13e-d5be-27aea426615e.png)

AMIはAmazon Linux 2023を使っています。
構築自体は済んでいるので、ssh接続して作業していきます。
各種詳細は末尾の参考ドキュメントを参照願います。

:::note info
EC2インスタンスにインストールするもの
* nginx/1.26.2
* PHP 8.3.10 (cli) (built: Jul 30 2024 13:44:37) (NTS gcc x86_64)
* Ver 8.4.3 for Linux on x86_64 (MySQL Community Server - GPL)
* Git
:::

## EC2インスタンスへのインストール

### Nginx1.26
```bash:ec2-user@AL2023
# パッケージを更新
sudo dnf upgrade

# Nginxをインストールして、バージョンを確認
sudo dnf install nginx
nginx -v

# 起動
sudo systemctl start nginx

# 起動状態の確認
systemctl status nginx

# 自動起動の設定
sudo systemctl enable nginx
```

#### Nginxの初期設定
Nginxで受けたHTTPリクエストをLaravelに伝えるための設定を行なっていきます。

:::note info
ポイント
Laravelのルーティングは、すべてのリクエストを`index.php`で受け取ります。
また、受け取る際、NginxはFastCGIサーバ（php-fpm）にリクエストを転送します。
:::

`sudo vim /etc/nginx/nginx.conf`

```diff_php:/etc/nginx/nginx.conf
server {
    listen       80;
    listen       [::]:80;
    server_name  _;
-   root         /usr/share/nginx/html;
+   # Laravelのpublic/index.phpが応答するよう設定
+   root         /var/www/[後にGitHubからクローンするプロジェクト名]/public;
+
+   # クリックジャッキング対策（HTTPレスポンスの際、他のサイトではフレーム内への埋め込みを許可しない）
+   add_header X-Frame-Options "SAMEORIGIN";
+   # ブラウザがサーバ指定のMIMEタイプを厳密に守るよう指定（スニッフィングの禁止）
+   add_header X-Content-Type-Options "nosniff";
+   
+   # スラッシュで終わっているリクエストが来た際、処理するファイルを定義する
+   index index.php;
+   charset utf-8;
+   
+   # / 以下のリクエスト全てを判定する（例：/about/indexなど）
+   location / {
+       # 該当するファイル、ディレクトリが静的資材として存在しなければ、index.phpにリクエストを転送
+       try_files $uri $uri/ /index.php?$query_string;
+   }
+   
+   location = /favicon.ico { access_log off; log_not_found off; }
+   location = /robots.txt  { access_log off; log_not_found off; }
+   
-   error_page 404 /404.html;
+   error_page 404 /index.php;
-   location = /404.html {
-   }
-   error_page 500 502 503 504 /50x.html;
-   location = /50x.html {
-   }
+
+   location ~ \.php$ {
+       # php-fpmのソケットファイルの場所を定義する（環境によって異なるため後述します）
+       fastcgi_pass unix:/var/run/php-fpm/www.sock;
+       fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
+       include fastcgi_params;
+       fastcgi_hide_header X-Powered-By;
+    }
+
+    location ~ /\.(?!well-known).* {
+        deny all;
+    }
}    
```

:::note info
一口メモ
php-fpmのソケットファイルの場所は、環境によって異なります。
Ubuntuなどでは`/var/run/php/`となりますが、Amazon Linuxでは`/var/run/php-fpm/`となります。
以下のコマンドでソケットファイルの場所を確認できますので、ご自身の環境に合った定義を行います。
`sudo cat /etc/php-fpm.d/www.conf | grep listen`
:::

```bash:ec2-user@AL2023
# 設定が正しいかテストし、反映する
sudo nginx -t
sudo systemctl reload nginx
```

### PHP8.3
```bash:ec2-user@AL2023
# インストールできるパッケージ名を検索
dnf search php

# PHP8.3をインストールして、バージョンを確認
sudo dnf install php8.3.x86_64
php -v
php-fpm -v
```
#### PHPの初期設定
NginxからUnixソケット通信の送受信設定を行なっていきます。

`sudo vim /etc/php-fpm.d/www.conf`
```diff_ruby:/etc/php-fpm.d/www.conf
- user = apache
+ user = nginx

- group = apache
+ group = nginx

+ ;ソケットファイルのパーミッションを設定
+ listen.owner = nginx
+ listen.group = nginx
+ listen.mode = 0660
```

```bash:ec2-user@AL2023
# 設定を反映
sudo systemctl restart php-fpm.service
```


### MySQL8.4
```bash:ec2-user@AL2023
# MySQL公式リポジトリのインストール
sudo dnf install https://dev.mysql.com/get/mysql84-community-release-el9-1.noarch.rpm

# リポジトリが正常に追加されたことを確認
dnf repolist enabled | grep mysql.*-community

# MySQLサーバとクライアントをインストールして、バージョンを確認
sudo dnf install mysql-community-server
mysqld --version

# MySQLドライバのインストール
sudo dnf install php-pdo php-mysqlnd
sudo systemctl restart php-fpm

# MySQLサーバの起動
sudo systemctl start mysqld

# 起動状態の確認
systemctl status mysqld
```
#### MySQLの初期設定
MySQLサーバ初回起動時にスーパーユーザ`root@localhost`が作成されるため、初期パスワードを変更します。
```bash:ec2-user@AL2023
# 設定された初期パスワードを確認
sudo grep 'temporary password' /var/log/mysqld.log

# MySQLサーバに接続(上記で確認した初期パスワードを入れます)
mysql -uroot -p

# 初期パスワードを変更
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '[変更後パスワード]';
```

:::note warn
パスワード設定時にバリデーションが効いています！
* 8文字以上であること
* 大文字、小文字、数字、記号が1文字以上含まれていること
:::

#### データベース作成

```bash:ec2-user@AL2023
mysql -u root -p
mysql> create database MyLaravelDB;
mysql> show databases;
```

### GitHubからLaravelアプリをClone
サーバの設定が済んだので、LaravelアプリをCloneしていきます。

```bash:ec2-user@AL2023
sudo dnf install git

# SSHキーを生成する
ssh-keygen -t ed25519 -C "your_email@example.com"

# ssh-agentを開始する
eval "$(ssh-agent -s)"

# SSHキーをssh-agentに追加する
ssh-add ~/.ssh/id_ed25519

# SSHキーをクリップボードにコピーする
cat ~/.ssh/id_ed25519.pub
```
#### GitHubにSSHキーを登録
1. GitHubにログインし、自分のプロフィール画像をクリック > Settingsを開く
1. 左のツリーから SSH and GPG keysを開く
1. New SSH keyボタンをクリック
1. Titleを入力 > Authentication Keyを選択 > Keyにコピーした公開鍵を貼り付ける
1. Add SSH keyボタンをクリック

#### git clone
```bash:ec2-user@AL2023
# SSH接続を確認
ssh -T git@github.com
# (成功)Hi username! You've successfully authenticated, but GitHub does not provide shell access.

# ディレクトリの所有者を変更してからクローンする（/var/www/はrootが所有者になっているため）
# sudoを付ければ解決かと思ったが、実行するユーザがrootに切り替わるため、SSHキーが/root/.sshに未保存のため失敗する
cd /var/www/
sudo chown -R ec2-user:ec2-user /var/www
git clone git@github.com:*********/*********.git

# Nginxに、storageとbootstrap/cacheディレクトリに書き込み権限を付与
sudo chown -R nginx:nginx /var/www/[プロジェクト名]/storage /var/www/[プロジェクト名]/bootstrap/cache
sudo chmod -R 775 /var/www/[プロジェクト名]/storage /var/www/[プロジェクト名]/bootstrap/cache
```

#### .envファイルを作成してDB設定を行う
```bash:ec2-user@AL2023
cd [プロジェクトディレクトリ]
# .env.exampleをコピーして.envを作成
cp .env.example .env
vim .env
```

```diff_php:.env
- APP_URL=http://localhost
+ APP_URL=http://[EC2インスタンスのオープンIPアドレス]
- DB_CONNECTION=sqlite
+ DB_CONNECTION=mysql
+ DB_HOST=127.0.0.1
+ DB_PORT=3306
+ DB_DATABASE=[MySQLで作成のDB]
+ DB_USERNAME=root
+ DB_PASSWORD=[rootのパスワード]
```

#### Composerのインストール
Composerのインストールは[Composerのインストール](https://getcomposer.org/download/)を参照ください。

```bash:ec2-user@AL2023
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === 'dac665fdc30fdd8ec78b38b9800061b4150413ff2e3b6f88543c636f7cd84f6db9189d43a81e5503cda447da73c7e5b6') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

# パスを通す
sudo mv composer.phar /usr/local/bin/composer

# Composerで依存関係をインストールする
composer install
```

#### APP_KEYの自動生成とDBマイグレーション
```bash:ec2-user@AL2023
php artisan key:generate
php artisan migrate
```

## 最後に
ブラウザで、EC2インスタンスのオープンIPアドレスに接続して、アプリが動作する確認を行います。
`http://[EC2インスタンスのオープンIPアドレス]`

:::note alert
エラーが出たらキャッシュをクリアしてみましょう
`cd /var/www/[プロジェクト名]`
`php artisan config:clear`
`php artisan cache:clear`
`php artisan view:clear`
:::

## 参考ドキュメント
* [パッケージ管理ツール DNF](https://docs.aws.amazon.com/ja_jp/linux/al2023/ug/package-management.html)
* [Laravelを使用するためのNginx設定](https://laravel.com/docs/11.x/deployment#nginx)
* [NginxDocument](https://nginx.org/en/docs/)
* [クリックジャッキングの基礎知識](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%82%B8%E3%83%A3%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0)
* [php-fpmの設定](https://www.php.net/manual/ja/install.fpm.configuration.php)
* [LinuxにMySQLをインストールする](https://dev.mysql.com/doc/refman/9.1/en/linux-installation-yum-repo.html)
* [SSHキーの生成](https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent?platform=linux)
* [SSHキーのGitHubへの登録](https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account)
* [Composerのインストール](https://getcomposer.org/download/)