2620 words
13 minutes
IISでPHPを動かしたら404になった話

Windows Server上でPHPのアプリを動かすことになった。

開発環境はApacheだけど、本番はIIS。

なのでVirtualBoxにWindows Server 2025を立てて、

Windows Server
↓
IIS
↓
PHP
↓
CodeIgniter

まで一回通しておこう、という検証を始めた。

IISはほぼ触ったことがない。

解決手順だけ確認したい場合は、IIS + PHPで404になったときの確認ポイント にまとめている。

まあでもPHP動かすだけやろ。

この時点ではそう思っていた。


IISとPHPまでは割と順調#

まずWindows ServerにIISを追加。

「役割と機能の追加」からWebサーバー(IIS)を選んで、PHPをFastCGIで動かすためにCGIも有効化した。

http://localhost にアクセスするとIISのデフォルトページが表示された。

ここまではOK。

次はPHP。

本番はPHP 7.3系なので、検証環境では7.3.33を使うことにした。

IIS + FastCGIなのでNTS版。

php-7.3.33-nts-Win32-VC15-x64.zip

ここで「VC15ってなんやねん」という寄り道もあった。

VC15はVisual C++ 2017系でビルドされた、という意味であって、VC++ランタイムがPHPのZIPに入っているという意味ではない。

実際、最初に

Terminal window
php.exe -v

しても何も出なかった。

終了コードを見ると、見たことないくらいデカい負数。

VC++ Redistributableを入れてからもう一度実行すると、

Terminal window
php.exe -v

が正常に表示された。

なるほど。

PHPを入れたつもりだったが、PHPが立つための床板がまだなかったらしい。

その後、IISのハンドラーマッピングで、

要求パス: *.php
モジュール: FastCgiModule
実行可能ファイル: C:\PHP\7.3.33\php-cgi.exe

を設定。

info.php に、

<?php phpinfo();

を書いてアクセスすると、無事PHPの情報画面が表示された。

よし。

IISからPHPまでは動いた。

あとはCodeIgniterを置けばいい。

ここからだった。


CodeIgniterを置いたら500.19#

アプリ一式を wwwroot に配置してアクセス。

出た。

500.19。

PHPのエラーですらない。

調べていくと、web.config にRewriteの設定がある。

一方、構築したばかりのIISにはURL Rewrite Moduleをまだ入れていなかった。

なるほど。

IISからすると、

<rewrite>

とか急に言われても知らんがな、という状態だったらしい。

URL Rewrite Moduleをインストール。

これで500.19は消えた。

よし、前進。

と思ったら、

この localhost ページが見つかりません HTTP ERROR 404

今度はページが見つからないらしい。

エラー番号が小さくなったからといって、ゴールに近づいているとは限らない。


web.configを外したら403.14#

まずRewriteを疑った。

web.config を一旦無効化してアクセスしてみる。

すると今度は、

403.14

になった。

これはディレクトリは見えているけど、既定のドキュメントが決まっていないときに出るやつ。

じゃあ defaultDocument か。

元の web.config にも設定があったので、最小構成にして defaultDocument だけ入れてみる。

<defaultDocument>
<files>
<clear />
<add value="index.php" />
</files>
</defaultDocument>

すると今度は、

404.0

になった。

403から404へ。

進んでるような、横に移動してるだけのような。


IIS、本当にwwwroot見てる?#

404.0なので、次はファイルそのものを疑った。

IISの Default Web Site の基本設定を見る。

物理パスは、

%SystemDrive%\inetpub\wwwroot

%SystemDrive% は通常 C: なので、

C:\inetpub\wwwroot

を見ている。

そこは合ってる。

PowerShellでも、

Terminal window
Test-Path C:\inetpub\wwwroot\index.php

を実行。

True。

index.php もちゃんといる。

じゃあPHPのハンドラーマッピングか?

確認する。

*.php
↓
FastCgiModule
↓
php-cgi.exe

ここも合ってる。

FastCGIの設定も見る。

合ってる。

IISは正しい場所を見ている。

ファイルもある。

PHPも動いている。

ハンドラーも合っている。

なのに「ページが見つかりません」。

嫌な感じになってきた。


test.txtまで見つからない#

PHPだけの問題なのか確認するため、txtファイルでも試すことにした。

test.txt を置いてアクセス。

404.0 + 0x80070002

PHP関係ないやん。

となると、コピーしてきたファイルの権限か?

Windows Serverだし、IISだし、コピー元のACLとか継承とか、その辺が何かやってるんじゃないか。

そう思って、今度は wwwroot の中でテストファイルを直接作った。

Terminal window
Set-Content -Path "C:\inetpub\wwwroot\iis-test.txt" -Value "IIS TEST"

ブラウザからアクセス。

出た。

ほら権限や。

コピーしてきたファイルだけ読めてないんや。

そう思った。

ここでほぼ犯人を捕まえた気になっていた。


phpinfo.phpなんていなかった#

表示できるファイルと表示できないファイルの権限を比較しようとした。

Terminal window
icacls C:\inetpub\wwwroot\phpinfo.php

すると、

The system cannot find the file specified.

ん?

いやいや。

ブラウザでも phpinfo.php が見つからなかったんやから……

……

実際に置いていたファイル名を確認する。

info.php

phpinfo.phpちゃうやん。

ブラウザに打っていたURLが間違っていただけだった。

IISはずっと、

「そのファイルないで」

と言っていた。

404.0も、

0x80070002 も、

かなり具体的に、

「ないで」

と言っていた。

こっちが聞いてなかった。


じゃあindex.phpは?#

ただし、これですべて解決したわけではない。

info.php の件は単なるファイル名間違いだった。

でも、

Terminal window
Test-Path C:\inetpub\wwwroot\index.php

はちゃんと True。

index.php は本当に存在する。

それなのに、

http://localhost/index.php

では、

この localhost ページが見つかりません HTTP ERROR 404

になる。

ここで一つ気になった。

この画面、さっき見ていたIISの詳細な404.0画面じゃない。

ブラウザの簡易的な404表示になっている。

もしかして、

「IISがindex.phpを見つけられない」という話ではない?


index.phpの先頭で止めてみた#

確認する方法は単純。

index.php の先頭に一時的にこれを書いた。

<?php
echo 'INDEX OK';
exit;

アクセス。

INDEX OK

出た。

つまり、

ブラウザ
↓
IIS
↓
FastCGI
↓
PHP
↓
index.php

ここまでは全部通っている。

さっきまで「index.phpが見つからない」と思っていたけど、違った。

index.phpには普通に到達していた。

画面には「ページが見つかりません」と出ていたけど、少なくともIISがファイルを見失っているわけではない。

ここでようやく、調査対象がIISからCodeIgniter側へ移った。


最後に残ったのはDB接続だった#

さらにアプリ側を追っていくと、DB接続まわりがうまくいっていなかった。

このアプリではその辺のエラーがそのまま表に出ず、結果的に「ページが見つかりません」として見えていたっぽい。

DB接続まわりを修正すると、ようやくアプリの画面まで表示された。

これで、

Windows Server
↓
IIS
↓
FastCGI
↓
PHP
↓
CodeIgniter
↓
DB

まで開通。

ただ、正直ここは後から振り返ると記録が少し曖昧だった。

DB接続エラーそのものを「ページが見つかりません」にしていたのか、DB接続に失敗した結果として別の処理がそう返していたのか。

そこまでは追えていない。

覚えているのは、DB接続まわりを直したあと、最終的にアプリが動いたこと。

そして、もし本当にDBに繋がらないのを「ページが見つかりません」で返していたのだとしたら、

このアプリもだいぶ道に迷っている。


「ページが見つからない」を信じて、ページを探し続けた#

今回の調査で一番ハマったのは、画面に出ている言葉をそのまま原因だと思ってしまったことだった。

「ページが見つかりません」と言われた。

じゃあIISがファイルを見つけられてないんやろ。

そう思って、

物理パスを見た。

ハンドラーマッピングを見た。

FastCGIを見た。

ファイルの存在を確認した。

権限まで疑った。

途中には、本当に存在しないファイル名を自分で打っていた件まで混ざっていたので、余計にややこしくなった。

でも index.php に直接文字を出してみたら、そこまでは普通に届いていた。

つまり画面に出ていた、

ページが見つかりません

は、必ずしも、

IISがそのファイルを見つけられません

という意味ではなかった。

画面に出ているのは、あくまで最終的に見えている症状。

原因がどこにあるかは別の話だった。

だから今なら、表示されたエラーだけを見て調査する場所を決めるんじゃなくて、

静的ファイルは見えるか
↓
PHPは動くか
↓
index.phpまで届くか
↓
アプリの中は動いているか
↓
DBまで繋がっているか

と、入口から一個ずつ確認する。

今回も index.php まで届いていることをもっと早く確認していれば、少なくともIISの設定やファイルの存在を延々と疑う必要はなかった。

「どこまで正常に動いているか」を先に確定させる。

結局これが一番早い。


それにしても、今回の最後の原因はDB接続まわりだった。

「ページが見つかりません」と言われて調査を始めて、最終的にDBを触っている。

日常に置き換えるなら、

「テレビが映らない」

と言われて家まで見に行ったようなもんだ。

電源は入ってる?

ケーブルは?

入力切替は?

テレビ壊れてない?

こっちは当然、テレビの周りを調べる気でいる。

でもよくよく話聞いていったら、

冷蔵庫のコンセントが抜けてました。

ってなったくらい話が遠い。

ってかテレビの事ですらなかったんかい!テレビどこいった?みたいな。

別に直しますけど、

「テレビが映らない」から冷蔵庫には、なかなか辿り着かんて。