このブログは普段は非情技(非ITエンジニア)向けに記事を書いている。
しかし、この記事は自分の為の「技術的備忘録」として書いた記事だ。
情技師(ITエンジニア)にしか理解できない(と思う)。
よって今回は非情技の方々には役に立たない。
タグに「技術的備忘録」と書かれている記事は他の記事と違い情技師(ITエンジニア)向けの記事だ。
タグに「技術的備忘録」と書かれている記事は他の記事と違い情技師(ITエンジニア)向けの記事だ。
ご了承ください。
以前は、Windows 上では、IIS にPHPをセットアップして使用していたが、先日HDDが壊れてSSDに換装したきっかけで、Windows環境をクリーンインストールしてそれまで環境の作り方や開発のしかたを見直している。
スマートクライアントなどはまだ IIS を使用するが、デバックだけなら IIS を必要としない。
今では ASP.NET もMVCとなり、IIS と必要としなくなっているので、「これ以上 IIS を使い続ける理由もないかな」と思い、nginx に変更した。
Windows 10 への nginx と PHP のセットアップ方法の解説を検索して調べてみたが、分かりやすく一つに纏まっている記事が見つからず、結構理解するのに手間がかかった。
なので、Windows 10 への nginx と PHP のセットアップ手順について、ブログで共有する。
ただの備忘録なのでわざわざ Qiita に投稿するほどでもないと思うし、いまのところ Qiita に参入する気はないので自分のブログ記事にする。
nginx と Apache の違いについて
nginx に PHP をセットアップするには、Apache とは異なるモジュールを使用することになる。
その為、それに関係する部分だけ nginx と Apache の違いについて、説明する。
PHP には「Non Thread Safe」と「Thread Safe(スレッドセーフ)」の2種類のモジュールがある。
「Non Thread Safe」はシングルスレッドで使用するモジュールである。
「Thread Safe」はマルチスレッドで使用する。
マルチスレッドは所属プロセスの中で個々のスレッドが、同じメモリヒープ領域を共有するので、グローバル変数や動的メモリなどを使用していると複数のスレッドが互いに干渉してしまう。
使用中のグローバル変数が他のスレッドに書き換えられてしまったりする。
そこで通常はマルチスレッドプログラムはヒープを使用せずにスタック領域だけで動作するように作られている。
(厳密にはヒープ領域と静的メモリ領域は別のものですが、ここでは区別しません)
この構造を「Thread Safe(スレッドセーフ)」と呼ぶ。
スレッドセーフは「制約」なので、シングルスレッドではこの制約のない形で作られる。
これが「Non Thread Safe」である。
Apache は、マルチプロセスモードとマルチスレッドモードの二種類の動作を選ぶことができる。
IIS はマルチスレッドでのみ動作する。
マルチプロセスは、プロセスの中ではシングルスレッドで動作する。
(マルチプロセスマルチスレッドをOSは可能とするが Apache はそのように作られていない)
その為、スレッドセーフである必要は無い。
通常はマルチスレッドモードの方がメモリ利用効率が良いので、マルチスレッドモードを使用する。
なのでPHPは「Thread Safe(スレッドセーフ)」モジュールを使用する必要がある。
nginx はいくつかのプロセスを使用するが、本質的な処理はシングルプロセスであると同時にシングルスレッドである為、スレッドセーフである必要は無い。
「Non Thread Safe」を使用する。
nginx や、Node.js は、色々な呼び方があるが、「イベントドリブン型マルチタスク」という処理で複数の処理を非同期で実行する方式を採用している。
クライアントからリクエストが来る度、キューにリクエストを投入し、FIFOの順にリクエストを取り出し、処理を実行していく。
ディスクIO処理もキューにリクエストとして投入して、結果を待たずに次の処理に向かうので、シングルスレッドで複数の処理を実行できる。
大昔のOSで使用されていた古いマルチタスクだ。
16bit の Windows v3.1 などがこれを採用していた。Windows95 から現在のCPU時分割型のマルチタスクになった。
Windows v3.1 ではディスクIOを非同期に独立させていなかったので、そのマルチタスクは遅かった。
Windows v3.1 ではディスクIOを非同期に独立させていなかったので、そのマルチタスクは遅かった。
普通に考えたらこの方式は「遅い」はずなのだが、速度の最大のボトルネックである「ディスクIO」の処理を独立させ非同期に実行できるようにしたことにより、むしろこの方が早くなっている。
メモリの利用効率もシングルプロセス・シングルスレッドの方が良いに決まっている。
(厳密にはシングルプロセスではなく少なくともCPUの数と管理プロセスの分のプロセスは必要です)
この仕組みの違いが分かっていると、「Non Thread Safe」と「Thread Safe(スレッドセーフ)」の2種類のモジュールで迷うことはない。
nginx では PHP は「Non Thread Safe」を使用する。
nginx の配置
概要
windows版 nginx をダウンロードして適当なフォルダーへZIP解凍して配置する。
試験的に起動して動作することを確認後、nginxをwindowsサービスへ登録する。
導入手順
インストーラーはない。
「Stable version」の「nginx/Windows-?.??.?」をダウンロードする。
(?.??.? はバージョン番号)
(?.??.? はバージョン番号)
「C:serversnginx」などにZIPファイルの内容を解凍して配置する。
(フォルダーの場所は適当で良い、Users の配下には置かないように)
「C:serversnginxconf」の「nginx.conf」をテキストエディターで開く。
「pid」の項目が「#」でコメントアウトされているのでコメントを外し、パスを以下のように修正し保存する。
pid C:/servers/nginx/logs/nginx.pid;
「C:serversnginx」フォルダーをコマンドプロンプトで管理者権限で開き、
start nginx
と打ち込み、nginx を試験的に起動する。
ブラウザで「http://localhost/」を開き、nginx のメッセージが表示されることを確認する。
コマンドプロンプトで、nginx を停止する。
nginx -s stop
nginx -s quit
どちらでも良い。
動作確認完了。
nginxのサービス化
nginx は Windows のサービスとして開発されていない。
ただ、起動して無限ループでポートイベントを待っているだけのデーモンプログラムだ。
winsw というフリーソフトで、nginx をサービスとして管理できるようになる。
winsw は、中身が空っぽで、ただサービスを開始終了する時に、定義ファイルで登録してあるデーモンプログラムを開始終了するだけの Windowsサービス(常駐プログラム)だ。
これがあるとWindowsで管理し易くなるので導入する。
別にこれを使用しなくても、起動時にスタートアップなどで起動バッチを走らせても良い。
winsw をダウンロードする。
winsw-2.2.0-bin.exe
winsw-2.2.0-net4.exe
-bin は.NET2.0系、-net4 が.NET系である。
環境に合わせて選ぶ。
windows 10 なら、winsw-2.2.0-net4.exe です。
「C:serversnginx」フォルダーに「winsw-2.2.0-net4.exe」を配置する。
「winsw-2.2.0-net4.exe」のファイル名を「nginx-winsw.exe」など分かりやすい名称に変更する。
新規ファイル「nginx-winsw.xml」を作成する、中身は空のテキストファイルでよい。
「nginx-winsw.xml」の中身に以下のXML設定を貼り付ける。
<service>
<id>nginx</id>
<name>nginx</name>
<description>nginx</description>
<executable>c:nginxnginx.exe</executable>
<logpath>c:nginx</logpath>
<logmode>roll</logmode>
<depend></depend>
<startargument>-p c:nginx</startargument>
<stopargument>-p c:nginx -s stop</stopargument>
</service>
startargument を、startarguments (複数形)に変更する。
stopargument を、stoparguments (複数形)に変更する。
終了タグも同様。
これをしないとサービスを終了できなくなる。
前者は識別子のスペースを受け付けない。
一つのタグが一つの識別子しか受け付けない。
後者はスペース区切りで、同時に複数の識別子が指定できる。
<stoparguments>-p c:nginx -s stop</stoparguments>のように。
これを前者のタグで書くと、
<stopargument>-p</stopargument>
<stopargument>c:nginx</stopargument>
<stopargument>-s</stopargument>
<stopargument>stop</stopargument>
と成る。
以下の
<executable>c:nginxnginx.exe</executable>
<logpath>c:nginx</logpath>
<startarguments>-p c:nginx</startarguments>
<stoparguments>-p c:nginx -s stop</stoparguments>
を、以下のように変更する。
<executable>C:serversnginxnginx.exe</executable>
<logpath>c:nginx</logpath>
<startarguments></startarguments>
<stopexecutable>C:serversnginxnginx.exe</stopexecutable>
<stoparguments>-s</stoparguments>
<stoparguments>stop</stoparguments>
(<stopexecutable>は追加です)
(管理者権限の)コマンドプロンプトで、
C:serversnginxnginx.exe install
を実行する。
サービスにnginxが追加される。
サービスの nginx を「サービス」画面から起動し、「http://localhost」をブラウザで開いて動作を確認する。
サービスからnginxを削除する時は、nginxを停止して
C:serversnginxnginx.exe uninstall
と打ち込み実行する。
htmlの場所
html ファイルの置き場所は以下の場所になる。
C:serversnginxhtml
ここに配置したindex.htmlを、http://localhost/ でブラウザに表示する。
PHPの導入と動作確認
公式サイトより、PHPモジュールをダウンロードする。
OSが、32bit(x86)か、64bit(x64) か確認してから、それに合うモジュールを選ぶ。
それから nginx の場合は「Non Thread Safe」を選ぶ。
64bit Windows 10 なので、私は、「php-7.3.6-nts-Win32-VC15-x64.zip」を使用した。
zip ファイルを解凍して、「C:serversphp-7.3.6-nts」などの適当なフォルダーに解凍する。
これもインストーラーはない。
次に、nginx の設定ファイルをPHPと通信するよう設定する。
C:serversnginxconf フォルダーを開き、nginx.conf をテキストエディターで開く。
(1) index.php の設定
index の指定に、index.php を加える。
これで、デフォルトで nginx が index.php を読みに行く。
location / {
root html;
index index.php index.html index.htm;
}
(2) PHP を使用する設定
nginx.conf では、行の先頭の「#」がコメントアウトを意味する。
PHPの設定は、コメントアウトされているのでこれを外し(先頭の#を消す)有効にする。
以下が、コメントアウトされていモノを有効にしたPHPの設定である。
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ .php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME C:/Servers/nginx-1.16.0/html$fastcgi_script_name;
include fastcgi_params;
}
「fastcgi_param SCRIPT_FILENAME C:/Servers/nginx-1.16.0/html$fastcgi_script_name;」の部分は、nginx を配置したパス名に書き換える。
注意点として、Windowsのパスは「」記号を区切りに使用するが、この設定は「Linux形式」でバスを記述するので「/」を区切りに使用する。
ちなみに、「fastcgi_pass 127.0.0.1:9000;」の「9000」はポート番号を意味し、このポート番号で nginx と PHP は通信する。
このポート番号は nginx側 と PHP側 で同じ値に設定しなければならない。
(3)動作確認
nginx が起動している状態で、以下のコマンドを打ち、php-cgi.exe を起動する。
C:serversphp-7.3.6-ntsphp-cgi.exe -b 127.0.0.1:9000
起動したままになる。
次にPHPの動作確認のため、「C:serversnginxhtml」の中に以下の「phpinfo.php」ファイルをテキストエディタで作成し配置する。
<?php
phpinfo();
?>
ブラウザで「http://localhost/phpinfo.php」が表示して、PHPの設定情報が表示されたら、正常に動作することが確認できたことになる。
確認できたら、php-cgi.exe を「ctrl + C」キーで終了する。
PHPのサービス登録
nginxと同様に winsw でサービスに登録する。
winsw-2.2.0-bin.exe
winsw-2.2.0-net4.exe
を、PHPのフォルダーにコピーして、EXEの名称を適当に「php-cgi-winsw.exe」など分かりやすい名称に変更する。
新規ファイル「php-cgi-winsw.xml」を作成する、中身は空のテキストファイルでよい。
「php-cgi-winsw.xml」の中身に以下のXML設定を貼り付ける。
<service>
<id>PHPCGI</id>
<name>PHPCGI</name>
<description>PHP</description>
<executable>C:serversphp-7.3.6-ntsphp-cgi.exe</executable>
<logpath>C:serversphp-7.3.6-ntslogs</logpath>
<logmode>roll</logmode>
<depend></depend>
<startargument>-b</startargument>
<startargument>127.0.0.1:9000</startargument>
<stopexecutable>taskkill.exe</stopexecutable>
<stopargument>/f</stopargument>
<stopargument>/im</stopargument>
<stopargument>php-cgi.exe</stopargument>
</service>
ちなみに、
<executable>が指定しているのがサービスに登録したいEXEである。
<startargument>はそのEXEの起動パラメータを指定する。スペースを指定できないので識別子の数だけ順番に記述する。
<stopexecutable>は終了するときに使用するEXEである。
<stopargument>はそのEXEの起動パラメータを指定する。スペースを指定できないので識別子の数だけ順番に記述する。
このケースは起動時はphp-cgi.exeを指定して起動するが、終了する時はtaskkill.exeで強制的に殺している。
php-cgi.exeには終了命令がないからだ。
nginxには終了命令があるのでnginx.exeを指定している。
管理者権限でコマンドプロンプトを開き、以下のようにサービスを登録する。
C:serversphp-7.3.6-ntsphp-cgi-winsw.exe install
windowsの「サービス」管理画面で「PHPCGI」が存在することを確認し、
サービスを開始する。
起動したなら、ブラウザで「http://localhost/phpinfo.php」が表示して、PHPの設定情報が表示されたら、正常に動作することが確認できたことになる。
サービスを削除する時は、php-cgi-winsw.exe を終了して、
管理者権限のコマンドプロンプトで、
C:serversphp-7.3.6-ntsphp-cgi-winsw.exe uninstall
と打ち込めば削除できる。
ちなみに、バックグラウンドで他の「php-cgi-winsw.exe」や「「php-cgi.exe」」が起動していたらサービスは起動できないので、tasklist.exe などで確認した方が良い。
起動していたら、taskkill で終わらせよう。
以上です。
NGINX と PHP について書かれた本が見当たらない。
最近、書籍が技術の変化に追いつけないように見えるな。
ネット情報は正確さに欠けるし、困ったモノだ。
こういうところにビジネスチャンスがあるのかもしれないが。
何も思いつかないけどさ….