最近業務でNext.js+LaravelのアプリケーションをAWSのAmazon ECS(Fargate)にデプロイするタスクを担当しているので、デプロイするにあたりNext.js側、Laravel側でやっておくこと、エラー対応などをまとめておく。
- ECSへのデプロイはEC2へのデプロイに比べそもそもネットに情報が少ない
- ECSの中でもデータプレーン(コンテナ実行環境)にEC2を使った記事が多くFargateを使った記事はかなり少ない
- ECS+Fargateへのデプロイでも本記事のようなフロントエンド+APIの構成のデプロイ例はマジで少ない
という状態で結構苦戦したので、自分で苦戦したことを残しておくとともに同じ構成でデプロイする方に向けて参考になれば嬉しいです。
ECS、ECR、Fargateについての技術説明・全体的なデプロイ作業の手順についてはこの記事では扱わないが、この記事(というかZennのbooks)がめちゃくちゃ参考になった、かつ、わかりやすかったのでこれに沿って作業したのでオススメ。


Zennのbooksは技術スタックがNuxt.js+Railsと見事に被ってないがとてもわかりやすかったのでオススメ。(こういうのが無料で手に入るってすごい…)
この記事では
- Docker
- Next.js
- Laravel
- AWS
に分けてまとめていく。
Docker
まずはDockerコンテナに関係するところから。
ローカル開発でDocker環境を使う場合にDocker Composeでコンテナを一元管理してdocker-compose.yml
にvolumesオプションでローカルとコンテナ側でソース等を関連付けることがよくあるが、ECSにデプロイする場合はDocker Composeは使えないので基本的にDockerfile内でローカルのソースをコンテナ側にコピーする(COPY
コマンド実行)必要がある。
PHP
コンテナを立ち上げる時にLaravel側のソース変更を反映をする必要があり、そこにはenv
ファイルやconfig
ファイルの変更も入っている可能性があるのでDockerfileにコマンドを追加してキャッシュをクリアする。
WORKDIR /app
COPY ./api .
RUN composer install && \
php artisan cache:clear && \
php artisan config:clear && \
chmod -R 777 storage
- php artisan cache:clear:envファイルの変更を反映する
- php artisan config:clear:configディレクトリのファイルの変更を反映する
configファイルの内容を反映するために使う選択肢にphp artisan config:cache
があるが、これはキャッシュファイルを作成するためのものなのであまり使わない方が良い。
以下の内容なら良いと思います。(というかデプロイ環境ならこっちの方が良いかも?)
WORKDIR /app
COPY ./api .
RUN composer install && \
php artisan cache:clear && \
php artisan config:clear && \
php artisan config:cache && \
chmod -R 777 storage

Nginx
Nginx・Laravelのコンテナ間通信
今回の構成ではNext.js→Nginx→Laravelという通信の流れでNginxとLaravelでコンテナ間通信が生じる。
Dockerでのローカル開発では宛先となるPHPコンテナのサービス名を用いるが、ECSでのコンテナ間接続では宛先のホストはlocalhostになるのでローカル用とECS用の設定ファイルが必要になる。
ローカル開発だけの段階では設定ファイルはdocker/nginx/conf/default.conf
に置いていたけど、以下のように分けることで対応した。
docker/nginx/conf/local/default.conf
:ローカル開発用docker/nginx/conf/ecs/default.conf
:ECSデプロイ用
コンテナ間通信を表すコードの違いは以下のとおりである。
ローカル開発用
# FastCGIサーバーのアドレスを指定
fastcgi_pass api:9000;
ECS用
# FastCGIサーバーのアドレスを指定
fastcgi_pass localhost:9000;
ここは調べてもあまり情報が出てこなかったので手こずった。
Laravelのソースコードのコピー
NginxコンテナにLaravelのソースコードをコピーしないとNginxにアクセスした時に404になる。(ローカルのapiディレクトリにLaravelを配置している場合)
COPY ./api /app
ローカル環境ではこのコピーがなくても問題なく動いたので全然気づかなかったけど、設定ファイルでLaravelのpublicディレクトリを見に行く設定をしているのでそれはそうだよなとなった。(逆になんでローカルでは動いたんだろうと思っている…)
Node(Next.js用)
Next.js側でもAPIのドメイン等の環境変数の切り替えが必要だが、Next.jsはnext start
すると.env.production
を(ファイル名指定で)読み込みにいくので、以下のようにしてdev環境, stg環境, prod環境で使用する環境変数ファイルを切り替えるようにした。(他にも方法があると思うが今の自分にはこれがシンプルでやりやすかった)
# dev環境
COPY ./client/.env.dev ./.env.production
# stg環境
COPY ./client/.env.stg ./.env.production
prod環境の場合は、準備した.env.production
を使えば良いので、上記コードの前に実行するソースコードのコピーコマンドだけで問題ない。
Next.jsの環境変数の取り扱いはルールがややこしいので必要な時に何度も調べて確認するのが良いと思う。
Next.js
getStaticPropsを使う時のリクエスト先のエンドポイント
SSG使う場合のメソッドであるgetStaticProps内で使うAPIのエンドポイントのルールはローカル開発とは異なる。
結論から言うとクライアントサイドからAPIにリクエストするときと同じエンドポイントでOK。
ローカルのDocker環境の場合は例えば、Nginxコンテナ(サービス名はnginx)のポートが
- ローカル:8000
- コンテナ:80
とした場合、
- クライアントサイドからリクエストするエンドポイント:
http://localhost:8000
getStaticProps
内でリクエストするエンドポイント:http://nginx:80
となるが、ECSにデプロイした場合は、上記2つは同じエンドポイントを指定する。
ローカル開発でエンドポイントが異なる件に関してはZennのスクラップで雑だけど残している。
health check用のエンドポイントを定義する
ECSのコンテナにALB(Application Load Balancer)経由でアクセスする場合はhealth checkが必要になるため、health check用のAPIエンドポイントを設定する必要がある。
health check対象のパスを/api/healthcheck
とした場合は、pages/api/healthcheck.ts
を作成する。
import { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify({ status: 'ok' }))
}
health checkは指定のエンドポイントからステータスコード200のレスポンスが返却されるとOK。
後から書くが、バックエンドにもALBを設ける場合はLaravel側にも同様にhealth check用のAPIエンドポイントが必要になる。
Laravel
環境でenvを切り替える
LaravelもNext.js同様、デプロイする環境(dev, stg, prod)で読み込むenvファイルを切り替える必要がある。
切り替え方法はいくつかあるが、この記事では個人的に簡単だと思った方法を紹介する。
public/.htaccess
を以下のように修正する。
# Set APP_ENV
SetEnvIf Host "api.sample.com" APP_ENV=prod
SetEnvIf Host "api.stg.sample.com" APP_ENV=stg
SetEnvIf Host "api.dev.sample.com" APP_ENV=dev
これで以下のような設定にすることができる
https://api.sample.co/〜
:env.prod
を読み込むhttps://api.stg.sample.co/〜
:env.stg
を読み込むhttps://api.dev.sample.co/〜
:env.dev
を読み込む
他の方法はこちらの記事に書かれている。(結構古い記事…)

Laravel Sanctum用の設定を変更する
これはフロントエンドとLaravelの認証にLaravel SanctumのSPA認証を使っている場合の話になるが、環境変数の修正が必要になる。(以下はdev環境を想定)
SESSION_DOMAIN=.dev.sample.com # ドメインの頭に . をつける
SANCTUM_STATEFUL_DOMAINS=dev.sample.com # フロントエンドのドメインを指定
バックエンドのドメインにapi.dev.sample.com
のようにサブドメインを使っている場合でも、SESSION_DOMAIN
には独自ドメイン(ここでいうとdev.sample.com
)の頭に.
をつけた値を設定する。
ローカル開発の場合はSESSION_DOMAIN=localhost
でいけたのは何でだろうか…(.
をつけてない)
Laravel Sanctumについては別の記事でまとめている。


health check用のエンドポイントを定義
バックエンドのコンテナへのアクセスにALBを使う場合はhealth check用のAPIエンドポイントを設ける。
フロントエンドと同様に/api/healthcheck
を対象パスとしてroutes/api.php
に追記する。
// health check用
Route::get('/healthcheck', function () {
return response()->json(200);
});
AWS
デプロイするソースコードを修正した時の再デプロイ手順
ECS+Fargateにデプロイしたアプリケーションのソースコード(アプリ・Docker環境とも)変更を再度デプロイしたい時の手順は以下の順番で行う。
- ECRへのログイン
- イメージのビルド
- イメージへのタグ付け
- イメージをECRへプッシュ
- タスク定義のリビジョンアップ
- サービスの更新(最新のタスク定義を選択)
これを毎回する必要があるので、自動化したいなという気持ちが湧き上がる。
AWSのCode BuildとCode Pipelineというサービスでできるらしい。
GUIツールでRDSに接続する方法
まず、GUIツールを使ってDBにアクセスするのは絶対にしたい。
EC2インスタンス上でECSコンテナを動かす場合は、そのEC2にSSH接続してRDSに接続できるので
- RDSの情報(ホスト/ユーザー名/パスワード/ポート)
- SSH用の情報(EC2のホスト/ユーザー名/秘密鍵)
を使ってGUIツール(Sequel AceやTable Plus)でRDSに接続することができる。
が、Fargate上でコンテナを動かす場合はそれができない。
コンテナ実行環境にFargateを使っている場合は、踏み台サーバー的としてEC2を準備してそのEC2にSSHしてRDSに接続しにいく。(EC2のスペックは最小限でOK)
最後に
初めて実務でAWSをガッツリ触るタスクが「Next.js+LaravelのアプリケーションをECS+Fargateにデプロイする」という重めのものだったけど、学びになることがたくさんあってよかった。(めちゃくちゃ苦戦しました。)
心残りがgetServerSideProps
がうまくいかず、SSGだとまずい箇所は全てuseEffect
内でクライアントでデータフェッチするように変更したこと。。
せっかく実務でAWSを触ったので最低限のキャッチアップはして記事を書こうかなと思っている。
コメント