Laravelの成果物をXServerに継続的にデプロイする

# はじめに
XServerではPHPが動くのでLaravelのデプロイが可能です。
実際にデプロイを行うために行った作業を中心に記録しています。

事前に一度だけ行う手順と、継続的にデプロイを行うためのスクリプトに別れています。

1. 一度だけ
 1.1. XServerでドキュメントルートの設定を行う
 1.1. XServerにデータベースを作成する
 1.1. DBの接続情報を .env.develop に記載する
1. 転送する

# 前提

今回の想定環境です。

|定数名 | |
|---|---|
| example.net | 取得しているドメイン |
| app.example.net | アプリケーション用に用意したサブドメイン |
| examplenet | XServer ユーザー名 |
| 環境名 | develop |

# 最初に必要なこと

1. ドキュメントルートの設定
1. DB作成（と設定の記載）
1. SSH設定
1. XServer上でのnode環境構築

## XServer上での設定

サブドメインの設定を行っておきます。

![Screenshot 2023-08-30 at 15.35.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/d94da37a-c51e-ec6a-01fe-e02e8b4f5006.png)

今回のドキュメントルートは

` /home/examplenet/example.net/public_html/app.example.net/ ` となります。


## ドキュメントルートの設定

Laravel（や他のフレームワーク）ではアプリケーション内のディレクトリへのドキュメントルートの設定が必要です。[^docroot]
自分でWebサーバの設定を行うのであれば自由に設定できますが、レンタルサーバの場合にはある程度階層構造が決められており、ドキュメントルートにすることができません。
そこでLaravelの公開用ディレクトリになる `public` をシンボリックリンクを使ってドキュメントルートにします。

XServerではホームディレクトリが `/home/ユーザー名` となっておりその下に主となるドメイン名のディレクトリがあります。XServerでは少し複雑ですが、`public_html` の中にサブドメイン名のディレクトリがあります。
今回は主となるドメイン名のディレクトリにアプリケーションを配置し、公開用ディレクトリを公開ディレクトリ名へのシンボリックリンクとします。


```
- /home/examplenet/example.net/
  |- public_html/app.example.net     # 公開ディレクトリ
  |- app/                            # Laravelアプリケーションを置くディレクトリ
```

SSHでログインしてシンボリックリンクの設定を行います。

```bash
mkdir -p ~/example.net/app/public
ln -s ~/example.net.app/public ~/example.net/public_html/app.examle.net
```

確認を行います。

```bash
echo 'Hello symlink' > ~/example.net/app/public/hello.html


# シンボリックリンク側で中身が見えるか確認する
cat ~/example.net/public_html/app.example.net/hello.html

Hello symlink


# curlでWebサーバ越しに見えるか確認しておく。
curl -s http://example.net/hello.html

Hello symlink
```

[^docroot]: 厳密には必要ではないこともありますが、一般的な設定ではアプリケーションの特定ディレクトリをドキュメントルートとします。アプリケーションディレクトリ全体が公開されることも好ましくありません。

## DBの作成

サーバパネルからDBを作成します。

![Screenshot 2023-08-28 at 15.11.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/4bc4d412-ccaa-1553-4047-ce3a2cdc264a.png)

MySQLユーザの追加とデータベーススキーマへの権限追加も行っておきます。


## DB設定の記載

デプロイ先用に `.env.develop` というファイルでDB関連の設定を記載しておきます。

```env:.env.develop
DB_CONNECTION=mysql
DB_HOST=mysql_example.xserver.jp
DB_PORT=3306
DB_DATABASE=examplenet_app
DB_USERNAME=examplenet_app
DB_PASSWORD=example_password
```


## SSH設定
デプロイ用のSSH設定を行います。今回はXServer上で作成しますが手元で作成して公開鍵を送っても良いです。

自動でデプロイできるよう、キーフレーズ無しのキーペアを作成します。

```bash
cd .ssh
ssh-keygen -f exampleapp_deploy
cat exampleapp_deploy.pub >> authorized_keys
```

秘密鍵は手元に `secrets/develop.key` という名前で保管しておきます。


## XServer上でのnode環境構築

今回はLaravelでInertia.js Vite.js という仕組みを使ってビルドするため、XServer上で `npm` が実行できるようにします。

手元（macOS）でビルドをして転送すれば動くかなとも思ったのですがうまく動きませんでした。

下記の方のページが大変参考になりました。（ほぼ同じことをしました）

https://chigusa-web.com/blog/xserver-laravel/

### 抜粋

```bash
curl -L git.io/nodebrew | perl - setup

# 現在のstableのv20だとXServerでは動かなかったので v16 系最新を使う
nodebrew install v16 && nodebrew use v16

# パスを通す
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

# 確認
node -v
# v16.20.2
```

以上で初期設定は完了です。

# デプロイの準備

改めてデプロイに必要な事柄をまとめます。

| 名前 | 今回の想定 |
|---|---|
| SSHユーザー名（Xserver契約名） | examplenet |
| SSHホスト名 | examplenet.xsrv.jp |
| SSH接続用キーの場所 | secrets/develop.key |
| SSH接続用ポート番号 | 10022 (XServer標準) |
| デプロイ先パス | /home/examplenet/example.net/app |


デプロイの流れは下記の通りです。

1. rsyncで必要なファイルの転送
1. .env ファイルの置き換え
1. composerの実行とnpm系のビルド

これらを変数にしておき、デプロイ用のスクリプトを書きます。

```bash:bin/deploy_develop.sh
#!/usr/bin/env bash
# 開発環境に対してデプロイを行います。

set -xe
cd -- "$(dirname "${BASH_SOURCE}")"

SSH_USER='examplenet'
SSH_HOST='examplenet.xsrv.jp'
SSH_KEY='../secrets/develop.key'
SSH_PORT=10022
DEPLOY_PATH='/home/examplenet/example.net/app'
chmod 0600 ${SSH_KEY}

# storage/app/public は除外
rsync -av \
  --checksum \
  --delete \
  --rsh "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ${SSH_KEY} -p ${SSH_PORT}" \
  --exclude ".idea" \
  --exclude ".vscode" \
  --exclude "vendor" \
  --exclude "node_modules" \
  --exclude "storage/app/public" \
  --exclude "storage/debugbar" \
  --exclude "storage/framework" \
  --exclude "storage/logs" \
  ../app/ \
  ${SSH_USER}@${SSH_HOST}:${TARGET_DIR}


# .envファイルの置き換え
ssh \
    -o UserKnownHostsFile=/dev/null \
    -o StrictHostKeyChecking="no" \
    -i ${SSH_KEY} \
    -p ${SSH_PORT} \
    ${SSH_USER}@${SSH_HOST} \
    "cd $DEPLOY_PATH && mv .env.develop .env"

# Setup Inertia (vite)
ssh \
    -o UserKnownHostsFile=/dev/null \
    -o StrictHostKeyChecking="no" \
    -i ${SSH_KEY} \
    -p ${SSH_PORT} \
    ${SSH_USER}@${SSH_HOST} \
    "cd $DEPLOY_PATH && composer require && npm i && npm run build"
```

上を実行すると転送されビルドされます。