はじめに
AWS App Runner で Cantaloupe(IIIF画像サーバー)をホストし、その前段に CloudFront を配置しようとしたところ、CloudFront 経由でアクセスすると全てのリクエストが 404 エラーになる問題に遭遇しました。
本記事では、問題の原因調査から試した解決策、そして結論までを記録します。
環境
- アプリケーション : Cantaloupe 5.0.5(IIIF画像サーバー)
- ホスティング : AWS App Runner
- CDN : Amazon CloudFront
- リージョン : ap-northeast-1(東京)
問題の概要
症状
| アクセス方法 | 結果 |
|---|---|
| App Runner に直接アクセス | 200 OK |
| CloudFront 経由でアクセス | 404 Not Found |
確認したこと
CloudFront 経由で 404 が返る際、レスポンスヘッダーに server: envoy が含まれていました。これは App Runner の内部プロキシ(Envoy)に到達していることを示しています。
つまり、CloudFront → App Runner の通信は成功しているが、App Runner 内部でリクエストがアプリケーション(Cantaloupe)に転送されていないことがわかりました。
原因
Host ヘッダーの問題
App Runner の内部では、Envoy がリバースプロキシとして動作しています。Envoy は Host ヘッダー を見てリクエストをルーティングします。
なぜ Host ヘッダーが CloudFront のドメインになるのか
CloudFront がオリジン(App Runner)にリクエストを転送する際、デフォルトではビューワーの Host ヘッダーがそのまま転送されます。
試した解決策
1. オリジンリクエストポリシー「AllViewerExceptHostHeader」
AWS が App Runner 向けに推奨しているポリシーです。このポリシーは Host ヘッダーを除外し、CloudFront がオリジンのドメイン名を Host ヘッダーとして自動設定するはずです。
結果 : ❌ 失敗(404 のまま)
2. オリジンリクエストポリシー「なし」
ビューワーのヘッダーを一切転送しない設定です。
結果 : ❌ 失敗(404 のまま)
3. カスタムオリジンリクエストポリシー
明示的に「ヘッダー: なし」を設定したカスタムポリシーを作成しました。
結果 : ❌ 失敗(404 のまま)
4. CloudFront Functions で Host ヘッダーを書き換え
ビューワーリクエスト時に Host ヘッダーを App Runner のドメインに書き換えようとしました。
結果 : ❌ 失敗
CloudFront Functions では、ビューワーリクエストイベントで Host ヘッダーは読み取り専用であり、変更できません。
5. Lambda@Edge で Host ヘッダーを書き換え
Lambda@Edge はオリジンリクエストイベントで実行でき、より多くのヘッダーを変更できます。
結果 : ❌ 失敗
Lambda@Edge のオリジンリクエストイベントでも Host ヘッダーは読み取り専用でした。
6. 新しい App Runner サービスと CloudFront ディストリビューションを作成
既存の設定に問題がある可能性を考え、完全に新しいリソースを作成しました。
- 新しい App Runner サービス(カスタムドメインなし)
- 新しい CloudFront ディストリビューション
- オリジンリクエストポリシー「AllViewerExceptHostHeader」
結果 : ❌ 失敗(404 のまま)
調査で判明したこと
App Runner のログ確認
App Runner に直接アクセスした場合のログ:
CloudFront 経由でアクセスした場合:
- Cantaloupe のログにリクエストが記録されない
- つまり、Envoy がリクエストをアプリケーションに転送する前に 404 を返している
curlで Host ヘッダーを変更してテスト
App Runner に直接アクセスする際、Host ヘッダーを CloudFront のドメインに変更:
404 が再現しました。 これで、問題は Host ヘッダーにあることが確定しました。
結論
問題の本質
CloudFront + App Runner の組み合わせで 404 エラーが発生する問題は、App Runner の Envoy が Host ヘッダーでルーティングを行っている ことが原因です。
「AllViewerExceptHostHeader」ポリシーを使用しても解決しない場合、これは App Runner 側の問題 と考えられます。
推奨される対応
AWS サポートに問い合わせる
- App Runner + CloudFront で 404 が発生する問題として報告
代替アーキテクチャを検討する
- ECS Fargate + ALB : CloudFront との連携実績が豊富
- EC2 + Nginx : 最も柔軟な構成
- Cloudflare : Host ヘッダーの書き換えが容易
参考情報
同様の問題を報告している記事
- AWS App Runner - App Runner インスタンスの前に Cloudfront ディストリビューションを配置する (Reddit)
- 解決!AWS App RunnerとCloudFrontの404エラー問題 (Zenn)
これらの記事では「AllViewerExceptHostHeader」で解決したと報告されていますが、今回のケースでは解決しませんでした。
AWS ドキュメント
まとめ
| 試した方法 | 結果 |
|---|---|
| AllViewerExceptHostHeader | ❌ |
| オリジンリクエストポリシー「なし」 | ❌ |
| カスタムポリシー(ヘッダーなし) | ❌ |
| CloudFront Functions | ❌ (Host は読み取り専用) |
| Lambda@Edge | ❌ (Host は読み取り専用) |
| 新規リソース作成 | ❌ |
設定はすべて正しいにもかかわらず動作しないため、App Runner の内部動作に起因する問題と考えられます。CloudFront + App Runner の組み合わせを検討している方は、この問題に遭遇する可能性があることを念頭に置いてください。