Docker で nginx + PHP-FPM コンテナを作る方法

この記事は最終更新日から 1年以上 が経過しています。

近年 Web サーバーは、Apache の代わりに nginx もよく使用されています。 お仕事で使用している方も多いのではないでしょうか。 nginx から PHP を使用したい場合、FPM(FastCGI Process Manager)版の PHP が必要になります。 Docker で nginx + PHP-FPM コンテナを作成してみましょう。

Docker で nginx コンテナを作る

コンテナのイメージは、下記の公式イメージを使用します。 イメージのバージョン(タグ)はいろいろありますが、特にこだわりが無いなら最新版(latest)で良いと思います。

nginx は Web サーバーですので、コンテナ側のポート番号は 80 番です。 ホスト側から Web ブラウザ(Chrome など)で接続できるよう、コンテナ側のポート 80 番へのマッピングを設定しましょう。 ホスト側のポート番号は、他で使用されていないものなら何番でも良いと思います。

ドキュメントルートはデフォルトだと "/usr/share/nginx/html" になります。 ホストのディレクトリとバインドマウントして、そこに HTML ファイルを置いて動作確認してみましょう。

例:ホストの "./html" を、コンテナの "/usr/share/nginx/html" にバインドマウントする場合
docker-compose.yml
version: "3.8"
services:

  # nginx コンテナ
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./html:/usr/share/nginx/html

nginx の設定ファイルを使用する

nginx の設定を変更したい場合は、nginx の設定ファイルを使用すると良いでしょう。

nginx の設定ファイルの詳しい書き方はここでは記載しませんが、 基本的な書き方としては {} で囲ってブロックになること、 終端には ; が必要になること、 # で1行コメントになることを覚えておくと良いでしょう。

nginx の設定ファイルの場所は "/etc/nginx" ディレクトリの配下です。 nginx の設定ファイルは複数のファイルで構成されています。 全体の設定は "/etc/nginx/nginx.conf" ファイルで、 そこからサーバーの設定として "/etc/nginx/conf.d" ディレクトリ配下の ".conf" ファイルが読み込まれるようになっています。

nginx の全体の設定である "/etc/nginx/nginx.conf" の方には大事な設定が書かれているので、変更する際は注意が必要です。 基本的にはサーバーの設定の方を変更する機会が多いと思いますので、そちらのファイルを変更しましょう。 デフォルトのサーバーの設定のファイルは "/etc/nginx/conf.d/default.conf" です。

例:nginx 全体の設定ファイル
/etc/nginx/nginx.conf
(省略)

events {
    (省略)
}

http {
    (省略)

    include /etc/nginx/conf.d/*.conf;
}
例:デフォルトのサーバーの設定のファイル
/etc/nginx/conf.d/default.conf
server {
    listen 80;

    (省略)
}

ドキュメントルートを変更する

デフォルトのサーバーの設定のファイルを変更してドキュメントルートを変更してみましょう。 ドキュメントルートを変更するには root を使用します。

例:ドキュメントルートを "/path/to/new/root" に変更する場合
default.conf
server {

    # ドキュメントルート
    root /path/to/new/root;
}

バインドマウントを使用する

nginx の設定ファイルを頻繁に変更するなら、バインドマウントを使用すると良いでしょう。 なお、nginx の設定ファイルを変更した場合は、反映させるためにコンテナの再起動(正確には nginx の再起動)が必要になるので注意してください。

例:ホストの "./default.conf" を、コンテナの "/etc/nginx/conf.d/default.conf" にバインドマウントする場合
docker-compose.yml
version: "3.8"
services:

  # nginx コンテナ
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./default.conf:/etc/nginx/conf.d/default.conf
      - ./html:/path/to/new/root

Dockerfile を使用する

nginx の設定ファイルをあまり変更しないのなら、バインドマウントではなく Dockerfile を使用すると良いでしょう。 Dockerfile の中で、nginx の設定ファイルをコンテナにコピーします。 ついでに chmod コマンドでパーミッションを設定しておくと良いでしょう。 なお、nginx の設定ファイルを変更した場合は、反映させるためにコンテナをビルドし直す必要があります。

例:ホストの "./nginx-custom/default.conf" を、コンテナの "/etc/nginx/conf.d/default.conf" にコピーする場合
./nginx-custom/Dockerfile
FROM nginx:latest

# nginx のデフォルトのサーバーの設定ファイルを配置
COPY ./default.conf /etc/nginx/conf.d/default.conf
RUN chmod 644 /etc/nginx/conf.d/default.conf
docker-compose.yml
version: "3.8"
services:

  # nginx コンテナ
  nginx:
    build: ./nginx-custom
    ports:
      - 8080:80
    volumes:
      - ./html:/path/to/new/root

Docker で PHP-FPM コンテナを作る

HTML、CSS、JavaScript、画像ファイルなどの静的なファイルは nginx だけで処理を行うことができますが、PHP ファイルは実行することができません。 nginx から PHP を使用するためには、FPM(FastCGI Process Manager)版の PHP が必要になります。 PHP が使用できるように PHP-FPM のコンテナを作成してみましょう。

コンテナのイメージは、下記の PHP の公式イメージを使用します。 イメージのバージョン(タグ)はいろいろありますが、今回は PHP 8.2 の FPM 版である 8.2-fpm を使用します。 PHP のバージョンを変更したい場合は、別のタグに変更してください(例:PHP 8.1 の場合は 8.1-fpm)。

なお、PHP-FPM コンテナに PHP のエクステンションをインストールする方法や、PHP の設定ファイルを使用する方法は、 「Docker で Apache + PHP コンテナを作る方法」に記載している方法と同じですので、 そちらを参考にしてください。

PHP-FPM コンテナには、nginx コンテナから PHP ファイルのリクエストが来ますので、実行したい PHP ファイルを置いておく必要があります。 バインドマウントなどを使用して、PHP ファイルを配置しておきましょう。 配置場所は nginx のドキュメントルートと同じにしておくとわかりやすくて良いと思います。

nginx コンテナからのリクエストを待ち受けるポート番号は 9000 番です。

例:ホストの "./html" を、コンテナの "/usr/share/nginx/html" にバインドマウントする場合
docker-compose.yml
version: "3.8"
services:

  # nginx コンテナ
  nginx:
    (省略)

  # PHP-FPM コンテナ
  php-fpm:
    image: php:8.2-fpm
    volumes:
      - ./html:/usr/share/nginx/html

nginx コンテナと PHP-FPM コンテナをつなぐ

nginx コンテナと PHP-FPM コンテナを作成しましたが、このままだと2つのコンテナはバラバラの状態です。 この2つのコンテナをつないであげる必要があります。 具体的には、nginx コンテナで受け取ったリクエストを、FastCGI を使用して PHP-FPM コンテナに転送します。

PHP-FPM コンテナにリクエストを転送する

nginx のサーバーの設定ファイルを下記のように書き換えます。

location で、どの URL に対する設定なのかを指定できます。 指定する URL は、デフォルトでは前方一致での指定になるですが、~ を使用すると正規表現で指定することができます。

$document_root$fastcgi_script_name など、$ から始まっているものは変数です。 例えば $document_root には、root で指定したドキュメントルートの値が入っています。

FastCGI を使用して接続する接続先の情報は fastcgi_pass で指定します。 TCP ポートを使用する方法と、Unix ソケットを使用する方法があるのですが、ここでは TCP ポートを使用する方法を説明します。 ホスト名として docker-compose.yml で定義しているサービス名(つまり、services 項目で指定しているキー)を使用できます。 上記の例では、ホスト名として "php-fpm" が使用できます。 PHP-FPM コンテナがリクエストを待ち受けているポート番号は 9000 番ですので、ポート番号には 9000 番を指定します。

fastcgi_param で PHP-FPM コンテナに渡すパラメーターを指定します。 デフォルトのパラメーターは "/etc/nginx/fastcgi_params" ファイルに用意されていますので、include で読み込んで使用します。

PHP-FPM コンテナで実行する PHP ファイルの名前は、SCRIPT_FILENAME パラメーターで指定します。 なお、実行する PHP ファイルは、PHP-FPM コンテナに置いておく必要があるので注意してください。

例:".php" ファイルへのリクエストを、PHP-FPM コンテナに転送する場合
default.conf
server {

    # ドキュメントルート
    root /usr/share/nginx/html;

    # 全ての PHP ファイル
    location ~ \.php$ {

        # PHP ファイルが nginx コンテナに存在しない場合は、
        # PHP-FPM コンテナに転送せずに 404 Not Found にする
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }

        # FastCGI で PHP-FPM コンテナへ転送
        fastcgi_pass php-fpm:9000;

        # デフォルトの FastCGI パラメーター
        include fastcgi_params;

        # PHP-FPM コンテナで実行する PHP ファイルの名前
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

フロントコントローラーパターンを使用する

PHP のフレームワークでは、全てのリクエストを "/index.php" で処理するというフロントコントローラーパターンを使用しているものが多いです。 Apache を使用している場合は、mod_rewrite モジュールの RewriteRule を使用して URL を "/index.php" に書き換えていたと思います。

例:Apache で mod_rewrite を使用し、"/index.php" に書き換える場合
.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

これと同じことを nginx でもできるように設定ファイルを変更してみましょう。

なお、nginx の設定ファイルはかなり自由度が高く、いろいろな書き方ができます。 下記の記述はほんの一例にすぎませんので、ご自身の環境に合わせて設定してください。

try_files を使用すると、ファイルが存在しているかどうかを確認することができます。

例:ファイルが存在しないリクエストを全て "/index.php" で実行する場合
default.conf
server {

    # ドキュメントルート
    root /usr/share/nginx/html;

    # 全てのリクエスト
    location / {

        # リクエストされたファイルが存在しなければ、
        # フロントコントローラーに内部リダイレクト
        try_files $uri /index.php?$query_string;
    }

    # 全ての PHP ファイル
    location ~ \.php$ {

        # nginx コンテナで PHP ファイルの存在確認はしない
        # 全てフロントコントローラーにまかせる

        # FastCGI で PHP-FPM コンテナへ転送
        fastcgi_pass php-fpm:9000;

        # デフォルトの FastCGI パラメーター
        include fastcgi_params;

        # PHP-FPM コンテナで実行する PHP ファイルの名前
        # - 全てのリクエストをフロントコントローラーで実行
        fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    }
}

おまけ:バーチャルホストを使用する

複数のサイトを Docker で動作させたい場合、 1つのサイトごとに1つずつコンテナを作っても良いのですが、 それだと CPU やメモリなどの消費リソースが増えてしまい、 スペックの低い PC だと動作させるのが大変かもしれません。 そういった場合は、nginx のバーチャルホストを使用すると良いでしょう。 バーチャルホストを使用すると複数のサイトを1つのコンテナで動作させることができます。

例として、2つのサイトを使えるようにしてみます。

デフォルトのサイト設定を無効化する

まずはデフォルトのサイト設定が邪魔にならないよう無効化しておきましょう。 無効化しなくても良いと言えば良いのですが、バーチャルホストを使って複数サイトを管理するならおそらく使用しないと思います。

デフォルトのサーバーの設定のファイルは "/etc/nginx/conf.d/default.conf" ですので、そのファイルを読み込まないようにします。 削除するのもあれなので、念のためにファイル名を変更して置いておくことにします。 設定ファイルとして読み込まれるのは拡張子が ".conf" のファイルだけなので、拡張子 ".bak" を付けて無効化します。

Dockerfile
FROM nginx:latest

# デフォルトのサイト設定を無効化
RUN mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak

各サイトの設定を追加する

次にバーチャルホストを使用したい各サイトの設定ファイルを追加します。

nginx の設定ファイルは最初からバーチャルホストに対応しています。 各サイトの設定ファイルを "/etc/nginx/conf.d" ディレクトリの配下に置くだけです。 設定ファイルの server ブロックが1つのサーバー(つまりホスト)の扱いなので、 1つのファイルに複数の設定を記述することもできるのですが、ファイルは分けておいた方が良いでしょう。 ホスト名は server_name で指定できます。

サイトの設定ファイルはアルファベット順に読み込まれます。 優先順位を付けたい場合は、ファイルの名前の先頭に番号を付けておくと良いでしょう。 どのサイトのホスト名にも一致しない URL が指定された場合、最初に読み込まれた設定ファイルのサイトが表示されます。

例:サイト1の設定ファイル(ホスト名は "site1.localhost")
./nginx-custom/001-site1.conf
server {

    # ホスト名
    server_name site1.localhost;

    # ドキュメントルート
    root /path/to/site1/root;
}
例:サイト2の設定ファイル(ホスト名は "site2.localhost")
./nginx-custom/002-site2.conf
server {

    # ホスト名
    server_name site2.localhost;

    # ドキュメントルート
    root /path/to/site2/root;
}
例:サイト1の設定ファイルと、サイト2の設定ファイルを追加
./nginx-custom/Dockerfile
FROM nginx:latest

# デフォルトのサイト設定を無効化
RUN mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak

# サイト1の設定を追加
COPY ./001-site1.conf /etc/nginx/conf.d/001-site1.conf
RUN chmod 644 /etc/nginx/conf.d/001-site1.conf

# サイト2の設定を追加
COPY ./002-site2.conf /etc/nginx/conf.d/002-site2.conf
RUN chmod 644 /etc/nginx/conf.d/002-site2.conf

各サイトのドキュメントルートにファイルを配置する

最後に各サイトのドキュメントルートにバインドマウントして、表示したいファイルを配置します。

例:2つのサイトのドキュメントルートにバインドマウント
docker-compose.yml
version: "3.8"
services:

  # nginx コンテナ
  nginx:
    build: ./nginx-custom
    ports:
      - 8080:80
    volumes:
      - ./site1_html:/path/to/site1/root
      - ./site2_html:/path/to/site2/root

なお、バーチャルホストで使用する URL のホスト名は hosts ファイルなどで、ローカルホスト(例:"127.0.0.1")に名前解決する必要があるので注意してください。 また、ホスト側のポート番号を 80 番以外にしている場合は、URL にポート番号を付けるのを忘れないようにしましょう。 例えば、上記の例のような設定だと、サイト1にアクセスするURLは "http://site1.localhost:8080/"、サイト2にアクセスするURLは "http://site2.localhost:8080/" のようになります。

参考サイト

関連記事

Docker で開発環境を作るのって結構大変です。構成を気軽に組み替えたりできるため自由度が高いですが、その分必要になる知識も多いですし、必要な作業も多いです。まずは、XAMPP でおなじみの Apache と PHP を組み合わせた Web サーバーを作るところから始めてみましょう。Docker で Apache + ...
Docker は、構成を気軽に組み替えたりできるので、とても便利ですよね。Windows で Docker を使って開発している方も多いと思うのですが、個人的にはどうしても気が乗らない理由がありました。それは処理速度です。遅い。遅すぎる。めちゃくちゃ遅い。つらい。耐えられない。。。ということで調査しました。いろいろと調 ...
最近では、アプリケーションの実行環境の構築に Docker を使うことも珍しくなくなりました。Docker は便利ではあるのかもしれませんが、難しく感じて敬遠されている人もいるのではないでしょうか。その感覚はおそらく間違っていません。実際、知れば知るほど奥が深い技術だと感じてしまいます。もはや沼というか深淵を覗いている ...

記事検索

最新記事

人気記事

RSSフィード

フィードバック

要望などあれば、お気軽にどーぞ。 不具合やバグを発見した場合も、連絡をいただけると助かります。

匿名でフィードバックする
匿名でフィードバックする

要望などあれば、お気軽にどーぞ。 不具合やバグを発見した場合も、連絡をいただけると助かります。

なお、このフォームから入力された内容について、管理者から返信はできませんので注意してください。 もし、管理者からの返信が必要であれば、X(旧 Twitter) もしくは、お問い合わせより、お願いします。