🚨 記事内容精査中です。
■ 実際にあった未経験エンジニアの物語
1章 Webサーバーソフトウェアを知る
あなたはプログラミングの世界に新たに足を踏み入れ、Webアプリケーションを開発する際にはWebサーバーソフトウェアが必要だということを学びました。このWebサーバーソフトウェアは、インターネット上でユーザーとアプリケーションの間の通信を担う重要な役割を果たすと理解しました。1
2章 Laravelプロジェクトの始動
あなたはLaravelというPHPフレームワークを使い始め、自身のプロジェクトを立ち上げます。すると、ブラウザ上であなたのプロジェクトのページが表示されていることに気づきます。この時点で、あなたはまだ専用のWebサーバーソフトウェアを設定していないはずです。
3章 誤解
「LaravelはWebサーバーソフトウェアがなくてもなんとか上手く動くのだろうか?」という疑問が浮かびましたが、なんかうまく動いているし、深くは考えませんでした。
(実はあなたの知らないうちにPHPのビルトインサーバー2が背後で動作しており、ブラウザでの表示を可能にしていました。このとき、php artisan serve
という魔法のコマンドがそのビルトインサーバーを起動させていることをあなたは知る由もなかった。)
筆者メモ
1年目の後輩にヒアリングしたところ、php artisan serveで起動しているのがサーバーだという感覚はなく、何かLaravelのプログラム群をランニング状態にするという感覚があると教えてもらいました。つまり、プログラム自体にON/OFF状態があるという感覚があるようです。確かに直観的にはそう考えることもありそうだなと感じました。
4章 忍び寄るnginx
ある日、あなたはチームの他のメンバーが環境構築について話しているのを耳にします。彼らはWebサーバーとしてnginxを使用することを検討していました。あなたは疑問に思います。「Laravelを使っているんだから、Webサーバーは必要ないのでは?」と。この矛盾があなたの脳を停止させました。
5章 発見!ビルトインサーバー
あなたの調査と学習を通じて、ついにビルトインサーバーの存在とその役割を理解します。php artisan serve
コマンドがビルトインサーバーを起動していたこと、そしてこれが開発用の簡易的なサーバーであることが明らかになります。
6章 本番運用とnginxへの移行
更に深く掘り下げると、ビルトインサーバーが本番環境には適していないことがわかります。本番環境では、安定性、セキュリティ、スケーラビリティが求められ、これらを満たすためにはnginxのような本格的なWebサーバーが必要です。あなたはnginxを使えるようになることの重要性を理解し、その学習に取り組み始めます。
■ nginxの設定ファイルを理解する
この記事でのゴールは、
- dockerを利用して、nginxとphp-fpmを組み合わせたLaravelアプリケーションの実行環境を構築する
ことです。さっそく、説明を始めていきます。
▼ nginx.confファイル
通常nginxをインストールすると、/etc/nginx/
ディレクトリにnginx.conf
ファイルが配置されます。ここに設定を書き込んでいきます。
▼ 設定項目の構造
⦿ ディレクティブ
ディレクティブは、Nginxの設定ファイル内でサーバーの動作を指示する命令です。ディレクティブは名前とパラメーターで構成され、セミコロン(;)で終了します。例えば、listen 80;
はNginxにポート80でリッスンするよう指示するディレクティブです。
⦿ コンテキスト
コンテキストは、ディレクティブをグループ化して、特定のセクションや条件下でのみ適用されるようにするためのものです。コンテキストは、{
と }
で囲まれたブロック内にディレクティブを記述することで定義されます。主なコンテキストには、http
, server
, location
などがあります。
⦿ 主なコンテキストの解説
# mainコンテキスト
# httpディレクティブ
http { # httpコンテキスト
# serverディレクティブ
server { # serverコンテキスト
listen 80; # listenディレクティブ
server_name example.com; # server_nameディレクティブ
# locationディレクティブ
location / { # locationコンテキスト
root /var/www/example.com; # rootディレクティブ
index index.html; # indexディレクティブ
}
# locationディレクティブ
location /images/ { # locationコンテキスト
root /var/www/example.com/images; # rootディレクティブ
}
}
}
設定ファイル👆の内容
設定ファイル👆の内容
今は、詳しい内容を理解する必要はありません。設定ファイルの書き方の雰囲気だけつかめればOKですが、一応解説をつけておきます。この設定では、example.com
へのHTTPリクエストをポート80で受け付け、ルートディレクトリとして /var/www/example.com
を使用します。また、/images/
へのリクエストに対しては /var/www/example.com/images
ディレクトリからファイルを提供します。
mainコンテキスト
main
コンテキストは、Nginx設定ファイルの最上位レベルに位置し、特定のコンテキストブロックに包含されないディレクティブの集まりです。これらのディレクティブは、Nginxサーバー全体に適用され、http
、server
、location
などの他のコンテキストで上書きされない限り、その設定が全般に影響します。main
コンテキストは最上位に位置しているため、わざわざ{}
で囲む必要はありません。
httpコンテキスト
http
コンテキストは、HTTPに特化した設定をグループ化するために使用されます。この中で指定されたディレクティブは、Nginxが扱うすべてのHTTP通信に適用されます。例えば、キャッシュの挙動や、ログファイルのパスなどを指定できます。
serverコンテキスト
server
コンテキストは、特定のドメインやポートに対する設定を定義します。複数の server
ブロックを定義することで、1つのNginxサーバーで複数のサイトをホストすることができます。server_name
や listen
ディレクティブを使用して、どのドメインやポートに対する設定かを指示します。
locationコンテキスト
location
コンテキストは、URIの特定のパターンに基づいてリクエストを処理するための設定を定義します。例えば、特定のパスへのリクエストに対して特定のファイルを返したり、プロキシサーバーを経由して処理を行うなどの設定が可能です。
▼ デフォルトのnginx.confを見てみよう
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
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;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
📝 デフォルトのnginx.confの中身を確認する方法
nginxをインストールすれば、デフォルトのnginx.confを確認できます。
後の事を考えて、docker-composeでnginxコンテナを立ち上げて、確認しましょう。
laravel-nginx/
├── nginx
│ └── Dockerfile
└── docker-compose.yml
networks:
laravel-nginx:
driver: bridge
services:
nginx:
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- '8080:80'
networks:
- laravel-nginx
FROM nginx:1.25.3-alpine3.18
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
docker compose up -d
docker compose exec nginx sh
cat /etc/nginx/nginx.conf
⦿ mainコンテキスト
-
user
- Nginxワーカープロセスが動作するユーザーを指定します
-
worker_processes
- Nginxが生成するワーカープロセスの数を指定します。autoに設定すると、Nginxは自動的に利用可能なCPUコアの数に基づいてワーカープロセスの数を決定します。これにより、パフォーマンスとスケーラビリティが最適化されます
-
error_log
- エラーログの出力先とログレベルを指定します。ここで指定されたファイルには、エラーメッセージや警告などが記録されます。ログレベル(この例ではnotice)を指定することで、どのレベルのログメッセージを記録するかを制御できます。ログレベルには「debug < info < notice < warn < error < crit < alert < emerg」順に高くなり、設定したレベル以上のログが出力されます
-
pid
- このディレクティブはNginxのメインプロセスのPID(プロセスID)をファイルに記録する場所を指定します。Nginxを再起動または停止する際にこのPIDファイルが使用されます
⦿ eventsコンテキスト
-
worker_connections
- このディレクティブは、1つのワーカープロセスが同時に開くことのできる最大接続数を指定します
- サーバーの同時接続数は
worker_processes×worker_connections
で決定されます。例えば、worker_processes
が4
に設定されている場合、全体での最大接続数は4×1024=4096
接続となります
⦿ httpコンテキスト
-
include
- このディレクティブは、他の設定ファイルを現在の設定ファイルに含めることを指示します。
/etc/nginx/mime.types
は、さまざまなファイルタイプに対するMIMEタイプの定義を含むファイルです。include /etc/nginx/conf.d/*.conf;
は、/etc/nginx/conf.d/
ディレクトリ内の全ての.confファイルを含めることを指示し、柔軟な設定管理を可能にします
- このディレクティブは、他の設定ファイルを現在の設定ファイルに含めることを指示します。
-
default_type
- MIMEタイプが明示的に指定されていない場合に使用されるデフォルトのコンテンツタイプを設定します。application/octet-streamは、特定のタイプが分からないバイナリデータを指す一般的なタイプです
-
log_format
- ログに記録される情報のフォーマットを定義します。
main
はこのフォーマット名を意味し、それ以降部分で具体的なフォーマットを指定しています
- ログに記録される情報のフォーマットを定義します。
-
access_log
- アクセスログの出力先と使用するログフォーマットを指定します。この場合、ログファイルは
/var/log/nginx/access.log
に保存され、log_formatで定義されたmain
フォーマットが使用されます
- アクセスログの出力先と使用するログフォーマットを指定します。この場合、ログファイルは
-
sendfile
- 静的コンテンツの配信時に、カーネルスペースからユーザースペースへのファイルコピーを回避し、効率を向上させるために
sendfile
システムコールを使用するかどうかを制御します。on
に設定することでパフォーマンスが向上します
- 静的コンテンツの配信時に、カーネルスペースからユーザースペースへのファイルコピーを回避し、効率を向上させるために
-
keepalive_timeout
- キープアライブ接続が閉じられるまでのタイムアウト時間(秒)を設定します。この値を適切に設定することで、クライアントとサーバー間の接続の再利用を促進し、通信の効率を向上させることができます
-
gzip
(コメントアウトされています)- HTTPレスポンスの圧縮を有効にするかどうかを制御します。コメントアウトされているため、この設定は無効です。有効化すると、ページのロード時間を短縮し、帯域幅の使用量を削減することができます
📝 log_formatについて深掘り
構文
log_format name 'string' ...;
- name
- ログフォーマットの名前です。この名前は、access_logディレクティブで参照され、どのフォーマットを使用するかを指定する際に用います
- 'string' ...:
- ログに記録される具体的なフォーマットを指定する文字列です。文字列内では、固定テキストと変数を組み合わせることができます。変数は$に続いて変数名が来る形式で、リクエストやレスポンスに関連する様々な値をログに含めることができます
変数の使用
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
この例では、mainという名前のログフォーマットが定義されており、以下の情報を含むログを生成します:
-
$remote_addr
: リクエストを送信したクライアントのIPアドレス -
$remote_user
: Basic認証で認証されたユーザー名(存在する場合) -
$time_local
: ローカルタイムゾーンに基づいたアクセス時間 -
$request
: リクエストライン(メソッド、パス、HTTPバージョン) -
$status
: レスポンスのHTTPステータスコード -
$body_bytes_sent
: クライアントに送信されたレスポンスのバイト数 -
$http_referer
: リファラーURL -
$http_user_agent
: ユーザーエージェント -
$http_x_forwarded_for
: プロキシ経由のリクエストの場合、オリジナルのクライアントIPアドレスを含むことがあります
Nginxはリクエスト、レスポンス、サーバー環境に関連する多くの変数を提供しています。これらの変数を使用して、ログに必要な情報を柔軟に含めることができます。詳細なリストや変数の説明については、Nginxの公式ドキュメントを参照してください。
■ FastCGI: Webサーバーとアプリケーションの橋渡し
FastCGIの説明に入る前に、Webサーバーとアプリケーションサーバー間の通信の基本をおさらいしましょう。Webサーバーソフトウェア(例えばnginx)は、インターネットからのリクエストを受け取り、それに応答する役割を持っています。しかし、動的なコンテンツを扱う場合、このWebサーバー単体ではリクエストを完結させることができません。そのため、アプリケーションサーバー(例えばPHPの実行環境)が必要となります。この二つのサーバー間の橋渡しをするのが、FastCGIの役割です。
FastCGIは、Webサーバーとアプリケーションサーバー間での効率的な通信を実現するプロトコルです。PHPの場合、この通信の効率化のためにPHP-FPM(FastCGI Process Manager)を利用します。PHP-FPMは、PHPの実行環境を管理し、FastCGIのプロトコルを通じてWebサーバー(例えばnginx)と通信します。この仕組みにより、PHPスクリプトの実行を効率的に行うことができ、アプリケーションのパフォーマンスを向上させることが可能になります。
ビルトインサーバーを使用していた時、このWebサーバーとアプリケーションサーバー間の橋渡しは、ほとんど意識されることがありませんでした。php artisan serveを実行すると、Laravelの開発環境が簡単に立ち上がり、ブラウザでアプリケーションを確認することができます。この時、PHPのビルトインサーバーが背後で動作していることは見えにくく、Webサーバーとアプリケーションサーバー間のやり取りがブラックボックス化していました。
FastCGIとPHP-FPMの役割
- FastCGI
- Webサーバーとアプリケーションサーバー間の通信プロトコル。効率的なプロセス管理と持続的な接続を提供し、アプリケーションの応答性を高めます
- PHP-FPM
- PHPの実行環境を管理するための高度なプロセスマネージャー。FastCGIプロトコルを使用してWebサーバーと通信し、PHPスクリプトの実行を効率化します
▼ 流れ
- Laravelドキュメントにあるnginxのserverディレクティブの設定項目について、理解する
- PHP-FPM上でLaravelアプリケーションを動かせるようにLaravelアプリケーション用のDockerfileを作成する
▼ Laravelドキュメントに記載されている設定項目について
Laravelのドキュメントには、nginxをWebサーバーとして利用する場合の、serverディレクティブの基本構成が紹介されています。まずは、これを理解し、必要に応じてカスタマイズしていくとよいでしょう。
server {
listen 80;
listen [::]:80;
server_name example.com;
root /srv/example.com/public;
add_header X-Frame-Options "SAMEORIGIN";
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/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
⦿ リスニングポート
-
listen 80;
- サーバーがIPv4アドレスでのリクエストをポート80でリッスンするように設定しています
-
listen [::]:80;
- サーバーがIPv6アドレスでのリクエストをポート80でリッスンするように設定しています
🤔 設定値の書き方がよくわからない
-
IPv4の場合:
- 全てのIPv4アドレスを受け入れる:
-
listen 80;
と記述すると、サーバーはポート80で全てのIPv4アドレスからのリクエストを受け入れます
-
- 特定のIPv4アドレスに制限する:
-
listen 192.168.1.1:80;
のように記述すると、サーバーはポート80で指定した 192.168.1.1 というIPv4アドレスからのリクエストのみを受け入れます
-
- 全てのIPv4アドレスを受け入れる:
-
IPv6の場合:
- 全てのIPv6アドレスを受け入れる:
-
listen [::]:80;
と記述すると、サーバーはポート80で全てのIPv6アドレスからのリクエストを受け入れます。[::] はIPv6アドレスの全範囲を指します
-
- 特定のIPv6アドレスに制限する:
-
listen [2001:db8::1]:80;
のように記述すると、サーバーはポート80で指定した 2001:db8::1 というIPv6アドレスからのリクエストのみを受け入れます
-
- 全てのIPv6アドレスを受け入れる:
このように、IPv4とIPv6の設定では、全てのアドレスからのアクセスを受け入れるか、特定のアドレスに制限するかを明示的に設定できます。IPv4ではポート番号のみを指定することで全アドレスをカバーし、IPv6では [::] を使用します。特定のアドレスに制限する場合は、そのアドレスを明確に記述します。
⦿ サーバー名
-
server_name example.com;
- この設定は、
example.com
というドメイン名でアクセスされたリクエストを処理するようサーバーに指示します
- この設定は、
⦿ ドキュメントルート
-
root /srv/example.com/public;
- サーバーがWebコンテンツを探す基本ディレクトリを指定します
⦿ インデックスファイルの指定
-
index index.php;
- ディレクトリにアクセスされた際にデフォルトで提供するファイルを指定します。ここでは index.php がデフォルトのインデックスファイルとして設定されています
⦿ セキュリティ関連ヘッダー
-
add_header X-Frame-Options "SAMEORIGIN";
- クリックジャッキング攻撃を防ぐために、ページが同じオリジンのフレーム内でのみ表示されるように設定します
-
add_header X-Content-Type-Options "nosniff";
- MIMEタイプのスニッフィングを防ぎます
🤔 そもそもヘッダーを追加する意味とは?
HTTPレスポンスのヘッダーにさまざまな項目を追加することで、ブラウザや他のクライアントに特定の動作を指示することができます。これらのヘッダーは、Webページのセキュリティを向上させたり、特定の動作を制御したりするために使用されます。
💡セキュリティヘッダーについてもっと詳しく
- X-Frame-Options:
- X-Frame-Options ヘッダーは、あるページが <iframe> や <frame>、または <object> タグ内で表示されることを許可するかどうかを制御します
- 例えば X-Frame-Options: SAMEORIGIN と設定すると、そのページは同じオリジンのドキュメント内でのみ表示でき、クリックジャッキング攻撃3を防ぐのに役立ちます
- X-Content-Type-Options:
- X-Content-Type-Options ヘッダーは、特に nosniff オプションを使用して、ブラウザがMIMEタイプを推測(スニッフィング)するのを防ぎます
- X-Content-Type-Options: nosniff と設定すると、ブラウザはサーバーから提供されたMIMEタイプの指示に従ってコンテンツを処理します。これにより、特定の種類の攻撃(例えば、悪意のあるスクリプトが正当なファイルタイプとして偽装されること)を防ぐのに役立ちます
⦿ ロケーション
Nginx設定ファイルにおけるlocation
ブロックは、特定のURLパターンに基づいてリクエストを処理するための方法やルールを定義するものです。location
ブロックを使用することで、異なるURLパターンに対して異なる設定や処理を適用できます。基本的な形式は以下の通りです:
location [パターン] {
# パターンにマッチした場合の設定
}
パターン
location
ブロックのパターンには、シンプルな文字列マッチングから正規表現を使用した複雑なパターンマッチングまで、さまざまな形式が使用できます。
- 通常の文字列マッチング 👉 例:
location /images/
- このタイプはリクエストされたURIが指定された文字列で始まるかどうかをチェックします。この例では、URIが
/images/
で始まる全てのリクエストに適用されます。マッチングは最も単純で、正確な文字列の一致を基にしています
- このタイプはリクエストされたURIが指定された文字列で始まるかどうかをチェックします。この例では、URIが
- 大文字小文字を区別する正規表現マッチング 👉
location ~ \.php$
-
~
は大文字小文字を区別する正規表現マッチングを意味します。この例では、URIが.phpで終わる全てのリクエストに適用されます(例えばfile.php)。正規表現はより複雑なパターンマッチングを可能にします
-
- 大文字小文字を区別しない正規表現マッチング 👉
location ~* \.jpg$
-
~*
は大文字小文字を区別しない正規表現マッチングを意味します。この例では、.jpg
(大文字小文字を問わず)で終わる全てのリクエストに適用されます
-
- 最長一致優先 👉
location ^~ /images/
-
^~
は、このロケーションブロックがマッチした場合、他の正規表現マッチングを無視して、このブロックを使用することを意味します
-
- 正確なマッチング 👉
location = /favicon.ico
-
=
は完全一致マッチングを意味します。この例では、リクエストURIが正確に/favicon.ico
と一致する場合にのみ適用されます。一致した場合は、このブロックの設定項目が最優先に適用されます
-
パターンマッチングの優先順位
- 🥇 正確なマッチング:
location = /path のような形式のブロックは、完全一致する場合に最優先されます。 - 🥈 正規表現マッチング:
location ~ /path や location ~* /path のような正規表現を使うブロックは、非正規表現のブロックより優先されます。ただし、複数の正規表現ブロックがマッチする場合、設定ファイル内で最初に見つかったものが使われます。 - 🥉 最長一致優先:
location ^~ /path のような形式のブロックは、URIとの最長一致を試みます。これは非正規表現ブロックの中で特に優先されます。 - 💩 一般的なマッチング:
location /path のような形式のブロックは、上記のいずれにも該当しない場合に適用されます。これらは設定ファイル内で上から順にマッチングが試みられます。
各locationディレクティブの内容
各locationディレクティブの内容をマッチの優先度順に説明していきます。
location = /favicon.ico { access_log off; log_not_found off; }
Laravelでは、ファビコンに設定したい画像を、publicディレクトリ直下にfavicon.ico
として格納しています。その画像を取得するための設定です。
location = /robots.txt { access_log off; log_not_found off; }
robots.txt
によって、クロール不要なコンテンツを制御し、クロールさせたいページにだけ効率良くクローラーを誘導することができます。そのrobots.txt
を取得するための設定です。
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
リクエストされたURLが .php
で終わる(つまり、PHPファイルに対するリクエスト)場合にマッチするロケーションブロックを定義しています。
-
fastcgi_pass
- FastCGIサーバーの待ち受けアドレスを指定します
-
fastcgi_param
- この行は、FastCGIプロセスに渡される
SCRIPT_FILENAME
パラメータの値を設定します。$realpath_root
は、リクエストされたファイルのルートディレクトリの絶対パスを示し、$fastcgi_script_name
はリクエストされたスクリプトのパスです。これにより、FastCGIプロセスは実際に実行すべきPHPファイルを正確に知ることができます
- この行は、FastCGIプロセスに渡される
-
include fastcgi_params;
- この行は、追加のFastCGIパラメータを含むファイルを指定します。fastcgi_params はNginxによって提供される標準のパラメータファイルであり、FastCGIプロセスに渡すべき一般的なパラメータが定義されています。これにより、スクリプト名、クエリストリング、リクエストメソッドなど、PHPスクリプトの実行に必要な情報がFastCGIプロセスに渡されます
location ~ /\.(?!well-known).* {
deny all;
}
.well-known
ディレクトリ4を除く、すべての隠しファイルおよび隠しディレクトリにアクセスを禁止するルールです。ここでの隠しファイルとは、名前がピリオド(.)で始まるファイルやディレクトリを指します。
location / {
try_files $uri $uri/ /index.php?$query_string;
}
上記のどのlocation
ディレクティブにもマッチしなかった場合に、ここにたどり着きます。try_files
ディレクティブは、指定されたファイルまたはディレクトリが存在するかどうかを順に検証し、最初に見つかったリソースに基づいてリクエストを処理します。最後までリソースが見つからない場合は、最後の引数の処理をします。本例では次のように動作します:
-
$uri
Nginxはまず、リクエストされたURIが実際のファイルとして存在するかを確認します。例えば、/example というリクエストがあった場合、対応する /example という名前のファイルがドキュメントルートに存在するかをチェックします。 -
$uri/
次に、リクエストされたURIがディレクトリとして存在するかを確認します。これは、リクエストがディレクトリに対して行われ、そのディレクトリが存在する場合に、そのディレクトリのインデックスファイル(例:index.html)を自動的に提供するために使用されます -
/index.php?$query_string
上記のどちらも見つからない場合、リクエストは /index.php にフォワードされ、元のリクエストのクエリ文字列が付加されます。これにより、フロントコントローラーパターンを使用するアプリケーションで、すべてのリクエストを一つのPHPファイル(この場合はindex.php)に集約し、そのファイル内でリクエストのルーティングや処理を行うことが可能になります
■ nginx×Laravelのローカル開発環境構築
まずは、php-fpmで動作するLaravelアプリケーションを作成してます。
Docker Installation Using Sailに従って、nginx-laravel
ディレクトリ配下にapplication
というLaravelプロジェクトを作成します。
curl -s "https://laravel.build/application" | bash
そこに、下記のような構成になるように、nginx
ディレクトリやDockerfile
、php.ini
などを追加します。
laravel-nginx/
├── application
│ ├── ...Laravelのディレクトリ群
│ ├── Dockerfile
│ └── php.ini
├── nginx
│ ├── Dockerfile
│ └── nginx.conf
└── docker-compose.yml
それぞれファイルを次のようにします。
FROM php:8.3-fpm-alpine3.19
WORKDIR /var/www/application
COPY ./ ./
RUN curl -sLS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
RUN composer install
COPY php.ini /usr/local/etc/php/conf.d/zz0-app.ini
EXPOSE 9000
CMD ["php-fpm"]
[PHP]
log_errors_max_len = 0
default_charset = 'UTF-8'
default_mimetype = ''
[opcache]
opcache.enable_cli=1
opcache.revalidate_freq = 0
opcache.validate_timestamps = 1
[Session]
session.cookie_secure = 1
session.cookie_httponly = 1
[MySQLi]
mysqli.allow_persistent = 0
[Date]
date.timezone = 'UTC'
FROM nginx:1.25.3-alpine3.18
COPY ./nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
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;
keepalive_timeout 65;
#gzip on;
# 💡default.confを読み込むとそちらのserverディレクティブがlocalhostにマッチしてしまうので、includeしない
# include /etc/nginx/conf.d/*.conf;
server {
listen 80;
listen [::]:80;
server_name localhost;
# 💡 サーバールートを変更
root /var/www/application/public;
add_header X-Frame-Options "SAMEORIGIN";
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$ {
# 💡 php-fpmのコンテナに向き先を変更
fastcgi_pass application:9000;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
}
networks:
nginx-laravel:
driver: bridge
services:
application:
build:
context: ./application
dockerfile: Dockerfile
ports:
- '9000:9000'
volumes:
- ./application:/var/www/application
- nginx-laravel-vendor:/var/www/application/vendor
networks:
- nginx-laravel
nginx:
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- '80:80'
depends_on:
- application
networks:
- nginx-laravel
volumes:
nginx-laravel-vendor:
driver: local
docker compose build
docker compose run application php artisan key:generate
docker compose up -d
http://localhostにアクセスすると
■ 参考