1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2024-03-06

前提:

  1. localhostへアクセスしてCGIを動作させる
  2. homebrewがインストールされている(here)
  3. 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
[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の場所はこちら

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にアクセスして、空欄を埋め、スクリプトが正しく実行されるかを確認してください。

ステップ7: エラーになる場合

error_logを確認する

error_logには、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に置き換えてください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?