[AWS EC2]nginxとphp-fpm周りでエラーが発生した場合の解決策

## はじめに
この記事はプログラミング初学者による備忘録用の記事であり、また、少しでも他の初学者のお役に立てればと思い書いています。

今回は、EC2×Nginx×php-fpm×Laravelで開発中に、ブラウザ上で``http://EC2インスタンスのパブリックIPアドレス/login``に接続後、ログイン画面の表示に成功したものの、ユーザー登録を実行した際に、**404 Not Found**と表示され非常に悩まされたので、解決に至るまでに試したことを記録しておきたいと思います。

間違いなどがございましたら、ご指摘のほどよろしくお願い致します。

## エラー内容
ブラウザ上で、``http://EC2インスタンスのパブリックIPアドレス/login``に接続後、Laravelアプリケーションのログイン画面の表示に成功したものの、ユーザー登録を実行した際に``404 Not Found``が表示されユーザー登録に失敗した。

今後、同様のエラーに悩まされないよう、解決するまでに試したことを記録しておきたいと思います。


## 1.php-fpmとnginxの接続を確認
ドキュメントルート``/usr/share/nginx/html/``にphpinfo.phpのテストファイルを追加して、PHP Versionに関する詳細画面が表示されるかどうかを試す。
下記のコマンドを実行して、ドキュメントルートでphpが実行できるかを確認します。

```
# ec2-userでphpinfo.phpをvi起動で作成
[ec2-user@ip-###-##-##-## ~]$ sudo vi /usr/share/nginx/html/phpinfo.php

# vi起動後、/usr/share/nginx/html/phpinfo.php上で下記のコードを入力、保存
<?php phpinfo(); ?> 
```
### ブラウザで``http://EC2のパブリックIPアドレス/phpinfo.php``に接続
接続後、PHPVersionの詳細画面が表示されれば、php-fpmとnginxの接続は成功です。
エラーが起きた際は、``/etc/nginx/nginx.conf``と``/etc/php-fpm.d/www.conf``の設定を再確認して下さい。

![スクリーンショット 2022-03-02 17.21.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891113/c8bcae62-ad2d-f8db-9284-fe5532441036.png)

## 2.``/etc/php-fpm.d/www.conf``の実行ユーザーを確認
Laravelアプリケーションを動かす際は、権限絡みで問題が発生しないように**プールのユーザーとグループ**を実行ユーザーに変更しておく必要があります。

動かしたいLaravelアプリケーションを、EC2インスタンス上のどの実行ユーザーのホームディレクトリ配下にインストールしたかを確認し、状況に合わせて``/etc/php-fpm.d/www.confのユーザーとグループ``をEC2インスタンスの実行ユーザー名に変更します。



```/etc/php-fpm.d/www.conf
# 略

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
; RPM: apache user chosen to provide access to the same directories as httpd
user = 実行ユーザー名(nginx) ; #========この行をapacheから実行ユーザー名に変更します
; RPM: Keep a group allowed to write in log dir.
group = 実行ユーザー名(nginx) ; #========この行をapacheから実行ユーザー名に変更します
```

## 3.php-fpmとnginxの通信方法の設定を確認
**TCP**か**UNIXドメインソケット**のどちらで通信しているかを確認しておく必要があります。
php-fpm側の設定では、``/etc/php-fpm.d/www.confのlistenディレクティブ``で通信方法が定義されており、**TCP**か**UNIXドメインソケット**を確認して、パスの内容を``nginx.confファイルのfastcgi_pass``と合わせる必要があります。

下記のように、**UNIXドメインソケット**を利用した``listen = /run/php-fpm/www.sock``であれば、nginx.confファイルの``fastcgi_pass``には``unix:/run/php-fpm/www.sock``と指定する必要があります。
※TCPの場合はlisten = 127.0.0.1:9000

```/etc/php-fpm.d/www.conf
; The address on which to accept FastCGI requests.
; Valid syntaxes are:
;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific IPv4 address on
;                            a specific port;
;   '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
;                            a specific port;
;   'port'                 - to listen on a TCP socket to all addresses
;                            (IPv6 and IPv4-mapped) on a specific port;
;   '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = /run/php-fpm/www.sock #=======TCPかUNIXドメインソケットを確認する
```
**UNIXドメインソケット**の場合、下記のようにnginx.confファイルの``fastcgi_pass``には``unix:/run/php-fpm/www.sock``を指定します。

```/etc/nginx/nginx.conf
location ~ \.php$ {
        fastcgi_pass   unix:/run/php-fpm/www.sock;
        # 略
        }
```

## 4.``/etc/php-fpm.d/www.conf``のlisten.ownerなどを変更しているかを確認する
php-fpmとnginxの通信方法で、**UNIXドメインソケット**を使用する場合は``listen.owner``などを変更する必要があり、変更していない場合、php-fpm.sockのパーミッションはnginxが読めない状態になります。

下記のように変更することで、php-fpm.sock の所有ユーザ・グループが変更されてnginxと接続できる状態になります。

```/etc/php-fpm.d/www.conf
; Set permissions for unix socket, if one is used. In Linux, read/write
; permissions must be set in order to allow connections from a web server.
; Default Values: user and group are set as the running user
;                 mode is set to 0660
listen.owner = ユーザー名(nginx) #=====セミコロン(;)を消して実行ユーザー名(nginx)に変更します
listen.group = ユーザー名(nginx) #=====セミコロン(;)を消して実行ユーザー名(nginx)に変更します
listen.mode = 0660 #=====セミコロン(;)を消します
```
``補足``
**listen.owner**と**listen.group**では、UNIXドメインソケットを利用する場合、ソケットのオーナー/グループを指定します。
Webサーバーからリクエストを受け付けるには、Webサーバーがソケットに対して読み書き可能な状態が必要とされます。



## 5.``/etc/nginx/nginx.conf``の設定を確認
ここでは、主にphp-fpmとの連携で重要な箇所を確認していきます。

確認すべき箇所は下記の通りです。

**・root**:ドキュメントルートの指定が間違っていないかを確認する。
<br>
**・location**:求められている``location / {処理}``が設定できているかを確認する。

下記の``try_files $uri $uri/ /index.php?$query_string;``の処理内容は、

・リクエストされたURIにファイルが存在するかを確認(``$uri``の部分)
・ファイルが無ければ、リクエストされたURIにディレクトリが存在するかを確認(``$uri/``の部分)
・ディレクトリが存在しなければ、index.phpに内部リダイレクトする(/index.php?$query_stringの部分)
となっています。
<br>
**・location ~ \.php$**:拡張子がphpであるファイルに対して行う処理を確認します。
・location内にrootパラメータを記述していないかを確認する。

・fastcgi_passが正しく指定されているかを確認する。**UNIXドメインソケット**の場合、``unix:/run/php-fpm/www.sock``または``unix:/var/run/php-fpm/www.sock``を指定しているかを確認する。TCPの場合は``fastcgi_pass= 127.0.0.1:9000``と指定する。

・fastcgi_paramが正しく指定されているかを確認する。``index.php``をドキュメントルートに設置するのであれば、``SCRIPT_FILENAME $document_root$fastcgi_script_name;``と指定する必要があります。


```/etc/nginx/nginx.conf
# 略
root         /home/実行ユーザー名/特定のディレクトリ/public;

location / {
            try_files $uri $uri/ /index.php?$query_string;
        }

location ~ \.php$ {
        fastcgi_pass   unix:/run/php-fpm/www.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
}
```

## 終わりに
私の場合、上記5つを試したところ、``/etc/php-fpm.d/www.conf``のlistenの値と``/etc/nginx/nginx.conf``のfastcgi_passの値が一致していなかった為、エラーが発生していました。
この記事が少しでもお役に立てれば嬉しいです。

## 参考文献
[nginx docs](https://nginx.org/en/docs/http/ngx_http_core_module.html)
[Laravel 6.x デプロイ](https://readouble.com/laravel/6.x/ja/deployment.html)
[PHP docs FastCGI Process Manager (FPM)](https://www.php.net/manual/ja/install.fpm.php)