AWSサーバーにlaravelを構築した時の備忘録
以前、仕事の関係でawsサーバーにテスト用のlaravel環境を構築する機会がありましたので、ここにその時の備忘録を記しておこうと思います。
以下注意点です。
- 今回はあくまでテスト環境です。今すぐ作成したものをサーバー上でとにかく確認したいという用途であったことを理解していただき、「使えるところは使う」というくらいの面持ちで閲覧してください。
- それと関係して今回はDBは使っていません。DBを構築するなら別インスタンスに構築するか、AWSならRDSを使って接続することになります。
- 今回はawsサーバー内に.pemファイルを使って入るところから始めます。サーバーの用意は調べると多くの最新の記事が出てくるのでそれに頼ることにします(今後機会があれば書きます)。
- 今回はmacを使っています。少し手順がありますがwindowsでもできます。apple自体はあまり好きではないですがssh接続が簡単に出来るので...
構築環境
説明できる範囲で今回使う環境を紹介します
- Amazonマシンイメージ(AMI):Amazon Linux 2023
- webサーバー :apache
1. ssh接続
sudo ssh -i /Users/<pemファイルがおいてあるパス>/ファイル名.pem <ログインするユーザー名(初期は「ec2-user」)>@作成したIP
するとこのようなアスキーアートが出て入れます
, #_
~\_ ####_ Amazon Linux 2023
~~ \_#####\
~~ \###|
~~ \#/ ___
~~ V~' '->
~~~ /
~~._. _/
_/ _/
_/m/'
2. 現在のサーバーの情報確認
今回は自分で作ったサーバーではなかったので、まずサーバーの確認をすることにしました。
自分で作った際は必要ないと思います。
今回は仮として「ec2-user」でログインしたものとします。
-—————————–
$ pwd
/home/ec2-user
-—————————–
$ whoami
ec2-user
-—————————–
$ sudo whoami
root
-—————————–
$ id
uid=1000(ec2-user) gid=1000(ec2-user) groups=1000(ec2-user),4(adm),10(wheel),190(systemd-journal) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Amazon Linux 2023 ではデフォルトユーザーは ec2-user でsudo権限が付与されているので最初はみなさんこうなると思います。
補足
せっかく調べたのでこの辺りのコマンドの意味を説明しようと思います。
・uid=1000(ec2-user):「User ID」のこと。Linuxでは内部的にユーザーは「番号」で管理されており、1000は基本的に最初に作られた一般ユーザー。・gid=1000(ec2-user):「Group ID」のこと。ec2-user は自分と同じ名前のグループに属している。Linuxではユーザーが複数グループに所属することができる。このグループの概念は今後apacheを入れたときに少し関係してくる。
・groups=1000(ec2-user),4(adm),10(wheel),190(systemd-journal):現ユーザーが所属しているグループ。
またgidとgroupsの違いは、gid= は「主グループ」で、groups= は「所属している全グループ一覧」 です。
adm -> ログファイル閲覧権限を持つグループ
wheel -> sudoを許可されるグループ
systemd-journal -> systemdのログを読める権限・context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023:通常のLinuxのとは違う、SELinux のセキュリティコンテキストです。
ユーザー : ロール : タイプ : レベル で構成されています。
調べた感じこの「unconfined_t」が特に重要で、通常のLinuxの権限上で他のアプリにrootが奪取されたり脆弱性の問題があった時にこれが二重ロックとして働くようです。
正直これだけでも記事が一つ書けそうなくらい深い内容なのでこれくらいにしておきます。少なくともここからも権限の広いユーザだということがわかります。
また、「/etc/os-release」にOS情報を格納する標準ファイルがあるのでそこを確認するとサーバーの基本的な情報が確認できます。
ここで「Amazon Linux 2023」などということがわかります。
一応出力内容は伏せていますが、おそらく同じサーバーエンジンを使っていれば同じです。
$ cat /etc/os-release
NAME=
VERSION=
ID=
ID_LIKE=
VERSION_ID=
PLATFORM_ID=
PRETTY_NAME=
ANSI_COLOR=
CPE_NAME=
HOME_URL=
DOCUMENTATION_URL=
SUPPORT_URL=
BUG_REPORT_URL=
VENDOR_NAME=
VENDOR_URL=
SUPPORT_END=
3. dnf の確認・更新
dnf とはLinux系で使用されるパッケージ管理コマンドです。
エンジニア歴の長い人はyumというものもあり、ほぼその後継と捉えられているようです(違っていたらすみません)。
とにかく、macのHomebrewやwindowsのWinGetのようなものです。
補足
細かい話をすると dnfは LinuxのRHEL系で使われるものです。みんな大好きUbuntuやDebianでは aptを使います。
dnfがあるか確認 & アップデートをしていきます。
$ sudo dnf -y update
Amazon Linux 2023 Kernel Livepatch repository 208 kB/s | 31 kB 00:00
Dependencies resolved.
Nothing to do.
Complete!
4. webサーバーの導入
webサーバーとはHTTP・HTTPSリクエストを受け取ってレスポンスを返すサーバーのことです。
今回は諸々の理由からapacheを使いますが、個人的に好きなnginxなどもあります。
ちなみに、laravelの公式ドキュメントではnginxが使われています。
Deployment - Laravel 12.x - The PHP Framework For Web Artisans
$ sudo dnf -y install httpd
〜
Complete!
インストールできたら次にサーバーを立ち上げてみます。
$ sudo systemctl enable –now httpd //システムの立ち上げ
$ sudo systemctl status httpd –no-pager //状態の確認
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
Active: active (running) since Wed 2026-02-18 08:59:56 UTC; 110ms ago
Docs: man:httpd.service(8)
Main PID: 28125 (httpd)
Status: “Started, listening on: port 80” //80番ポート
Tasks: 177 (limit: 517)
Memory: 13.0M
CPU: 50ms
CGroup: /system.slice/httpd.service
├─28125 /usr/sbin/httpd -DFOREGROUND
├─28135 /usr/sbin/httpd -DFOREGROUND
├─28139 /usr/sbin/httpd -DFOREGROUND
├─28140 /usr/sbin/httpd -DFOREGROUND
└─28141 /usr/sbin/httpd -DFOREGROUND
「systemctl」について:
- Amazon Linux 2023 は systemd という仕組みでサービスを管理(起動・停止・依存関係管理など)しているようです。昔は service コマンドだったようですが、
今は systemd が OS のサービスを管理しています。
補足
少し詳しい流れを説明するとこうです。
まず、sudo systemctl enableで対象サービス(httpd)を起動ターゲットに登録しています
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service
↑の出力が肝です。
「/usr/lib/systemd/system/httpd.service」に対して「/etc/systemd/system/multi-user.target.wants/」にシンボリックリンク(パスを通すような感じ)が作られます
つまり「マルチユーザーモードで起動するときに httpd.service を実行する」よう登録したということです
マルチユーザーモードとはLinuxの動作モード(ランレベル)におけるサーバーとして稼働している通常状態のことです(といううかEC2は通常multi-user.targetで起動します)
| ランレベル | Head |
|---|---|
| 0 | シャットダウン |
| 1 | シングルユーザーモード |
| 3 | マルチユーザーモード(CUI) |
| 5 | GUIモード |
これを、先ほどの出力の
multi-user.targetが意味しています
つまり、誤解を恐れずにいうと「sudo systemctl enableはsystemdのターゲット機構にサービスを登録する操作である」ということです
5. webサーバーの疎通確認
$ curl -I http://localhost
HTTP/1.1 403 Forbidden
〜
疎通確認をしたところ403エラーが出ました。 403は、サーバーには届いてるが Apache が「この場所は見せない(読ませない)」判断して拒否してる状態です。 調べた感じ主に2つの可能性があります。
- 権限の問題
- index.html や index.php が無い(正しい場所に置かれていない)
はい...普通に確認する用の HTMLファイルを置くのを忘れていました。
$ sudo bash -lc ‘echo “OK” > /var/www/html/index.html’ //HTMLファイルを作成
$ sudo chmod 644 /var/www/html/index.html //権限を与える(所有者:読み書きOK それ以外:読むだけOK)
curl -I http://localhost //再度疎通確認
curl http://localhost
HTTP/1.1 200 OK
〜
これで、「OK」を確認できました。
正直、疎通確認が必要なければどうせ後でlaravelを置くので必要ないのですが、一応ここの話はこの後のLaravel導入時で重要な話になってきます。
Laravelを動かすときも同じ理屈で、DocumentRoot を public/ にし、そこにある index.php をApacheがそれを読める+PHPとして実行できる必要があります。
6. phpの必要なパッケージの導入
いよいよphpです。
本当はapacheと一緒に入れても良いのですが、今回は学習のため後から入れました。
$ sudo dnf -y install php php-fpm php-cli php-mbstring php-xml php-curl php-mysqlnd
~
Complete!
$ php -v // バージョンが出ればOK
次に、phpををwebサーバーで動かします
$ sudo systemctl enable –now php-fpm
$ sudo systemctl status php-fpm –no-pager
〜
Active: active (running)
この「Active: active (running)」が帰って来ればうまくいっている証拠です。
apacheの時にも似たコマンドがありましたね。
今回はそれのphp版です。php-fpmとありますがWebサーバーからPHPを実行するための仲介プロセスのようなものだと考えてください。
補足
php-fpmとはPHP FastCGI Process Managerのことです。
なんのことかいな、と思うかもしれませんが「FastCGIという通信方式でPHPを実行するプロセス管理機構」のことです。
FastCGIについてはこの記事がとてもわかりやすいです。
わかったふりをしていたphp-fpmってなんなのかを図解してみた #PHP - Qiitaちなみに、php-fpmのマスタープロセスはrootで起動しますが、実際にPHPを実行するワーカープロセスはapacheユーザーで動作します。
これは、仮にアプリケーションに脆弱性があっても影響範囲を限定するための仕組みだと思われます。
先ほど登場したsystemdと一緒に確認するとsystemd -> php-fpm マスタープロセス(php-fpmのワーカー生成などの大本の管理) -> php-fpm ワーカープロセス(実処理、PHPコード実行や受け取りや結果の返答など)
といった感じです。
少し脱線しましたが、少し詳しい流れはこのような形になります。
Apache → FastCGI → php-fpm → PHP
- Apacheがリクエストを受ける
- リクエストが .php ファイルの場合、FastCGI経由で php-fpm に処理を委譲
- php-fpmがPHPを実行
- 結果をApacheへ返す
- ブラウザへ返る
最後に、apacheが正しく動作しているか確認をしてここは終わりです。
「enabled」が帰って来ればOKです。
$ sudo systemctl is-enabled httpd
enabled
6. composerの導入
composerはPHPのパッケージ管理ツールです。
ここで見つけたのですが、このサイトがわかりやすくほぼそのままの通りでできます。
【AWS初学者向け】EC2にLaravelアプリケーションをデプロイ #PHP - Qiita
ただし、先に言っておくと「php -r "if (hash_file~」から始まるコマンドは記事のそのままのハッシュで進めると(少なくとも自分の環境では)うまくいかなかったので--公式のドキュメントをコピペして実行した方が良いです。
$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php -r "if (hash_file('sha384', 'composer-setup.php') === 'c8b085408188070d5f52bcfe4ecfbee5f727afa458b2573b8eaaf77b3419b0bf2768dc67c86944da1544f06fa544fd47') { 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
基本的に意味を理解する必要は全くないのですが
- PHPを使ってcomposerのインストーラーをダウンロードし、composer-setup.php という名前で保存
- ダウンロードしたファイルのSHA384ハッシュを計算し公式が公開している値と比較しており、一致すれば正規ファイルと分かります。つまり、改ざんされていないか確認しています
- インストール
- インストーラーの削除
- composer.phar を/usr/local/bin に移動させ「composer」コマンドを使えるようにしています
$ composer -V
Composer version
PHP version
これでバージョンが表示されたらOK
7. laravelの導入
laravelの置く場所を作っていきます。
今回は/var/wwwの上に作ります。
$ sudo mkdir -p /var/www/
$ cd /var/www
補足
linuxのディレクトリにはそれぞれ役割があります /etc:設定ファイル
/usr:プログラム
/home:ユーザー
など
そして今回の /var は可変データ(Variable Data)に関するものをおくディレクトリです。
つまり、Webサーバーが配信するコンテンツの置き場所はここになりますより詳しく知りたい時は、この記事がわかりやすく説明されておりオススメです。 [Linux]各ディレクトリの役割 #var - Qiita
いよいよlaravelを導入していきます。
ここでは、myapp という名前のディレクトリに構築することにします。
$ composer create-project laravel/laravel:^12.0 myapp
~
mkdir(): Permission denied
はい、エラーが出ました。
laravelの置く場所を作る際にsudo mkdir -p /var/www/とsudoを使ったため権限がrootになり、現ユーザーのec2-userでディレクトリやファイルを触る権限がなくなってしまったためこのようなエラーが出ました。
なのでrootの所有になっているものをec2-userに変えます。
$ sudo chown -R ec2-user:ec2-user /var/www //所有者の変更
$ composer create-project laravel/laravel:^12.0 myapp
で成功します。
8. apacheの設定ファイルを編集
apache の設定を変更する前に、現在の設定を確認します。
$ sudo grep -R "DocumentRoot" -n /etc/httpd/conf /etc/httpd/conf.d
/etc/httpd/conf/httpd.conf:120:# DocumentRoot: The directory out of which you will serve your
/etc/httpd/conf/httpd.conf:124:DocumentRoot "/var/www/html"
/etc/httpd/conf/httpd.conf:235: # access content that does not live under the DocumentRoot.
〜
/etc/httpd/conf/httpd.conf
/etc/httpd/conf.d/*.conf
から "DocumentRoot"に関する記述を探しています。
基本的に /etc/httpd/conf/httpd.conf にありますが念のためです。
そして結果として帰ってきた「/etc/httpd/conf/httpd.conf:124:DocumentRoot "/var/www/html"」が今回の編集が必要なところです。
ところで『5. webサーバーの疎通確認』で403エラーが出た時、/var/www/html/index.htmlを用意することで直りました。
それは、/etc/httpd/conf/httpd.conf に「DocumentRoot "/var/www/html"」とあるからです。
ここは apache の非常に重要な設定でWebサーバーが公開するディレクトリを意味しており、laravelはエントリポイントである /public/index.php を最初に読ませることが必要です。
よってここの DocumentRoot "/var/www/html"をDocumentRoot "/var/www/myapp/public"にする必要があります。
$ sudo vi /etc/httpd/conf/httpd.conf
viは個人的に苦手で毎回使い方を忘れてしまうのですが、このような時によく使うので操作を覚えた方が良いです。自分は毎回調べます。
それはさておき「DocumentRoot "/var/www/html"」を「DocumentRoot "/var/www/myapp/public"」にしてください。
それともうひとつ、Allow Overrideの項目をALLに変更してください。
Laravel の .htaccess を有効にするために必要です。
Apache では基本的に先ほどのhttpd.confで設定を管理しますが、.htaccessファイルを置くことでディレクトリごとの設定が可能になります。
Laravel の public ディレクトリには .htaccessファイルがあります。ここで主にURLリライト(実際とは異なる構造の内部的なURLを返す)をしており、.htaccess を有効にしないと正しく動きません。
この2つを変更したら、次に再起動、疎通確認をします。
$ sudo systemctl restart httpd
$ curl -I http://localhost
HTTP/1.1 500 Internal Server Error
~
X-Powered-By: PHP
~
500番エラーです。X-Powered-By: PHPとあるので apache が正しく動いてphpが動作し public/index.php を読めています。
これはおそらくlaravel側のエラーだと推測できます。
この情報だけでは原因が特定できないので、laavel側のエラーを見にいきます。
laravelのエラーはデフォルトでは storage/logs/laravel.log に入っています。
$ sudo tail -n 100 storage/logs/laravel.log
tail: cannot open 'storage/logs/laravel.log' for reading: No such file or directory
「あれ? ない?」
storage/logs/laravel.log というディレクトリやファイルはないと言われました。
ということは storage ディレクトリに apacheが書き込む権限がないことが原因だと思われます。
php-fpmのところで言及しましたが、php-fpmのマスタープロセスはrootで起動しますが、実際にPHPを実行するワーカープロセスはapacheユーザーで動作します。
つまり、ログを書いているのは Apache ではなく Laravel(=PHP)です。
どちらにせよ、storage に apacheの権限を付与しないといけません。
$ sudo chown -R apache:apache storage bootstrap/cache
$ sudo chmod -R 775 storage bootstrap/cache
主にlaravelのキャッシュを司る bootstrap/cache にも一緒に権限を渡しています。
そしてもう一度エラーを発生させると storage/logs にlaravel.log生成されたことが確認できました。
中身を確認します。
$ curl -I http://localhost
HTTP/1.1 500 Internal Server Error
~
$ ls -la storage/logs
~ laravel.log
$ sudo tail -n 100 storage/logs/laravel.log
~
確認するとわかりますが、とんでもない情報量です。
残念ながら、今の実力ではこのエラーの内容を理解することができませんでした。ただし、絶対に読めた方が良いです。
個人的にここがジュニアエンジニアと中堅エンジニアのボーダーだと思います。
今回はAIに読んでもらいました。要約すると以下の通りです。
ログを確認すると、セッション保存先が database になっているにも関わらずDBが準備されていないことが原因です。
最初に結論を言うと、これは database/ ディレクトリ と database/database.sqlite にapacheの書き込み権限がないのが原因です。
laravelでは(laravel以外でも基本そうだと思いますが)ユーザーごとの一時的な状態をサーバー側に保存する仕組みがあります。自分では意図していなくても、CSRF対策、フォーム、一時メッセージなどのために必要に応じてセッションを利用します。
少なくとも、現在の composer を使ってlaravelを作ると(他の方法で作ったことがないので他の状況ではわかりませんが)最初からsqliteが作られます。
それは、laravel内の myapp/composer.json に
"scripts": {
~
"post-create-project-cmd": [
"@php artisan key:generate --ansi",
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
"@php artisan migrate --graceful --ansi"
],
~
があることからわかります。
これは、composer create-project 実行後に自動で走る Composer Script です。
なので、このままこのsqliteを使うのであれば database/ ディレクトリ と database/database.sqlite にapacheの書き込み権限を渡す必要があります。
$ sudo chown apache:apache database/database.sqlite
$ sudo chmod 664 database/database.sqlite
$ sudo chown apache:apache database
$ sudo chmod 775 database
こうして、再びリスタート直し疎通確認します。
$ php artisan config:clear
$ sudo systemctl restart httpd
$ curl -I http://localhost
HTTP/1.1 200 OK
~
はい、200 OK が出て通りましたね。
そして、ブラウザから自分のサーバーのグローバルIPからアクセスして最初のlaravelの画面が出れば構築完了です。
お疲れ様でした。
終わりに
今回は主に webサーバーの権限を学習するのに良い機会になったと思います。
アプリが動作するためにどのファイルやファオルダに権限を渡すのか、またセキュリティの観点からどこまで権限を渡して良いのかを考える良い経験になったと思います。
また、この後もフロントサイドにvuejsを入れようとした際にnpm installをしようとするとサーバーが落ちた問題とその対処をした話もありますが、それは改めて書くことにします。
Author
主にシステム面で学習したことをまとめています。 フロント、サーバー、インフラ、AIなど細かい分野に絞らずに広く発信していきます。