[homebrew] M1 MacでnginxのCGIを動かす

前提：
1. localhostへアクセスしてCGIを動作させる
1. homebrewがインストールされている([here](https://brew.sh/ja/))
1. nginxがhomebrewを利用して既にインストールされている``brew install nginx``

最初の時点でnginxが起動している必要はありません。
初学者につき、sudoやchmod 777を多用しますが、ご容赦ください。
個人的な試作のみで利用するのが良いと思います。

## ステップ1: CGI実行に必要なパッケージのインストール
以下2つのツールをインストールします。
- fcgiwrap
- spawn-fcgi

以下のコマンドを利用してください。
```
brew install fcgiwrap spawn-fcgi
```
[fcgiwrap]
CGIを高速安全に実行する外部ツール。NginxとCGIスクリプトの間の接続を提供する。[wiki](https://ja.wikipedia.org/wiki/FastCGI)
[spawn-fcgi]
fcgiwrapを起動する。これによってNginxからfcgiwrapにアクセスできるようになる。

## ステップ2: ディレクトリの作成と権限の変更
以下2つのディレクトリを作成します。
①cgiの実行ファイルを保存するディレクトリ
②cgiとnginxをつなげるソケットを保存するディレクトリ

ではまず①から。ディレクトリの権限が動作に影響を及ぼすので、ガイドに沿って行ってください。
```
cd /opt/homebrew/Cellar/nginx/1.25.4/
```
```
mkdir cgi-bin
```
```
chmod 777 cgi-bin
```

次に②です
```
cd /opt/homebrew/Cellar/nginx/1.25.4/
```
```
mkdir sock
```
```
chmod 777 sock
```
これでディレクトリ作成と権限の変更は完了。

## ステップ3: cgiの実行ファイルを作成

以下の2つのファイルを、指定する名称と場所で作成してください。
#### ファイル名称「form.py」
``/opt/homebrew/Cellar/nginx/1.25.4/cgi-bin/``にファイルを作成し、以下の内容を記載してください。

```
#!/opt/homebrew/bin/python
import cgi
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
print("[Python CGI]",file=sys.stderr)
print('Content-Type: text/html; charset=UTF-8\n')
html_body = """
<h1>[Python3 CGI]</h1>
<h2>area01 = "%s"</h2>
<h2>area02 = "%s"</h2>
"""
form = cgi.FieldStorage()
area01 = form.getvalue('area01', '')
area02 = form.getvalue('area02', '')
print(html_body % (area01, area02))
```

#### ファイル名称「form_py.html」
``/opt/homebrew/Cellar/nginx/1.25.4/html``にファイルを作成し、以下の内容を記載してください。
```
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Python CGI Form</title>
  <head>
  <body>
    <form action="http://localhost:8100/form.py" method="post">
    <input type="text" name="area01"> <BR />
    <input type="text" name="area02"> <BR />
    <input type="submit" name="submit">
  </form>
  </body>
</html>
```

## ステップ4: fcgiwrapの設定

spawn-fcgiとfcgiwrapを連携させてバックグラウンドで実行します。
コマンドは以下です。
```
sudo -u _www spawn-fcgi -f /opt/homebrew/Cellar/fcgiwrap/1.1.0/sbin/fcgiwrap -d /opt/homebrew/Cellar/nginx/1.25.4/cgi-bin/ -s /opt/homebrew/Cellar/nginx/1.25.4/sock/cgi.sock
```

### コマンドの説明
#### sudo -u _www
ユーザー："_www"としてこの操作を実行します、という宣言です。
nginxのworkerprocessの起動ユーザーと同じユーザー名に設定します。（nginxの設定は後で説明）

#### オプション-fに続く引数
brewでインストールしたfcgiwrapの実行ファイルの場所を示しています。
``brew info fcgiwrap``とコマンドを打つと、どのディレクトリにfcgiwrap用のスペースが確保されたかわかります。例：``/opt/homebrew/Cellar/fcgiwrap/1.1.0``
このディレクトリのさらに深いところ、``./sbin/``にfcgiwrapの実行ファイルがあると思います。

#### オプション-dに続く引数
cgiのスクリプトファイル(form.pyなど)を保存するルートディレクトリです。
nginxのconfigure Fileでいう[root]のような意味ですね。
任意の場所を選ぶことができます。

#### オプション-sに続く引数
cgi.sock(名称は任意)は、fcgiwrapとnginxが通信するためのソケットです。
このコマンドを実行すると、ファイルは自動的に作成されます。
nginxがcgiスクリプトを実行する時には、このファイル（ソケット）を通して、fcgiwrapにデータを送出します。そしてcgiスクリプトの実行結果はこのソケットを通して、nginxに返送されます。
ソケットファイルはグラフィカル表示しても見えませんが、``ls``コマンドをうてば見えます。


## ステップ5: Nginxの設定
Nginxの設定ファイル（/opt/homebrew/etc/nginx/nginx.conf）を編集して、CGIスクリプトを処理するための設定を追加します。

nginx.confを以下に書き換えてください。
```
user _www;

error_log  logs/error.log;
error_log  logs/error.log  notice;
error_log  logs/error.log  info;
error_log  logs/error.log  debug;

events {
    worker_connections  1024;
}

http {
    keepalive_timeout  65;
    server {
        listen       8100;
        server_name  localhost;


        location / {
            root   html;
            index  index.html index.htm;
            limit_except GET POST{
                deny  all;
            }
        }

        location = /form.py{
            root           /opt/homebrew/Cellar/nginx/1.25.4/cgi-bin;
            fastcgi_pass   unix:/opt/homebrew/Cellar/nginx/1.25.4/sock/cgi.sock;
            include        fastcgi_params;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
```
### 設定ファイルの記述の説明
ポイントを絞って設定ファイルの記述を説明します。
#### user _www
ユーザー名：_wwwがworkerプロセスの実行者です、という意味です。
fcigwrapの設定でも出てきましたね。この2つのユーザーは同じにしてください。異なると、権限エラーになる可能性があります。
#### error_log xxx
fcgiwrapとの接続に問題があった場合に、logへエラーを出力させるようにします。
デバック用ですね。
[error_logの場所はこちら](https://qiita.com/jizots/items/36199d654c3971009a1b)
#### location = /form.py
URIが~/form.pyと完全一致した場合に、このlocationの情報が利用されます。
#### root /opt/~~
サーバー側のリソースの場所です。
~/form.pyへアクセスがあったときに、このデータ（先に作ったcgiスクリプト）を実行します。
#### fastcgi_pass unix:/opt/~~
nginxとfcgiwrapが情報をやり取りする、ソケットファイルの保存場所です。
先ほど作成したソケットへのフルパスを記載します。
unix:~と書き出しているのは、同じホストのunixのソケットを利用した通信であることを示しています。

## ステップ6: Nginxの再起動
変更を適用するためにNginxを(再)起動します。
```
//起動の場合
sudo nginx
```
```
//再起動の場合
sudo nginx -s reload
```
これで、Nginxを介してCGIスクリプトを実行する設定が完了しました。
ブラウザから[http://localhost:8100/form_py.html](http://localhost:8100/form_py.html)にアクセスして、空欄を埋め、スクリプトが正しく実行されるかを確認してください。

## ステップ7: エラーになる場合
#### error_logを確認する
[error_log](https://qiita.com/jizots/items/36199d654c3971009a1b)には、nginxがどのように処理をしようとしているのかが細かく出力されます。
ファイルが見つからない、実行の権限がない、などがわかるのでかなり参考になります。
#### fcgiwrapの実行ユーザーを確認する
``ps aux | grep fcgiwrap``で実行ユーザーが「_www」になっているか確認してください。
もし違う場合は、最後に説明するクリーンアップを行い、ステップ3からやり直してください。
#### nginxのworkerプロセスの実行ユーザーを確認する
``ps aux | grep nginx``で実行ユーザーが「_www」になっているか確認してください。
もし違う場合は、最後に説明するクリーンアップを行い、ステップ3からやり直してください。

#### 503エラーの場合（もう一息の状態です）
form.pyの1行目を書き換えてみてください。
``#!/opt/homebrew/bin/python``の場合、あなたのPCのpythonのパスと異なるかもしれません。
    ``which python``とコマンドラインに入力して、出力されたパスに書き換えてみましょう。``
#!出力されたパス``
## ステップ8: クリーンアップ
テストが終わったら、あなたのパソコンのリソースを開放しておきましょう。
#### ソケットファイルの削除
```
rm path_to_socket_file/cgi.sock
```

#### プロセスの停止
```
ps aux | grep fcgiwrap
```
上記のコマンドが成功すると、プロセスid(pid)が表示されます。
おそらく2つ表示されるので、``fcgiwrap``の実行ファイルへのパスが表示されている方をkillします。
```
kill pid
```
表示されたpidに置き換えてください。