
ただし、Laravel 10から既存アプリケーションを更新する場合は事情が異なる。公式は既存アプリケーションのディレクトリ構造を、新規アプリケーションと同じ形へ無理に変更することを推奨していない。旧構造の Kernel.php を残したままでも動作できるように調整されているためである。
ここで問題になるのが、移行途中で新形式の bootstrap/app.php を導入した場合だ。旧来の Kernel.php や Handler.php が警告なしに無視される可能性がある。設定が壊れているのに例外が発生しない。これは通常のエラーより検出しにくい。
Laravel 11のミドルウェア登録方法を理解するには、単に記法を置き換えるだけでは不十分である。どの設定が読み込まれ、どの設定が無効になるのかを把握する必要がある。
Kernel.php 廃止の意味はファイル移動ではない
[Laravel 10以前では、HTTPミドルウェアの登録場所として app/Http/Kernel](/articles/laravelnoapilian/).php が使われていた。代表的な設定は次の三つである。
- すべてのリクエストに適用するグローバルミドルウェア
webやapiなどのミドルウェアグループ- 短い名前でルートに指定するミドルウェアエイリアス
従来は、これらを Kernel.php のプロパティに記述する構成が一般的だった。$middleware、$middlewareGroups、$middlewareAliases などが設定の入口である。
Laravel 11の新構造では、この役割が bootstrap/app.php に集約される。アプリケーションの起動処理と、フレームワークが利用する構成情報を同じ場所で組み立てる設計である。
ここで注意すべきなのは、Kernel.php の内容が自動的に bootstrap/app.php へ統合されるわけではない点である。旧ファイルの設定を残せば、新設定へ自動的にマージされると考えると誤る。
Laravel 11の移行で危険なのは、エラーが発生することではない。設定が無視されたまま、アプリケーションが起動することである。
Laravel 10から11へ更新した既存アプリケーションでは、旧来のディレクトリ構造が維持される場合がある。この状態では Kernel.php を残しても動作する。しかし、bootstrap/app.php に新形式の Application::configure() を導入すると、ロードされる構成の前提が変わる。
つまり、次の二つは別の状態である。
| 状態 | Kernel.php | bootstrap/app.php | 判断 |
|---|---|---|---|
| Laravel 10以前の構成 | 使用する | 旧形式または限定的 | 従来構造 |
| Laravel 11で旧構造を維持 | 残す | 既存構造に合わせる | 公式の移行方針に沿う |
| Laravel 11の新構造 | 使用しない | Application::configure() と withMiddleware() | 新規アプリケーションに近い構成 |
| 移行途中 | 残っている | 新形式を導入済み | 設定のサイレント・フェイルに注意 |
ファイルの存在だけでは、現在の構成を判断できない。実際にアプリケーションがどの形式で初期化されているかを確認する必要がある。
bootstrap/app.php と withMiddleware() の役割
Laravel 11の新構造では、ミドルウェア設定を withMiddleware() のコールバック内で行う。アプリケーションの設定を組み立てるコードに、ミドルウェアの追加やグループ設定を連続して記述する形式である。
概念的には、bootstrap/app.php の中で次のような構成になる。
Application::configure(basePath: dirname(__DIR__)) によってアプリケーションを構成し、続けて withRouting()、withMiddleware()、withExceptions() などを呼び出す。最後に create() を実行してアプリケーションを生成する。
ミドルウェアの設定対象は、withMiddleware() に渡される設定オブジェクトである。ここに対して、グローバルミドルウェアの追加、既存グループへの追加、CSRF検証の除外、信頼するプロキシの設定などを指定する。
従来の配列を直接編集する構成と比較すると、設定の意図がメソッド名に現れる。設定対象を間違えると、単に配列の順番を誤る場合とは異なる結果になる。
グローバルミドルウェアを追加する
全リクエストに適用するミドルウェアを追加する場合は、append() または prepend() を使用する。
append() は既存のグローバルミドルウェアの後ろに追加する。prepend() は先頭に追加する。実行順序が処理結果に影響するミドルウェアでは、この違いがそのまま挙動の違いになる。
たとえば、独自のリクエスト計測ミドルウェアを追加する場合、通常は対象処理の前後を計測できる位置に配置する必要がある。認証や例外処理より前に置くのか、ルーティング後に置くのかでも取得できる情報が変わる。
登録そのものは、$middleware->append(Middleware::class) または $middleware->prepend(Middleware::class) という形で記述する。
ここで確認すべきなのは、クラスの名前空間と実行順序である。クラスを登録しても、名前空間が間違っていればアプリケーション起動時に解決できない。一方で、既存の自動登録に依存している場合は、クラスが解決できても意図した場所で実行されないことがある。
ミドルウェアグループへ追加する
特定のルートグループにだけミドルウェアを追加する場合は、グローバル登録とは別のメソッドを使用する。
web グループに追加するなら、$middleware->web(append: [...]) のように指定できる。既存グループの末尾に追加したい場合は、appendToGroup('web', ...) という形式も使える。
api グループを対象にする場合も考え方は同じである。ただし、対象ルートが本当に api グループを使用しているかを確認しなければならない。ルート定義にグループが指定されていなければ、登録したミドルウェアは実行されない。
ミドルウェアの登録で頻発する誤りは、グローバルに追加したつもりでグループに追加しているケースである。反対に、管理画面だけに適用したい処理をグローバルへ追加すると、公開ページや外部向けAPIにも影響する。
登録場所は、処理の責務で決めるべきである。
- すべてのHTTPリクエストを計測する処理はグローバル
- セッションやCSRFに依存する処理は
web - トークン認証やAPI固有の制御は
api - 特定の機能だけに必要な処理はルート単位または専用グループ
「動く場所」に登録するのではなく、「必要な範囲」に登録する。適用範囲が広いほど、性能への影響と副作用の調査範囲も広くなる。
移行時に発生するサイレント・フェイル
Laravel 11のミドルウェア移行で最も検出しにくい問題が、サイレント・フェイルである。これは設定ミスによる例外や警告が発生せず、アプリケーションが動作しているように見える状態を指す。
典型的な流れは次の通りである。
1. Laravel 10から11へ依存関係を更新する
2. 新構造を参考に bootstrap/app.php を書き換える
3. 旧 Kernel.php にもミドルウェア設定が残っている
4. 新しい構成が採用され、旧ファイルの設定が読み込まれなくなる
5. 画面表示や一部のルートは正常に動作する
6. 認証、CSRF、独自ヘッダーなど一部の処理だけが欠落する
この状態では、テストが十分でないと移行完了と判断してしまう。トップページが表示されることは、ミドルウェア移行の成功を意味しない。
特に影響が見えにくいのは、次のような設定である。
- 監査ログの記録
- リクエストIDの付与
- 独自のセキュリティヘッダー
- 管理画面向けのアクセス制御
- CSRF除外設定
- プロキシ経由のIPアドレス判定
- APIレスポンスの変換処理
これらはすべての画面で即座にエラーを出すとは限らない。特定の条件でだけ欠落する。そのため、移行作業ではファイルを整理する前に、旧構造で登録されていた内容を一覧化する必要がある。
移行前に設定を分類する
Kernel.php の内容をそのまま bootstrap/app.php へ貼り付ける方法は適切ではない。まず設定を分類する。
| 旧構造で確認する対象 | 新構造での移行先 | 確認する内容 |
|---|---|---|
$middleware | append() または prepend() | すべてのリクエストに必要か |
$middlewareGroups['web'] | web(append: [...]) など | web ルートだけでよいか |
$middlewareGroups['api'] | api グループへの追加 | API専用の処理か |
$middlewareAliases | ルートでのミドルウェア利用方法 | エイリアス名と対象ルートが一致しているか |
VerifyCsrfToken の除外 | validateCsrfTokens(except: [...]) | 除外が本当に必要か |
TrustProxies | trustProxies(at: [...]) | 信頼するプロキシの範囲が適切か |
この分類をせずに新構造へ移行すると、登録先の誤りが発生する。グローバルミドルウェアをグループへ移す、グループ専用の設定を全体へ適用する、といった事故である。
旧設定と新設定の両方を残して比較する方法もある。ただし、新形式を導入した時点で旧ファイルが無視される可能性があるため、比較期間を長く取るほど安全になるわけではない。設定の正本をどちらに置くかを決め、検証後に不要な構造を整理するべきである。
CSRF除外設定は場所だけでなく意図を確認する
Laravel 10以前のアプリケーションでは、CSRF検証から除外するパスを VerifyCsrfToken の $except に記述しているケースがある。
Laravel 11の新構造では、bootstrap/app.php の withMiddleware() 内で validateCsrfTokens(except: [...]) を呼び出して設定する。書き換え自体は単純だが、ここは機械的に移行してはいけない。
CSRF除外は、フォーム送信を保護する仕組みの対象外を定義する設定である。外部サービスから受け取るWebhookのように、通常のブラウザセッションを使わないエンドポイントでは除外が必要になる場合がある。一方、管理画面やユーザー向けフォームのパスを除外すると、保護対象を意図せず失う。
確認する内容はパスの文字列だけではない。
- そのエンドポイントはブラウザから送信されるか
- セッション認証を使用しているか
- 外部サービスから直接呼び出されるか
- 署名検証など別の認証を実装しているか
- パス変更後も除外設定が残っていないか
WebhookのCSRF除外は、CSRF保護を不要にする設定ではない。別の認証方式でリクエストの正当性を検証することが前提になる。
また、除外対象にワイルドカードを使用している場合は、想定より広いパスが対象になる可能性がある。Laravel 11への移行を機に、除外設定をすべて列挙し、実際のルート定義と照合するべきである。
TrustProxies の移行はインフラ構成とセットで行う
プロキシやロードバランサーを経由するアプリケーションでは、クライアントのIPアドレス、HTTPS判定、ホスト情報の扱いにプロキシ信頼設定が影響する。
従来は app/Http/Middleware/TrustProxies.php を使って設定する構成が一般的だった。Laravel 11の新構造では、このミドルウェアを削除し、bootstrap/app.php で $middleware->trustProxies(at: [...]) のように設定する方法が推奨されている。
この設定はアプリケーションコードだけで完結しない。実際のネットワーク経路と一致していなければならない。
たとえば、次のような構成を考える。
- 利用者
- CDN
- ロードバランサー
- コンテナ
- Laravelアプリケーション
この場合、アプリケーションが直接受信する接続元は利用者ではない。プロキシヘッダーの内容を信頼する範囲を誤ると、IPアドレスの取得やHTTPS判定が不正確になる。
信頼するプロキシを広く指定すれば、動作確認だけは簡単になる。しかし、信頼範囲が広すぎると、信頼できない送信元からのヘッダーを受け入れる構成になる。反対に狭すぎると、HTTPSリダイレクトやURL生成で問題が出る。
移行時は、旧 TrustProxies.php の設定を移すだけで終わらせてはいけない。次の動作を実際の経路で確認する必要がある。
- HTTPSアクセス時にURLがHTTPへ戻らないか
request()->secure()の判定が正しいか- クライアントIPアドレスが期待する値になるか
- リダイレクト先のホスト名が正しいか
- 管理画面のアクセス制限がプロキシ経由でも機能するか
Docker環境では、開発環境と本番環境でプロキシ構成が異なることが多い。ローカルの直接アクセスだけで検証すると、本番固有の問題を見逃す。
ルート一覧とスケジュール一覧で移行結果を測る
ミドルウェアの設定は、ファイルの内容を読んだだけでは検証できない。登録結果を実行時の情報で確認する必要がある。
まず、ルート一覧を確認する。php artisan route:list を実行し、移行前と移行後でルート数、HTTPメソッド、URI、ミドルウェアの対応を比較する。
とくに確認対象になるのは、次のルートである。
webグループを使用するフォームapiグループを使用するAPI- エイリアス指定のある管理画面
- 認証を必要とするルート
- CSRF除外対象のWebhook
- レート制限を適用しているエンドポイント
ルートが一覧に存在していても、必要なミドルウェアが付いているとは限らない。ルートのURIだけでなく、ミドルウェア列を比較するべきである。
スケジュール設定はHTTPミドルウェアとは直接関係しない。しかし、Laravel 11へのアップグレード全体を検証する指標として php artisan schedule:list が使える。登録済みタスクの件数や実行間隔が移行前と一致するかを確認する。
これは、ミドルウェアだけを見ていると起動構成全体の差分を見落とすためである。bootstrap/app.php はミドルウェアだけでなく、ルーティング、例外、スケジュール関連のアプリケーション構成にも関係する。ファイルを大きく変更した場合は、周辺機能も同時に確認する必要がある。
検証は三つの層に分ける
移行後の確認は、次の三段階に分けると効率がよい。
1. 構成の検証
bootstrap/app.php に必要な設定が存在し、旧 Kernel.php にだけ残っている設定がないか確認する。
2. 登録結果の検証
php artisan route:list でルートとミドルウェアの対応を確認する。必要に応じて php artisan schedule:list でアプリケーション構成全体の変化を確認する。
3. リクエストの検証
実際にブラウザ、APIクライアント、Webhook送信元からアクセスし、認証、CSRF、プロキシ判定、独自ヘッダーの結果を確認する。
構成ファイルのレビューだけでは、実行順序や適用範囲を確認できない。ルート一覧だけでも、実行時の副作用までは分からない。三つを分けて確認することで、調査対象が明確になる。
Laravel 10から11へ移行する場合の現実的な手順
既存アプリケーションをLaravel 11へ移行する場合、新規アプリケーションの構造を完全に再現する必要はない。公式は、既存アプリケーションを新しいディレクトリ構造へ移行することを推奨していない。
この方針には理由がある。アプリケーションのディレクトリ構造は、ミドルウェアだけで決まっていない。例外処理、サービスプロバイダー、ルート、コンソール処理、独自の起動処理などが関係する。構造だけを変更すると、設定の参照先が複数箇所に分散する。
既存アプリケーションでは、次の順番が合理的である。
1. 依存関係と既存構成を固定する
まず、アップグレード前のコミットを固定する。composer.json と composer.lock の状態を記録する。Dockerを利用している場合は、PHPのバージョン、拡張機能、コンテナイメージも同時に保存する。
ミドルウェア移行の調査中にPHPやComposerの条件まで変えると、原因の切り分けが難しくなる。フレームワーク更新と実行環境更新は、可能なら別の変更単位に分けるべきである。
2. Kernel.php の設定を一覧化する
プロパティごとに内容を抽出する。コメントアウトされた設定も確認対象に含める。コメントには、現在は使っていない理由や、過去の障害対応が残っていることがある。
一覧化する対象は次の通りである。
- グローバルミドルウェア
webグループapiグループ- エイリアス
- CSRF除外
- 信頼するプロキシ
- 独自ミドルウェアの依存関係
ここで、ミドルウェアクラスが実際にルートで使われているかも確認する。登録されているが使われていないクラスをそのまま移行すると、不要な処理だけが残る。
3. 旧構造を維持するか決める
Laravel 11へ更新したからといって、ただちに Kernel.php を削除する必要はない。既存構造のまま動作させる方針も選択肢になる。
一方、新規機能の実装や大規模な構成変更を予定している場合は、bootstrap/app.php に設定を集約する方が分かりやすい場合もある。ただし、その場合は旧ファイルの設定が読み込まれなくなる前提で、すべての設定を移す必要がある。
判断基準はファイル数ではない。変更範囲と検証可能性で決める。
- 小規模な保守であれば、旧構造を維持する
- 新規アプリケーションに近い構成へ整理するなら、全設定を移行する
- 両方の構造を長期間併存させない
- 移行後の正本を一つに決める
4. bootstrap/app.php へ段階的に移す
新形式を採用する場合は、グローバル、グループ、CSRF、プロキシの順に分類して移行する。順番に意味がある。最初にすべてを移すと、どの設定が欠落したかを追跡しにくい。
各変更単位で次を確認する。
- アプリケーションが起動するか
- ルート一覧が変化していないか
- 対象ミドルウェアのログが出るか
- HTTPステータスが移行前と一致するか
- エラー時のレスポンスが変わっていないか
ミドルウェアは実行順序が重要である。登録順を変更した場合は、単にクラスが登録されているかだけでなく、前後関係も比較する必要がある。
よくある移行ミスと原因
Kernel.php を削除すれば新構造になると考える
ファイルを削除するだけでは、設定移行にならない。Kernel.php に登録されていた内容が bootstrap/app.php に存在しなければ、ミドルウェアは失われる。
このミスは、トップページが表示されるアプリケーションで起きやすい。公開ページに独自ミドルウェアが付いていなければ、欠落しても画面表示には影響しない。
新形式と旧形式を部分的に併用する
bootstrap/app.php に一部の設定だけを追加し、残りを Kernel.php に残す構成は危険である。新形式導入後に旧ファイルが無視される場合、残した設定がそのまま消えるからである。
併用する場合は、どの設定がどちらからロードされるのかを明確にしなければならない。挙動を推測してはいけない。ルート一覧と実際のリクエストで確認する。
グローバル登録とグループ登録を混同する
管理画面専用の認可処理をグローバルへ追加すると、公開ページやAPIにも処理が適用される。逆に、全リクエストで必要なログ記録を web グループだけに追加すると、APIのログが欠落する。
適用範囲はクラスの名前ではなく、処理の責務で判断する。
CSRF除外を移しただけで検証しない
旧 $except の内容を validateCsrfTokens(except: [...]) へ移しても、除外対象が現在のルートと一致しているとは限らない。ルート変更の後に古い除外だけが残っている場合もある。
除外設定は移行のついでに整理する価値が高い。対象を最小化し、Webhookなど別の認証を持つエンドポイントに限定するべきである。
TrustProxies を削除して終わる
旧ミドルウェアを削除したあと、新しい trustProxies() を登録しなければ、プロキシ経由の動作が変わる。ローカル環境では問題が見えず、本番環境でHTTPS判定やIPアドレス取得が壊れるケースがある。
Docker Composeなどでリバースプロキシを構成している場合は、アプリケーションコンテナから見た接続経路を確認する必要がある。
移行後に見るべき計測結果
Laravel 11のミドルウェア登録方法を変更したあと、性能面も確認する。登録先や実行順序が変わると、すべてのリクエストに適用される処理量が変化する。
見るべき指標は、単純な平均応答時間だけではない。
- ミドルウェア実行前後の処理時間
- データベースクエリ数
- メモリ使用量
- 5xxエラー率
- APIとWebでの応答時間差
- 認証済みと未認証の処理時間差
たとえば、ログ出力用ミドルウェアをグローバルへ移した場合、管理画面だけでなく静的に近い公開エンドポイントにも処理が入る。処理自体が軽くても、ログの書き込み先が遅ければボトルネックになる。
ミドルウェアの登録変更は、構成変更であると同時に実行経路の変更でもある。コードの差分が数行でも、リクエスト全体の計算量が変わることがある。
外部APIやWebhookを扱う場合は、タイムアウトの変化も確認する。CSRF除外やプロキシ設定の移行に伴い、認証処理や署名検証の順序が変わると、外部接続の失敗として現れる可能性がある。
既存アプリケーションでは「新しくすること」より「正しく追跡できること」を優先する
Laravel 11の新構造は、ミドルウェア設定を bootstrap/app.php に集約できる。設定の入口が明確になる点は利点である。新規アプリケーションでは、withMiddleware() を中心に構成する方が自然である。
しかし、Laravel 10から更新する既存アプリケーションに対して、ディレクトリ構造まで一気に置き換える必要はない。公式もその移行を推奨していない。既存構造を維持したまま更新し、必要な範囲だけを変更する方が、差分と障害範囲を管理しやすい。
移行の基準は、Kernel.php が存在するかどうかではない。次の状態を説明できるかどうかである。
- ミドルウェアの正しい登録場所が分かっている
- 旧設定が無視される条件を把握している
- グローバルとグループの適用範囲を区別できている
- CSRF除外とプロキシ設定を移行できている
route:listと実際のリクエストで結果を検証している
ファイル構造の変更は目的ではない。アプリケーションの実行経路を正しく保つための手段である。
最後に、今回の変更における改善点とトレードオフを整理する。
- 改善点:Laravel 11ではミドルウェア設定が
bootstrap/app.phpに集約され、構成の入口が明確になる - 改善点:
append()、prepend()、web()などにより、登録位置の意図をコードで表現しやすい - 注意点:新形式を導入すると、旧
Kernel.phpの設定が警告なしに無視される可能性がある - 注意点:Laravel 10からの移行で新ディレクトリ構造を強制すると、不要な差分が増える
- トレードオフ:新構造は新規開発に適しているが、既存アプリケーションでは全設定の棚卸しが必要になる
- 検証方法:
php artisan route:list、php artisan schedule:list、実際のHTTPリクエストを組み合わせる
Laravel 11のミドルウェア登録方法は、記法の変更ではなく、アプリケーション構成の読み込み方式の変更である。旧ファイルを残すか削除するかより、どの設定が実際に読み込まれているかを確認することが重要である。