XserverにLaravel9をデプロイした手順

Xserver（スタンダードプラン）にLaravel9をデプロイした際の手順を備忘録として残しておきます。
今回扱うLaravelのバージョンは9.36.4となります。

# SSH接続
### 1.XserverのSSH設定を有効にする
サーバーパネルのアカウントから「SSH設定」をクリックします。
![スクリーンショット 2023-03-11 114642.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/0c254f5c-d16f-da86-9743-8b3e3801ed7f.png)
「SSH設定」で「ONにする」を選択します。
![スクリーンショット 2023-03-11 114759.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/ec44375c-3f39-45c9-2893-c849c86363d3.png)
### 2.公開認証用の鍵ペアを生成する
「公開認証用鍵ペアの生成」タブを選択し、パスフレーズ（SSH接続する際に必要なパスワード）を入力して、確認画面へ進むボタンをクリックします。
![スクリーンショット 2023-03-11 115120.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/59b37fbd-e2c0-a965-fc6b-46cbdba1fe06.png)
確認画面から「生成する」ボタンをクリックすると「サーバーID.key」という名前のファイルがダウンロードされます。
### 3.ダウンロードしたファイルを移動させる
CLIから以下のコマンドでダウンロード下ファイルを移動させます。
~~~
mv ~/Downloads/サーバーID.key ~/.ssh/
~~~
.sshフォルダがない場合は以下のコマンドで作成してから先ほどのコマンドを実行してください。
~~~
mkdir ~/.ssh
~~~
### 4.実際にSSHで接続する
接続方法はCLIで下記を実行します
~~~
ssh -l サーバーID -i ~/.ssh/サーバーID.key サーバーID.xsrv.jp -p 10022
~~~
# PHPのバージョンアップ
Laravel9.xはPHPのバージョンが8.0以上必要なので変更する必要があります。
### 1.サーバーパネルから変更
まずは、サーバーパネルからバージョンを変更していきます。
サーバーパネルの「PHP」から「PHP Ver.切替」をクリックします。
![スクリーンショット 2023-03-11 121515.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/fc2397f1-844b-e435-b71b-f6e93cfd8546.png)
次にLaravelを使用するドメインを選択します。
![スクリーンショット 2023-03-11 121956.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/60514638-92b4-f8a5-6e84-d65afd06638b.png)
次にPHPのバージョンを選択し、変更ボタンをクリックします。
![スクリーンショット 2023-03-11 122806.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/734becdd-816d-2a2a-c1f7-b3300788bac5.png)
今回は8.0以上で推奨になっていた8.0.25を選択しました。
### 2.CLIから変更
###### 2.1バージョン確認
まずはバージョンを確認します。
~~~
php -v
~~~
これでバージョンが8.0以上でない場合はバージョンを上げる必要があります。
###### 2.2シンボリックリンク作成
XserverではSSH接続するユーザーにはroot権限を付与されないため、ホームディレクトリ以外にファイルを作ることができません。
そのため、ホームディレクトリからパス設定をする必要があります。
まずは「bin」ディレクトリを作成します。
~~~
mkdir $HOME/bin
~~~
次にシンボリックリンクを作成します。
ここではサーバーパネルから選択したのと同じ8.0.25を選択しています。
~~~
ln -s /opt/php-8.0.25/bin/php $HOME/bin/php
~~~
次にパスを通してあげます。
下記を実行して「.bash_profile」を編集します。
~~~
vi ~/.bash_profile
~~~
インサートモードにして、編集します。
~~~ruby:.bash_profile
PATH=$PATH:$HOME/bin
↓ 下記に変更
PATH=$HOME/bin:$PATH
~~~
エスケープして、「:wq」で保存したら下記を実行します。
~~~
source ~/.bash_profile
~~~
最後にもう一度PHPのバージョンを確認します。
~~~
php -v
~~~
これでバージョンが変わっていればOKです。
# Composerのインストール
下記のコマンドを実行してComposerをインストールします。
バージョンによって異なる場合があるため[Composer公式サイト](https://getcomposer.org/download/)から参照するのをオススメします。
~~~
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '55ce33d7678c5a611085589f1f3ddf8b3c52d662cd01d4ba75c0ee0459970c2200a51f492d557530c71c15d8dba01eae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
~~~
インストールするとcompoer.pharと.configディレクトリが作成されるので、composer.pharをcomposerという名前にして.config/composer/vendor/bin/の下に保存します。
~~~
mkdir -p .config/composer/vendor/bin/
mv composer.phar .config/composer/vendor/bin/composer
~~~
.config/composer/vendor/bin/にはパスが通っていないためパスを設定する必要があります。（先ほどのPHPの場合と同様に、composerのパスを追加）
~~~ruby:.bash_profile
PATH=$HOME/bin:$PATH ←PHP
PATH=$HOME/.config/composer/vendor/bin:$PATH ←Composer
~~~
.bash_profileの変更を反映させます。
~~~
source ~/.bash_profile
~~~
最後にバージョン確認をします。
~~~
composer -V
~~~
これでバージョンが確認できればOKです。
# Node.jsのインストール
npmを使用するのに必要なのでインストールをします。

ただし、Node.jsをそのまま入れるとバージョンの管理に手間がかかるため、バージョン管理ツール「nodebrew」を使ってNode.jsをインストールを行います。

### 1.nodebrewのインストール
CLIから下記のコマンドでインストールをします。
~~~
wget git.io/nodebrew
~~~
ダウンロードができたら、セットアップをします。
~~~
perl nodebrew setup
~~~
この際に、下記のエラーが発生しましたが特に問題ありませんでした。
~~~
perl nodebrew setup
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
	LANGUAGE = (unset),
	LC_ALL = (unset),
	LC_CTYPE = "UTF-8",
	LANG = "ja_JP.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
Can't open perl script "nodebrew": No such file or directory
~~~
一応[こちらの記事](https://notfounds.hatenablog.com/entry/2019/08/06/SSH%E3%81%A7%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AB%E7%B9%8B%E3%81%84%E3%81%A7%22perl%3A_warning%3A_Setting_locale_failed_%22%E3%81%8C%E5%87%BA%E3%81%A6%E3%81%8D%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AE)を参考に解決できるみたいです。

https://notfounds.hatenablog.com/entry/2019/08/06/SSH%E3%81%A7%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AB%E7%B9%8B%E3%81%84%E3%81%A7%22perl%3A_warning%3A_Setting_locale_failed_%22%E3%81%8C%E5%87%BA%E3%81%A6%E3%81%8D%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AE

次に、/.bash_profileに下記のコマンドを追記してパスを通します。
~~~
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
~~~
変更した内容を反映させます。
~~~
source ~/.bashrc
~~~
最後にバージョン確認をします。
~~~
nodebrew -v
~~~
バージョンが確認できればOKです。
### 2.Node.jsのインストール
nodebrewを使って、Node.jsのインストールをします。
~~~
nodebrew install-binary latest
~~~
下記のコマンドでインストールしたNode.jsを確認します。
~~~
nodebrew list
~~~
今回インストールしたのは「v19.7.0」だったので、こちらをアクティブにします。
~~~
nodebrew use v19.7.0
~~~
最後にバージョンを確認します。
~~~
node -v
~~~
ここで、私の環境では下記のエラーが発生しました。
~~~
node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by node)
node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by node)
~~~
[こちらのサイト](https://qiita.com/mindwood/items/05ef14d093ca3b713c41#nodejs-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)を参考にバージョンをv17.9.1に変更したら解決できました。

https://qiita.com/mindwood/items/05ef14d093ca3b713c41#nodejs-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB
# Laravelプロジェクトの作成
### 1.git clone
今回は既に作成済みのものなのでGitからcloneしていきます。
まずはホームディレクトリから使用するドメインのディレクトリに移動します。
~~~
cd ドメイン名
~~~
次にgitからcloneします。
~~~
git clone リモートURL
~~~
### 2.シンボリックリンク作成
Xserverの公開ディレクトリであるpublic_htmlに、Laravelの公開ディレクトリであるpublicのシンボリックリンクを作成します。
~~~
ln -s $HOME/サーバーID/ドメイン名/プロジェクト名/sample-project/public $HOME/サーバーID/ドメイン名/public_html
~~~
### 3.htaccessを編集
ドメイン名のURLにアクセスがあったら、先ほど作成したシンボリックリンク「public」フォルダ内を参照するように(すべてのリクエストがプロジェクト名/publicを通して処理されるように)、public_html内の.htaccessを編集します。
~~~
vi ~/ドメイン名/public_html/.htaccess
~~~
から下記を追記します。
~~~ruby:.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)$ public/$1 [QSA,L]
</IfModule>
~~~
# データベースの設定
### 1.データベースの追加
サーバーパネルからデータベースを追加していきます。
データベースの「MySQL設定」をクリックします。
![スクリーンショット 2023-03-11 200342.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/22bbd690-8d38-2477-003c-b9f8ef9eef7b.png)
「MySQL追加」タブからMySQLデータベース名を入力して確認画面へ進み、確認して追加を行います。
![スクリーンショット 2023-03-11 200524.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/8423389a-176c-d3dc-10ca-4d687ddad1b1.png)
### 2.MySQLユーザーの追加
「MySQLユーザー追加」タブからMySQLユーザーIDとパスワードを入力して確認画面ヘ進み、確認して追加を行います。
![スクリーンショット 2023-03-11 200928.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/1f38c06e-a38f-3994-e8b3-013650c6ad31.png)
「MySQL一覧」タブからアクセス未所有ユーザーの追加ボタンをクリックして、先ほど作成したデータベースにユーザーを追加します。
![スクリーンショット 2023-03-11 201304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/8cabd2de-d347-d9f5-8793-68954750baa5.png)
### 3.「.env」ファイルの編集
cloneしたプロジェクトは.envファイルは存在しないので、プロジェクトに移動して.env.exampleからコピーします。
~~~
cd ~/ドメイン名/プロジェクト名
cp .env.example .env
~~~
.envファイルを下記に修正します。
~~~
DB_CONNECTION=mysql 
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=作成したMySQLデータベース名
DB_USERNAME=MySQLユーザ名
DB_PASSWORD=MySQLユーザを作成した時のパスワード
~~~
次に下記のコマンドからmigrationを実行します。
~~~
php artisan migrate
~~~
この際に私の環境では下記のエラーが発生しました。
~~~
SQLSTATE[HY000]: General error: 1298 Unknown or incorrect time zone: 'Asia/Tokyo'
~~~
原因としては、config/database.php内のtimezoneを設定していたからでした。
~~~ruby:database.php
'mysql' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL'),
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'timezone' => 'Asia/Tokyo', ←ここが原因
    'options' => extension_loaded('pdo_mysql') ? array_filter([
    PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],
],
~~~
timezoneを指定している箇所を削除してあげると解決できました。

# Nodeパッケージのインストールとビルド
プロジェクト直下で下記のコマンドを実行し、NPMパッケージをインストールします。
~~~
npm install
~~~
次に、トランスパイルを行います。(JS/CSSをビルド)
今回のLaravel9はViteになるので下記のコマンドを実行します。
~~~
npm run build
~~~
Mixの場合は下記を実行します。
~~~
npm run prod
~~~
実行するとプロジェクト直下のpublicフォルダにjs/cssが出力されます。

# 各種設定
最後に少し設定を行います。
### .envファイルの設定
まずはアプリケーションキーを下記コマンドから生成します。
~~~
php artisan key:generate
~~~
次にAPP_DEBUGをfalseに変更します。
~~~
APP_DEBUG=false
~~~
### Cron設定
Cron設定に少し躓いたのでここに記しておきます。
まず、サーバーパネルのアカウントから「Cron設定」をクリックします。
![スクリーンショット 2023-04-05 153748.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/d17109c4-adb2-8f0b-edc3-0fc377e4b8c8.png)
その次にCron設定追加をクリックします。
![スクリーンショット 2023-04-05 153654.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/e085e55d-e386-a8ca-6e68-4c86d568cea4.png)
分・時間・日・月・曜日に「*」を入力します。
![スクリーンショット 2023-04-05 154043.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127267/4e7a17fc-987f-abea-3f9d-ac9e36ebc222.png)
次にコマンドに下記を入力し、確認画面ヘ進み作成します。
~~~
cd /home/プロジェクト名 && /usr/bin/php8.0 artisan schedule:run >> /dev/null 2>&1
~~~
ここではphp8.0を指定していますが自分の環境のphpのバージョンに合わせる必要があります。

### 常時SSL化
public_html内の.htaccessに下記を追加して常にhttpsにアクセスするようにします。
~~~ruby:.htaccess
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
~~~
以上でデプロイ作業は完了です。
URLにアクセスして正しく画面が表示されるか確認してください。