はじめに: CLBとGCSの落とし穴
Google Cloudで静的サイトをホスティングする際、CLB (グローバル外部アプリケーション ロードバランサ) と Cloud Storage (GCS) バックエンドの組み合わせは、セキュリティとパフォーマンスを両立する理想的な構成です。
しかし、
一般的なWebサーバーと異なり、CLBはルートURL(https://domain.com/)へのアクセスを自動で /index.html として処理してくれません。
なのでルートURL(https://domain.com/)にアクセスしてもxmlが表示されてしまいます。
この問題を解決するために、リダイレクトとリライトの2つのアプローチを比較し、最適な設定を解説します。
目標
ルートURL(https://domain.com/)にアクセスしindex.htmlを表示させつつ
さらにURLもルートURL(https://domain.com/)のままにする
※https://domain.com/index.htmlにならないようにする
前提

ルートについてはGoogle Cloudコンソールから変更はできるものの、
細かな設定ができないのでyamlファイルを作成してCLIから操作します。
※/と/index.htmlの関係性をうまく定義できないと無限リダイレクトが発生してしまいました。
失敗アプローチ – リダイレクトによる実現
最初に試したのは、fullPathMatch: / で厳密にルートパスのみをマッチさせ、/index.html へ301リダイレクトする方法でした。
# step1_redirect_with_fullpath.yaml
name: my-url-map
defaultService: projects/my-project/global/backendServices/my-backend-bucket
hostRules:
- hosts:
- '*'
pathMatcher: matcher1
pathMatchers:
- name: matcher1
routeRules:
- matchRules:
- fullPathMatch: /
priority: 1
urlRedirect:
pathRedirect: /index.html
redirectResponseCode: MOVED_PERMANENTLY_DEFAULT
stripQuery: false
defaultService: projects/my-project/global/backendServices/my-backend-bucket
結果
- index.htmlが表示されるようにはなった
- URLバーが /index.html に変わってしまう
- 目標である「URLを変えずに表示」を達成できない
ちなみに
prefixMatch に変更してテストもしてみました。
# step2_redirect_with_prefix.yaml
name: my-url-map
defaultService: projects/my-project/global/backendServices/my-backend-bucket
hostRules:
- hosts:
- '*'
pathMatcher: matcher1
pathMatchers:
- name: matcher1
routeRules:
- matchRules:
- prefixMatch: /
priority: 1
urlRedirect:
pathRedirect: /index.html
redirectResponseCode: MOVED_PERMANENTLY_DEFAULT
stripQuery: false
defaultService: projects/my-project/global/backendServices/my-backend-bucket
結果
現象変わらず、リダイレクトではうまくいかなそう
成功アプローチ – URLリライトによる実現
リダイレクト (urlRedirect) は、ブラウザに「別のURLに移動せよ」と指示するため、URLバーの表示が /index.html に変わってしまい、今回の要件には適さないことが判明しました。
解決策:URLリライト (urlRewrite)
CLBがリクエストを内部で書き換えてバックエンドに転送する URLリライト に切り替えました。
# step3_rewrite_final.yaml - 最終設計
name: my-url-map
defaultService: projects/my-project/global/backendServices/my-backend-bucket
hostRules:
- hosts:
- '*'
pathMatcher: matcher1
pathMatchers:
- name: matcher1
# --- [ ルートパス / から /index.html への URL 書き換えとルーティング ] ---
routeRules:
- matchRules:
# ★ 厳密にルートパス / のみに一致させる
- fullPathMatch: /
priority: 1
# ★ リダイレクトの代わりにルーティングアクションを設定
routeAction:
# パスを /index.html に内部的に書き換え
urlRewrite:
pathPrefixRewrite: /index.html
# 書き換え後のリクエストをバックエンドサービスに転送
weightedBackendServices:
- backendService: projects/my-project/global/backendServices/my-backend-bucket
weight: 100
# --- [ ルートパス以外の、その他の全てのパスの処理 ] ---
# /index.html や /images/ など、その他の全てのパスの処理は、
# このデフォルトサービスが引き続き担当します。
defaultService: projects/my-project/global/backendServices/my-backend-bucket
結果
みごとルートURL(https://domain.com/)のままindex.htmlの内容が表示されるようになりました。
各種パラメーターの説明
| 設定要素 | 役割 | 透過性の実現 |
|---|---|---|
| fullPathMatch: / | / のみに厳密に一致 | /index.html へのループを完全に回避 |
| routeAction | CLBが転送処理を実行 | ブラウザへのリダイレクト(301)を停止 |
| pathPrefixRewrite: /index.html | CLBはバックエンドにリクエストを送る際、パスを /index.html に書き換え | ユーザーのURLバーは / のまま変わらず、コンテンツが表示される |
| weightedBackendServices | 書き換え後のリクエストを明示的にバックエンドに転送 | 確実なルーティング |
| defaultService | その他のすべてのパスを処理 | リライト後の /index.html や、/images/ など、その他の全てのファイルリクエストを正常に処理 |
まとめ
Google Cloud CLBでルートパスを透過的に解決するには、URLリライトで実現することができました。
| アプローチ | URLバーの変化 | 最適な利用シーン |
|---|---|---|
| リダイレクト (urlRedirect) | ❌ 変わる(/index.html になる) | URLを永続的に変更したい場合 |
| リライト (urlRewrite) | ✅ 変わらない(/ のまま) | 静的サイトのルートファイル解決(本件の最適解) |
参考コマンド
# バックエンドサービスの確認 gcloud compute backend-services describe my-backend-bucket --global gcloud compute backend-services list --global # URL Mapの更新 gcloud compute url-maps import my-url-map \ --source=step3_rewrite_final.yaml \ --global # 設定の確認 gcloud compute url-maps describe my-url-map --global
この設定により、CLBのセキュリティを担保しながら静的サイトホスティングを実現させることができます。