AWS EC2にLaravelをデプロイする手順(入門者向け)2022修正版

目次

はじめに

初めてAWSを使う方向けの内容となってます。AWSのEC2にLaravelをデプロイする手順です。

前提・条件

  • Laravelアプリは作成済みで、Githubに置いてある。(他から持ってきてもいいです)
  • WEBサーバーにApacheではなくNGINXを使います。
  • データベースはAWSのRDSではなくEC2内にMySQLを入れて動かします。

全体の流れ

AWSアカウントを作成して、EC2でインスタンスを立ち上げます。はじめに必要なものをすべてインストールしてからそれぞれの設定を行っていきます。サーバの準備が整ったらGithubからLaravelをCloneします。

全体的には初心者向けの内容ですが、ターミナルなどで簡単なコマンド操作などができる方を対象にしています。

サーバの準備

まずはAWSのアカウントを作って、インスタンスの起動まで行っていきます。

AWSアカウント作成

簡単に作れるので詳しくは触れません。個人情報の入力や支払い方法などが必要です。以下のページから作成できます。

AWSアカウント作成

EC2インスタンス起動

アカウントが作れたらサインインして、まずEC2サービスのダッシュボードに行きます。(メニューバーの「サービス」から「EC2」を選択するか、見つからない場合は検索窓で「EC2」と検索すると出てきます)

リージョンの確認
右上辺りに表示されているリージョンが「東京」になっているか確認します。なっていなければ「アジアパシフィック (東京)ap-northeast-1」を選択します。(東京でなければいけないことはありません)

EC2のダッシュボードに入ったら、左のメニューから「インスタンス」を選択し「インスタンスを起動」ボタンを押します。

インスタンスとはAWS独自の仮想サーバの規格です。OSやCPU、メモリーなどをカスタマイズして簡単に立ち上げる事ができます。わかりにくい場合は「サーバ」と読み替えてもいいと思います。

インスタンスの起動設定

インスタンス起動に必要な設定を行います。

インスタンスの名前を入力します。なんでも構いません。わかりやすい名前を付けましょう。

Amazonマシンイメージ(AMI)を選択します。サーバをどのOSで動かすかを決めます。特にこだわりがなければAmazon Linux(無料枠)でいいと思います。

インスタンスタイプは、CPU、メモリなどです。これも特にこだわりがなければt2.micro(無料枠)にしましょう。

キーペアは、インスタンスにPCから接続する時に使う鍵のようなものです。必ず必要になるのでここで作成します。

「新しいキーペアの作成」を押すと、以下のようなダイアログが出てくるので、キーペア名を適当に入力します。以下のオプションは図の通りでOKです。

キーペアを作成」を押すとキーファイルがダウンロードされます。このファイルはインスタンスに接続する時に使います。

作成したら、作成したキーペアを選択しておきます。

ネットワークの設定は、外部からインスタンスへのアクセスをどう処理するかを決めます。初回はセキュリティグループを作成する必要があります。図を参考に設定してみてください。

ストレージはサーバ容量です。必要なサイズを設定します。無料枠は最大30GBです。

以上が設定できたら、「インスタンスを起動」ボタンを押します。(起動には少し時間がかかります)

各種インストール

起動したら、インスタンスに必要なものをインストールしていきます。

インストールするもの

  • NGINX
  • PHP
  • MySQL
  • Composer
  • Git
  • その他Laravelに必要なモジュール

SSHでインスタンスに接続

各種インストールするためにEC2にSSHで接続します。

接続するインスタンスを選択して「接続」ボタンを押すと、各種接続方法が表示されます。

インスタンス I EC2

PCからターミナルで接続する場合

SSH クライアント」を選択すると、接続手順が表示されます。

PCのターミナルから赤線↓のコマンドを打つと接続できます。先程ダウンロードしたキーペアファイルがあるディレクトリ内で実行しましょう。

インスタンスに接続

接続する方法は他にもあります。詳しい方法は長くなるのでここでは省略しますが、機会があったら記事にしたいと思います。

ブラウザから接続する場合

AWSにはブラウザからコマンド入力できる機能があるので、これを使って接続してもいいです。

EC2 Instance Connect」を選択して「接続」ボタンを押す。

インスタンスに接続 I EC2 Management Console

すると、以下のようにコマンド入力画面が開きます。

EC2 Instance Connect

各種インストール

SSH接続できたら、早速インストールしていきます。

まず、インスタンスに初めから入っているパッケージ類をアップデートしましょう。

パッケージ類アップデート

$ sudo yum update

NGINXをインストール

# NGINXをインストール
$ sudo amazon-linux-extras install nginx1

# サーバ起動
$ sudo systemctl start nginx

# 起動しているか確認
$ sudo systemctl status nginx

# インスタンス起動時に自動起動するように設定
$ sudo systemctl enable nginx


↓今ここでは実行しませんが、関連コマンド
----------------------------------
# 再起動
$ sudo systemctl restart nginx
# 設定再読み込み
$ sudo systemctl reload nginx
# 停止
$ sudo systemctl stop nginx

PHPインストール

# PHPインストール
$ sudo amazon-linux-extras install php7.4

# fpm起動
$ sudo systemctl start php-fpm.service

# インスタンス起動時に自動起動するように設定
$ sudo systemctl enable php-fpm

↓今は実行しませんが、後ほど使うコマンド
------------------------------------
# 再起動
$ systemctl restart php-fpm.service

MySQLインストール

データベースをインストールします。今回はMySQLを使いたいので、デフォルトで入っているMariaDBをアンインストールします。

MariaDBが入っているか確認

$ sudo yum list installed | grep mariadb

MariaDBアンインストール

$ sudo yum remove mariadb-libs

MySQL8.0インストール

リポジトリを追加して以下の手順でインストールします。

# MySQLリポジトリ追加
$ sudo yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm -y

# GPG鍵を更新します(最近変更になったため)
$ sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
# MySQLインストール
$ sudo yum install mysql-community-server

# 起動
$ sudo systemctl start mysqld.service

# 起動確認
$ sudo systemctl status mysqld.service

# 自動起動設定
$ sudo systemctl enable mysqld.service

# 確認
$ mysqld --version

Composerインストール

以下のコマンドでインストールできますが、ハッシュの部分が定期的に変わるのでエラーになる場合があります。その場合は公式を参照します。

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');"

移動&リネーム(パスを通す)

$ sudo mv composer.phar /usr/local/bin/composer

Gitインストール

$ sudo yum install git

その他のモジュールをインストール

他にLaravelを動かすのに必要なモジュールをインストールします。例えば以下のもの。

$ sudo yum install php-bcmath
$ sudo yum install php-mbstring
$ sudo yum install php-xml

使ってるライブラリなどによって必要なモジュールが変わる場合があるので、環境に合わせてインストールします。もし足りなかった場合はLaravelデプロイのところでcomposer installした時にエラーで何が足りないか教えてくれるのでそこでインストールしてもOK。

コーヒーブレイク

ここまででインストール関連は終わりです。次に各設定をしていきますが、その前にちょっと休憩がてら、サーバがちゃんと起動しているか確認してみましょう。

EC2のパブリックIPアドレスにブラウザでアクセスしてみます。パブリックIPアドレスは以下の場所で確認できます。パブリックDNSでもアクセスできます。

インスタンス I EC2

NGINXの初期ページが表示されたら正常に起動しています。

SSLの設定をしていないので、「https://~」での接続はできないので「http://~」でアクセスしてください。「オープンアドレス」クリックだと「https:」になってしまうので、「http:」と打ち直します。

各種設定

続いてそれぞれの設定ファイルを編集していきます。

php-fpm

PHPの設定ファイルを一部編集します。

$ sudo vi /etc/php-fpm.d/www.conf

上記コマンドはvimというエディタを使って編集するものです。vimの使い方がわからない方はググってください。

以下の項目を探してそれぞれ修正します。(listen.ownerなどは「;」でコメントアウトされているので「;」を消します)

user = nginx
group = nginx

listen = /var/run/php-fpm/php-fpm.sock

listen.owner = nginx
listen.group = nginx
listen.mode = 0660

php-fpm再起動

編集内容を反映するために再起動します。

$ sudo systemctl restart php-fpm.service

NGINX

続いてNGINXの設定をしていきます。

/etc/nginx/nginx.conf が設定ファイルです。別ファイルを作成して読み込む方法もありますが、今回はこのファイルを直接編集します。

$ sudo vi /etc/nginx/nginx.conf

上記コマンドはvimというエディタを使って編集するものです。vimの使い方がわからない方はググってください。

↓はデフォルトの内容にLaravel公式で紹介されているものを一部修正して挿入しています。内容が理解できなくても最初はコピペでいっちゃいましょう。

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen 80;
        server_name _;
        root /var/www/public;

        add_header X-Frame-Options "SAMEORIGIN";
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options "nosniff";

        index index.php;

        charset utf-8;

        location / {
            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 /index.php;

        location ~ \.php$ {
            fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
            include fastcgi_params;
        }

        location ~ /\.(?!well-known).* {
            deny all;
        }
    }

# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2;
#        listen       [::]:443 ssl http2;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers PROFILE=SYSTEM;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }

}

SSL(ポート443)の設定はまだしていません。現時点での暫定的な内容です。SSLの設定をする場合は後ほど編集します。またドメインの設定をする時にもこのファイルの編集が必要です。

設定反映

# 設定が正しいかテスト
$ sudo nginx -t

# 再起動
$ sudo systemctl restart nginx
or
# 設定再読み込み
$ sudo systemctl reload nginx

エラーが出る場合は、「nginx.conf」の内容に誤りがあります。誤字脱字などないかもう一度確認してみましょう。このファイルはインデント(スペースなど)も正確でないとエラーになります。

ルートディレクトリについて

NGINXのデフォルトのルートディレクトリは「/usr/share/nginx/html」ですが、今回は「/var/www」に変更しています。

ルートディレクトリの権限設定

先程ルートディレクトリを「/var/www」に設定しました。このディレクトリはまだ存在しないので、作成してアクセス権などを設定します。(この権限周りが意外と重要なポイントです

# ルートディレクトリを作る
$ sudo mkdir /var/www

# /var/www の所有者とグループを変更
$ sudo chown ec2-user:nginx /var/www

# /var/www のパーミッションを設定(今後追加されたコンテンツにも適用)
$ sudo chmod 2775 /var/www

# ec2-userを nginx グループに追加
$ sudo usermod -a -G nginx ec2-user

現在ログインしているユーザーは「ec2-user」ですが、外部からのリクエストを実行するのは「nginx」というユーザーです。「ec2-user」を「nginx」のグループに所属させることで同じグループになり、パーミッション77xのファイルならすべての権限を共有することができるようになります。

MySQL

MySQLの初期設定とデーターベースの作成をします。

初期設定の前にrootパスワードを確認しておきましょう。rootパスワードはMySQLのログに出力されています。以下のコマンドでその部分を表示できます。

$ sudo cat /var/log/mysqld.log | grep -e 'A temporary password is generated for root@localhost'

上記のコマンドを実行して表示された内容の最後の文字列がrootパスワードです。

初期設定

$ mysql_secure_installation

以下のように対話形式で設定をしていきます。

Enter password for user root: #初期パスワードを入れる
New password: #新しいパスワードを入れる
Re-enter new password: #もう一度新しいパスワードを入れる
Change the password for root ? ((Press y|Y for Yes, any other key for No) : #変更する場合はYes(y)、しない場合はNo
Remove anonymous users? (Press y|Y for Yes, any other key for No) : #Yes(y)と入力
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : #Yes(y)と入力
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : #Yes(y)と入力
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : #Yes(y)と入力

パスワード入力時、入力した文字は表示されません。入力したらENTERを押しましょう。

新しいパスワードを設定する場合、大文字小文字記号を組み合わせた複雑なものでないと受け付けてくれないので注意。

設定したパスワードはLaravelの.envで使うのでメモっておきます。

データベース作成

データベース名は任意の名前でOKです。これもLaravelの.envファイルで使うのでメモっておきます。

# mysqlにログイン
$ mysql -u root -p

# パスワードを聞かれるので先程のrootパスワードを入力

# データベース作成
mysql> create database [データベース名];

# 確認
mysql> show databases;

# ログアウト
mysql> exit;

MySQLにログインした状態でのコマンド入力は最後に「;」を付けます。

Laravelをデプロイ

サーバの準備が整ったので、早速Laravelをデプロイしていきます。最初に書いたように、LaravelアプリがGithubに置いてある前提ですが、他から持ってきても構いません。デプロイの方法はいろいろあると思うのでそれぞれの方法で行ってください。

GithubにSSHで接続

AWS側でキーを作成して、出来たパブリックキーをGithubに登録します。

SSHキー作成

# .sshへ移動
$ cd ~/.ssh

# キー作成
$ ssh-keygen

----------------------------------------------------------------------------------
Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa): #[Enter]を押す(名前を付けたい場合は入力)
Enter passphrase (empty for no passphrase): #[Enter]を押す(パスフレーズを設定する場合は入力)
Enter same passphrase again: #[Enter]を押す(パスフレーズを設定する場合はもう一度入力)

Githubにパブリックキー登録

以下のコマンドでパブリックキーが表示されるので、コピーしておきます。

$ sudo cat id_rsa.pub

Githubにログインして、Settings > SSH and GPG keys へ進んで「New SSH key」ボタンを押して、コピーしたパブリックキーを登録します。

接続確認

$ ssh -T git@github.com

---------------------------------------------------------------------------------
# 初回接続時は以下のようなことを言われるので、yesと入力
Are you sure you want to continue connecting (yes/no)?

Hi ******! You've successfully authenticated, but GitHub does not provide shell access.
↑こう表示されたら成功

GithubからLaravelアプリをCloneする

# ルートディレクトリに移動
$ cd /var/www

# Cloneする
$ git clone git@github.com:[アカウント名]/[リポジトリ名].git .

clone先として「.」ドットを指定してルートディレクトリ直下にファイルを展開します。(最後のスペース + ドットの部分)

指定しないとディレクトリごとcloneされるので注意。(階層が変わった場合は、/etc/nginx/nginx.conf でルートディレクトリの設定を変更する必要があります)

各種設定

.envファイル作成

vi /var/www/.env

.envの内容はアプリによって違うと思いますので、適宜設定してください。

APP_NAME=”アプリ名”
APP_ENV=production
APP_KEY=この後生成
APP_DEBUG=false
APP_URL=”アプリURL”

中略

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=”DB作成時の名前”
DB_USERNAME=root
DB_PASSWORD=”MySQL設定時のパスワード”

中略

パッケージインストール

$ composer install

アプリケーションキー(APP_KEY)生成

$ php artisan key:generate

DBテーブル作成

$ php artisan migrate

確認

先程確認したパブリックIPアドレスを開いて確認してみましょう。

ここまでの手順が問題なくできていれば、Laravelが表示されるはずです。

独自ドメインの設定

パブリックIPアドレスでアプリが表示できたら、そのIPアドレスと独自ドメインを結びつければ、自分のドメインでアプリを公開できるようになります。

ドメインの設定については環境によって大きく変わるので、それぞれのケースに合わせてググってもらった方が良い方法が見つかると思います。大まかにどんなケースがあるのかご紹介したいと思います。

AWSでドメインを取得する場合

AWSで取得して管理する場合は、Amazon Route 53 というサービスを使います。取得から管理まですべてAWSで完結するので、これから取得しようと考えている方はRoute 53を検討しても良いと思います。

他社で取得したドメインをAWSに移管して使用する場合

他社で取得したドメインをAWSに移管する(引っ越す)ことができます。これをすることで、ドメインの管理や支払いなどすべてをAWSに移すことができます。

移管するには、Amazon Route 53 を利用します。移管の方法については割愛しますが、大まかには、携帯のMNP(携帯電話番号ポータビリティ)のように、契約中の会社からキーを受け取って、そのキーを使って移管先で手続きをします。

AWSの場合ではありませんが、ドメイン移管についての流れについて過去にまとめた記事があるので参考にしてください。

サイト引っ越し(ドメイン移管・DNS設定)の流れ

他社で取得済みのドメインをそのまま使用する場合

AWSへドメインを移管しなくても、そのドメインを使ってアプリを表示することができます。他社でドメインを管理したまま、そのドメインの行き先をEC2へ向けるだけで実現します。

AWSでDNSを管理する場合

ドメインを管理している会社のドメイン関連の設定で、DNSの設定にAWSのDNSを設定することで、AWS側でDNSの設定を管理することができるようになります。DNSを管理できるようになると、サブドメインの設定や他の様々なことができるようになるので、可能ならこちらの方法がおすすめです。

これについても具体的な方法は割愛しますが、AWS側ではRoute 53 サービスを利用します。

他社でDNSを管理したままEC2に向ける場合

ドメインの管理もDNSの管理も他社に置いたまま、ドメインの行き先をEC2へ向けることができます。

ドメインを管理している会社のDNS設定で、AレコードというところをEC2のパブリックIPアドレスに設定をするだけです。これも詳細は割愛しますが、設定はドメイン管理会社側のみで、Route 53 サービスは利用しません。

上記の方法すべての場合に言えることですが、パブリックIPアドレスはインスタンスを起動する度に変わってしまいます。なので、ドメインと結びつける場合は必ず固定する必要があります。

EC2のElastic IP というサービスを使ってパブリックIPアドレスを固定しましょう。

SSLの設定

https://~で表示するためにはSSLの設定が必要です。

SSL証明書を無料で発行するには、「Let’s Encrypt」を使う方法と、AWSのELB(Elastic Load Balancing)を使う方法があります。

「Let’s Encrypt」を利用する手順を書いたのでご参照ください↓

AWS EC2に無料SSL(let’s encrypt)を設定する

上記記事の手順へ進む前に、/etc/nginx/nginx.confserver_nameへ対象のドメインを入れて、http://[ドメイン]で表示できる状態にしておきましょう。

    server {
        listen 80;
        server_name ここにドメインを入れる;
        root /var/www/public;

最後に

以上の手順でLaravelアプリをAWSで公開することができたと思います。

AWSを利用する前は得体の知れない難しさを勝手に感じていましたが、使ってみると意外とわかりやすく出来ていて、手順さえわかれば使いやすいサービスだなあと思いました。わからないところはググればAWS関連の記事は多いので、すぐに解決できたりします。とはいえ奥は深いのでいろいろハマると迷子になりますけどね。

サーバのタイムゾーンを日本標準時へ変更

ログなどの記録時間が日本時間の方が都合がいい場合は以下のように変更します。

# タイムゾーンの設定ファイルを所定の場所にコピー
$ sudo cp -p /usr/share/zoneinfo/Japan /etc/localtime

# /etc/sysconfig/clockを編集
$ sudo vi /etc/sysconfig/clock

---------------------
ZONE="Asia/Tokyo"
UTC=false