IIS 8.5でASP.NET Core 6をSelf-contained配置するとHTTP 500.21「AspNetCoreModuleV2が不正」になる原因と解決策(.NET 6 Hosting Bundle)

Visual StudioでASP.NET Core 6をSelf-contained(win-x64)発行し、Windows Server 2012 R2(IIS 8.5)へ配置したら、HTTP 500.21「Handler ‘aspNetCore’ has a bad module ‘AspNetCoreModuleV2’」で起動しない――そんなときの原因は、ランタイムではなくIIS連携用モジュール(ANCM)の不足であるケースがほとんどです。確認手順と最短の解決策を整理します。

目次

HTTP 500.21「AspNetCoreModuleV2 が不正」とは

IISでHTTP 500.21が出るときは、アプリのコードが実行される前段階、つまりIISの構成(モジュール/ハンドラー)の読み込みで止まっています。今回の典型例が次のメッセージです。

  • Handler “aspNetCore” has a bad module “AspNetCoreModuleV2” in its module list

これは「web.config に modules="AspNetCoreModuleV2" と書いてあるが、サーバー側に AspNetCoreModuleV2(ANCM: ASP.NET Core Module) が存在しない/正しく登録されていない」という意味です。.NET 6 ランタイムの有無とは別軸で発生します。

見えている症状原因の当たりまず見る場所
HTTP 500.21(AspNetCoreModuleV2 が不正)ANCM(AspNetCoreModuleV2)が未導入/破損IIS マネージャー → サーバー →「モジュール」
HTTP 500.30(プロセス起動失敗)アプリ起動時例外、依存DLL不足、環境変数などイベント ビューアー / stdoutログ
dotnet で dll は起動するが IIS では起動しないIIS連携の前提(ANCM、権限、アプリプール設定)不足web.config / アプリプール / フォルダ権限

結論:Self-contained 配布でも IIS 連携には ANCM が必須

「Self-contained(自己完結)」は、アプリが動くための.NET ランタイム一式を発行物に同梱する方式です。これによりサーバーに .NET 6 ランタイムが入っていなくても、コンソール起動(exe直起動、または dotnet で dll 実行)なら動きます。

しかし、IISで aspNetCore ハンドラーを使ってホストする場合、IISは内部でネイティブモジュール(ANCM)を使って、要求の受け口・プロセス起動・標準入出力連携・リサイクル連動などを行います。Self-containedに含まれているのは主に「アプリ実行環境」であり、IIS連携のためのANCMは同梱されません。

ポイント:Self-contained =「.NET ランタイム不要」ではあるが、IIS で動かすなら ANCM(AspNetCoreModuleV2)だけはサーバー側に必要。

項目Self-contained(win-x64).NET Hosting Bundle(IIS Hosting)
アプリ実行に必要な .NET ランタイム発行物に同梱されるサーバーに共有ランタイムとして入る(同梱ではない)
IIS 連携モジュール(AspNetCoreModuleV2 / ANCM)含まれない入る(これが目的)
目的サーバーにランタイムを入れられない/入れたくない場合の配布IISでASP.NET Coreアプリをホストできるようにする
今回のエラー(500.21)への効果単体では解決しない解決する

サーバー側でまず確認すること(切り分け)

導入に入る前に、ANCMが未導入なのか、登録が壊れているのかを確認すると再発防止にもつながります。IIS 8.5(Windows Server 2012 R2)での代表的な確認点は次の通りです。

IIS マネージャーで「モジュール」に AspNetCoreModuleV2 があるか

  1. IIS マネージャーを開く
  2. 左のツリーでサーバー名をクリック
  3. 中央の一覧から「モジュール」を開く
  4. 一覧にAspNetCoreModuleV2が存在するか確認

存在しなければ、今回のエラーの原因はほぼ確定です(= Hosting Bundle で解決)。

コマンドで確認する(GUIが触れない環境向け)

管理者権限のコマンドプロンプト/PowerShellで、IISのモジュール一覧を確認します。

cd %windir%\System32\inetsrv
appcmd list modules | findstr /i AspNetCore

何も出てこなければ未導入の可能性が高いです。導入済みなら AspNetCoreModuleV2(環境によっては AspNetCoreModule も) が表示されます。

web.config で指定しているモジュール名が一致しているか

発行物の web.config に、次のような記述があるはずです。

<handlers>
  <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>

ここで AspNetCoreModuleV2 を指定している以上、サーバーにそのモジュールが必要です。逆に、古いアプリで AspNetCoreModule を使っている場合は、そちらが必要になります(ただし現在はV2が一般的です)。

解決手順:.NET 6 Hosting Bundle をインストールする

対処はシンプルで、サーバーに.NET 6 Hosting Bundle(IIS Hosting を含む)を追加します。これで AspNetCoreModuleV2(ANCM)が導入され、IIS から ASP.NET Core アプリを起動できるようになります。

インストールの流れ

  1. サーバーに管理者権限でログイン
  2. Microsoft公式の「.NET 6 Hosting Bundle」を入手し実行
  3. インストール完了後、必要に応じてIISを再起動(iisreset)
  4. 再度アクセスして 500.21 が解消したか確認

再起動は「サーバー再起動」までは不要なことが多いですが、IISが古い構成を掴んだままの環境もあるため、まずは iisreset を推奨します。

iisreset

インストール後の確認

  • IIS マネージャー → サーバー →「モジュール」に AspNetCoreModuleV2 が出現する
  • アプリにアクセスして、500.21 ではなくアプリ本来のレスポンスが返る
  • 必要に応じてイベント ビューアー(Windowsログ → アプリケーション)でエラーが消えていることを確認

アプリプール設定でハマりやすいポイント

ANCMを入れて 500.21 が解消しても、次は「起動はするが 500.30 になる」「静的ファイルが出ない」といった別の壁に当たりがちです。IISの基本設定も合わせて押さえておくと、切り分けが速くなります。

設定項目推奨理由/補足
アプリプールの .NET CLR バージョンマネージド コードなしASP.NET Core は IIS の .NET CLR で動かすのではなく、ANCM経由でホストするため
パイプライン モード統合一般的な推奨。特別な事情がなければ統合でOK
32ビット アプリケーションの有効化win-x64 なら FalseSelf-contained(win-x64) は 64bit 実行が前提
アプリケーションプールのID(権限)最低限の権限 + 必要に応じて変更配置フォルダの読み取り/実行、ログ出力先の書き込み権限に注意

web.config の見どころ(Self-contained / inprocess)

質問にある通り、発行した web.config に hostingModel="inprocess" が入っているのは正常です。むしろinprocess は高速で、特別な事情がなければこのままで問題ありません。

Self-contained の典型例(processPath は exe)

Self-contained では、起動対象は基本的に「生成された exe」になります(Visual Studio の発行が自動で合わせてくれます)。イメージとしては次の形です。

<aspNetCore processPath=".\FeriasForm.Server.exe"
            arguments=""
            hostingModel="inprocess"
            stdoutLogEnabled="false" />

framework-dependent の典型例(processPath は dotnet)

一方で、framework-dependent(サーバーにランタイムが必要)だと次の形が一般的です。

<aspNetCore processPath="dotnet"
            arguments=".\FeriasForm.Server.dll"
            hostingModel="inprocess" />

どちらの形でも、IISがaspNetCoreハンドラーを処理するには ANCM(AspNetCoreModuleV2)が必要です。今回の 500.21 は、この前提が満たされていないことで起きています。

トラブルシュート用途の stdout ログ

起動に失敗する場合は一時的に stdout ログを有効化すると原因が追いやすくなります。ただしログにはパスや例外情報が出るため、運用に入ったら無効化してください。

<aspNetCore processPath=".\FeriasForm.Server.exe"
            hostingModel="inprocess"
            stdoutLogEnabled="true"
            stdoutLogFile=".\logs\stdout" />

このとき logs フォルダを作成し、アプリプールIDに書き込み権限を付与するのがコツです(権限がないとログ自体が出ません)。

「exe と同名の dll がある」のは正常

Self-contained で発行すると、出力先にアプリ名.exe とアプリ名.dll が並ぶことがあります。これは異常ではなく、ざっくり言うと次の役割分担です。

  • xxx.exe:起動用ホスト(エントリポイント)。必要なランタイムや依存を読み込み、アプリを立ち上げる
  • xxx.dll:アプリ本体(IL)。実際のASP.NET Coreアプリケーションコードが入っている

ローカルで動作確認するときは、基本は次のどちらかです。

  • Self-contained:exe を直接実行(.\FeriasForm.Server.exe)
  • framework-dependent:dotnet で dll を実行(dotnet .\FeriasForm.Server.dll)

逆に、dotnet FeriasForm.Server.exe のように「dotnet に exe を渡す」と、想定外のエラーになることがあります。exe は dotnet のホストではなく、それ自体がホストだからです。

.NET Core 2.x と .NET 6 は共存できる?

結論としては基本的に共存可能です。.NET(.NET Core含む)はサイドバイサイドで複数バージョンをインストールでき、既存アプリを壊さずに新しいランタイム/ホスティングを追加する運用が一般的です。

ただし、ここで混同しやすいのが「ランタイム」と「IISホスティング(ANCM)」です。

  • ランタイム:アプリが動く実行環境。Self-containedなら原則不要
  • ANCM:IISがASP.NET Coreを起動・プロキシするためのIIS拡張。IISホストなら必要

今回のケースは「サーバーの dotnet --info に .NET Core 2.1 しか出ない」こと自体が問題というより、ANCMが入っていない(または古い)ことが問題でした。Hosting Bundle を入れたことで解決し、既存の環境とも共存できた、という流れになります。

質問でよく出る疑問答え補足
Self-contained なのにサーバーに何か入れる必要がある?ある(ANCM)IIS連携は別コンポーネント。アプリの同梱物では代替できない
サーバーに .NET 6 ランタイムが無いのが原因?原因はランタイムではなく ANCMの不足ただし Hosting Bundle を入れるとランタイムも一緒に入る
.NET Core 2.x と .NET 6 は共存できる?できるサイドバイサイドが前提。既存アプリの影響は最小

それでも動かない場合の追加チェック

500.21 が解消しても、次の原因で止まることがあります。ここまで押さえると、現場での復旧がかなり早くなります。

配置フォルダの権限(特にログ出力や一時ファイル)

  • アプリ配置フォルダに、アプリプールIDが読み取り/実行できるか
  • stdoutログやアップロード先など、書き込みが必要な場所に書き込み権限があるか

必要な IIS 機能が入っているか

静的ファイル(React/Viteのビルド成果物)をIISから配信する場合、IISの役割/機能として「静的コンテンツ」が無効だと 404 になりやすいです。また、APIのルーティングに影響するため、基本機能(既定のドキュメントなど)も確認しておきましょう。

アプリが listen しているポート/URL が期待通りか

コンソールで http://localhost:5000 で動くのにIISだと動かない場合、IISでは ANCM が inprocess で w3wp に組み込むため、Kestrel が固定ポートを listen する形とは挙動が変わります。特に out-of-process に切り替えた場合は、ASPNETCORE_URLS や --urls の指定がぶつかっていないかを確認してください。

本番環境の例外が隠れている(500.30 対策)

本番では詳細エラーが隠れていることが多いので、切り分け時は次の順で情報を集めると効率的です。

  1. イベント ビューアー(アプリケーションログ)
  2. 一時的に stdout ログを有効化
  3. 発行フォルダで exe 直起動し、例外やポート競合を確認

まとめ

HTTP 500.21「AspNetCoreModuleV2 が不正」は、アプリの問題ではなく IIS 側の前提不足で起きる代表例です。Self-contained 配布であっても、IISでホストする以上はASP.NET Core Module(ANCM / AspNetCoreModuleV2)が必要になります。

  • 500.21 は「AspNetCoreModuleV2 がサーバーにない/登録されていない」サイン
  • 解決策は.NET 6 Hosting Bundle(IIS Hosting を含む)の導入
  • 導入後は iisreset、アプリプールは「マネージド コードなし」など基本設定も確認
  • .NET Core 2.x と .NET 6 の共存は基本的に可能(サイドバイサイド)

まずは Hosting Bundle を入れて 500.21 を消し、その上で 500.30 や権限・静的ファイル配信など、次の段階のトラブルシュートへ進めるのが最短ルートです。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次