Casdoor で CDN に静的ファイルをホストする方法: S3、MinIO、Azure Blob およびその他のストレージプロバイダ
CDN に静的ファイルをホストするには、オブジェクトストレージ (Amazon S3、MinIO、Azure Blob Storage、Google Cloud Storage、Alibaba Cloud OSS または Tencent Cloud COS) にファイルを配置し、CDN のオリジンとしてそのバケットからプルするように設定し、CDN ドメイン上の URL を配布します。Casdoor ではこれは 1 つの設定で行えます: バケット用のストレージプロバイダを作成し、その Domain フィールドに CDN アドレスを入力します。Casdoor はプロバイダの API を通じてアバターやその他のファイルをアップロードし、そのドメインで始まる URL を保存します。Casdoor のフロントエンドも app.conf の frontendCdnUrl と staticBaseUrl を介して CDN から提供できます。
ストレージプロバイダ一覧
ストレージプロバイダは、Casdoor がアップロードされたファイル (ユーザーアバター、ID カード画像、利用規約ページ、および Resources ページでアップロードされたものなど) をどこに書き込むかを決定します。プロバイダをアプリケーションに追加すると、そのアプリケーションでのアップロードはそこに保存されます。storage provider overview にすべてのタイプがリストされています。この表では、よく質問されるものをカバーしています:
| ストレージ | Casdoor プロバイダタイプ | Casdoor は S3 API を使用しますか? | セルフホスティング可能 | 公開 URL の設定方法 |
|---|---|---|---|---|
| ローカルファイルシステム | Local File System | いいえ、ディスク上のプレーンなファイル | はい、Casdoor サーバーです | /files/ 下で Casdoor によって配信されます。Domain は読み取り専用です |
| Amazon S3 | AWS S3 | はい | いいえ | Domain: バケット URL または CloudFront ドメイン。Endpoint (Intranet): VPC エンドポイント |
| MinIO | MinIO | はい、パススタイルのリクエスト付き | はい | Domain: バケット名が続く MinIO URL、または CDN ドメイン |
| Alibaba Cloud OSS | Aliyun OSS | いいえ、OSS SDK | いいえ | Domain: CDN ドメイン。空の場合、bucket.endpoint になります。Endpoint (Intranet): 内部エンドポイント |
| Tencent Cloud COS | Tencent Cloud COS | いいえ、COS API | いいえ | Domain: CDN ドメイン |
| Azure Blob Storage | Azure Blob | いいえ、Blob API | いいえ | Domain: カスタムドメインまたは Front Door ドメイン。Casdoor はパスにコンテナ名を追加します |
| Google Cloud Storage | Google Cloud Storage | いいえ、Google の Go クライアント | いいえ | Domain: 空の場合、https://storage.googleapis.com になります。Casdoor はパスにバケット名を追加します |
| Synology NAS | Synology | いいえ、DSM File Station API | はい | Domain フィールドはありません。URL は Endpoint に基づいています |
Casdoor はまた、Qiniu Cloud Kodo、CUCloud OSS、および他の Casdoor インスタンスにファイルを保存する Casdoor もサポートしています。各プロバイダガイド (Amazon S3、MinIO、Azure Blob、Google Cloud Storage、Alibaba Cloud OSS、Tencent Cloud COS、Synology NAS および local file system) では、どの値をどのフィールドに入れるかが示されています。
Endpoint と Domain の違い
これらの 2 つのフィールドは異なる役割を果たしており、多くの CDN の問題はこれらを混同することから生じます。
- Endpoint は、Casdoor がストレージ API (アップロード、削除、リスト表示) と通信するために使用するアドレスです。CDN は関与しません。
- Endpoint (Intranet) は、
app.confでisCloudIntranet = trueが設定されている場合、Endpoint の代わりに使用されます。これにより、Casdoor が同じクラウド内で実行されている場合、アップロードトラフィックはプロバイダーの内部ネットワーク上に保持されます。このフィールドは、AWS S3、Aliyun OSS、Azure Blob、CUCloud OSS に表示されます。 - Domain は、Casdoor が保存し、ブラウザがリクエストする URL のベースです。CDN を使用している場合は、そのドメインをここに指定します。
- Path prefix は、すべてのオブジェクトキーの前に付加されます。プレフィックスを
casdoorにすると、アバターはcasdoor/avatar/...配下に配置されます。
Casdoor は、ファイル URL を Domain のスキームとホスト、次に Domain のパス、次に path prefix、最後にファイルパスから構築します。Domain にスキームがない場合は https:// が追加されます。Domain のパス部分はオブジェクトキーの一部にもなるため、https://cdn.example.com/casdoor/ と指定すると、ファイルはバケット内の casdoor/ 配下に保存されます。Azure Blob と Google Cloud Storage では、Casdoor はコンテナ名またはバケット名をホストの後の最初のパスセグメントとして追加します。CDN がそのパスを提供する必要があります。
Domain が空の場合、Casdoor はプロバイダーを初めて使用する際に、プロバイダーのエンドポイントから値を入力して保存します。OSS や GCS などでは、この方法で正常に動作することがあります。しかし、S3 エンドポイントにバケット名が含まれない場合や、MinIO のようにパススタイルのリクエストでバケット名をパスに含める場合など、生成された URL にバケットが含まれず動作しないこともあります。自分で Domain を設定し、テスト用のアバターをアップロードして、他の人が使用する前に Casdoor が返す URL を開いて確認してください。
Casdoor がソーシャルログインからコピーしたアバター用に使用するプロバイダーは、app.conf の defaultStorageProvider から取得されます。これは admin が所有するプロバイダーの名前です(構成リファレンスを参照):
defaultStorageProvider = provider_storage_s3
isCloudIntranet = false
公開バケット、非公開バケット、および署名付き URL
Casdoor は、ユーザーの avatar フィールドとリソースレコードに、プレーンな永続的な URL を 1 つだけ保存します。これらのファイルに対して署名付き URL や期限切れになる URL は作成しません。したがって、Domain にあるものは匿名の GET リクエストに応答できる必要があります。それを実現する方法は 2 つあります。
オブジェクトを公開にする。 AWS S3 と MinIO では、Casdoor はすべてのオブジェクトを public-read キャンド ACL でアップロードします。Aliyun OSS でも、クライアントライブラリがデフォルトで同じ動作を行います。S3 では、新しいバケットのデフォルト設定と競合します。AWS によると、新しいバケットは ACL を無効化する Bucket owner enforced 設定を使用するため、public-read などの ACL を設定したアップロードは AccessControlListNotSupported エラーで失敗します。そのため、Amazon S3 ガイドでは、ACL を有効にし、Block all public access をオフにするよう指示しています。OSS では、オブジェクト ACL がバケット ACL より優先されるため、プライベートバケット内でも public-read オブジェクトを読み取ることができます。MinIO は匿名読み取りに ACL を使用せず、バケットポリシーを使用します:
mc anonymous set download myminio/casdoor
Azure では、ストレージアカウントで匿名アクセスを許可し、コンテナのアクセスレベルを Blob に設定する必要があります。Google Cloud Storage では、バケットに対して allUsers に Storage Object Viewer ロール (roles/storage.objectViewer) を付与する必要があります。
バケットを非公開のままにし、CDN だけが読み取れるようにする。 CDN はオリジンへのリクエストに署名を行い、ビューアーは署名なしで CDN 経由でアクセスします。各ベンダーには独自の実装があります:
- CloudFront には Origin Access Control (OAC) があります。AWS では OAC に Bucket owner enforced を要求するか、ACL が必要な場合は Bucket owner preferred を使用します。
- Alibaba Cloud CDN は、認可を行うことでプライベート OSS バケットからフェッチできます。
- Tencent Cloud CDN には、プライベート COS バケット向けのオリジンプル認証があります。
- Azure Front Door Premium は、Private Link を介してストレージアカウントに到達できます。
- Google の Cloud CDN ガイドでは、プライベートバケットへのアクセスについても扱われており、Storage Object Viewer ロールを
allUsersの代わりにサービスアカウントに付与します。
これによりバケット自身の URL は隠されますが、ファイルは CDN 経由で依然として公開されています。AWS S3 および Aliyun OSS タイプの場合、Casdoor が設定する public-read ACL により、オブジェクトはバケット URL でも読み取り可能になります。
アバターを一切公開したくない場合は、オブジェクトストレージの前に CDN を置くのは適切なツールではありません。それらのファイルは自分が管理するストレージタイプに保持し、そのホストに到達できるユーザーを制限してください。
キャッシュヘッダーとアバターの落とし穴
S3 と MinIO では、Casdoor はアップロード時にファイル拡張子から Content-Type を設定します。どのプロバイダーでも Cache-Control は設定されません。つまり、CDN のデフォルト TTL が適用されます。CloudFront では、Cache-Control がないオブジェクトはデフォルト TTL(キャッシュポリシーを使用しない場合は 24 時間)でキャッシュされます。オブジェクト単位でこれを制御するには、バケット内に Cache-Control メタデータを追加します。パス全体に対しては、CDN 上でキャッシュルールを使用します。
アバターには短い TTL が必要です。ユーザーが画像を変更すると、Casdoor は同じキー avatar/<organization>/<username>.<extension> に新しいファイルを書き込み、同じ URL を保存します。TTL が長いと、期限切れになるか、そのパスを手動でパージまたは無効化しない限り、人々は古い画像を見続けることになります。その他のアップロードでは、名前が既に使われている場合に番号付きサフィックス(-1, -2, ...)が付与されるため、新しいアップロードは新しい URL を取得し、長期キャッシュが可能になります。
効果的なレイアウト例:
| パス | 推奨キャッシュ |
|---|---|
avatar/* | 短い TTL(数分)、または変更時のパージ |
resource/* およびその他のアップロード | 長い TTL |
ハッシュ化されたフロントエンドアセット (assets/*) | 非常に長い TTL。ビルドごとにファイル名が変更されます |
CDN 上の Casdoor フロントエンド
ユーザーアップロードとは別に、Casdoor 自身の静的ファイルを Casdoor サーバーから移動する方法が 3 つあります。
frontendCdnUrl。 casdoor-web npm パッケージからフロントエンドをインストールする場合に使用します。npm CDN を指すように設定します。例えば:
frontendCdnUrl = "https://cdn.jsdelivr.net/npm/{name}@{version}"
Casdoor はビルドフォルダ内の package.json からパッケージ名とバージョンを読み取ります。index.html 内のスクリプトとスタイルシートリンクをその CDN に書き換え、ローカルパスをフォールバックとして保持します。ファイルの読み込みに失敗した場合、ブラウザは Casdoor からファイルを読み込み、Cookie によりそのセッション中はブラウザをローカルファイルに留めます。自分でビルドしたフロントエンドにはこのような package.json がないため、この設定は影響しません。
デプロイスクリプト。 ソースからビルドするフロントエンドの場合、フロントエンドファイルを CDN にホストする で deployment/deploy_test.go について説明しています。これは web/build/assets/ をストレージプロバイダーのいずれか経由でアップロードし、index.html がプロバイダーの Domain を指すようにします。Domain は / で終わる必要があります。Vite はこれらのファイル名にハッシュ値を付与するため、上記の表にある長い TTL に適しています。
staticBaseUrl。 これはロゴ、プロバイダーアイコン、デフォルトアバターなどのデフォルト画像の取得元を設定します。デフォルトは https://cdn.casbin.org で、casbin/static リポジトリを提供します。インターネットアクセスがないネットワークでは、そのリポジトリのコピーを自分で提供し、イントラネットに静的ファイルをホストする に記載されているように staticBaseUrl をそこに向けます。
選択肢の決定
- 単一サーバー、小規模なユーザー基盤:
Local File System。Casdoor がコンテナで実行されている場合は、filesディレクトリをボリュームにマウントします。Casdoor はこれらのファイルに対してX-Content-Type-Options: nosniffとサンドボックス化されたContent-Security-Policyを送信するため、アップロードされた HTML または SVG ファイルが Casdoor ドメイン上でスクリプトを実行することはできません。 - セルフホストおよび S3 形状:
MinIO。他の S3 互換ストレージに対してもドキュメントで推奨されるタイプです。 - すでにクラウドを利用している場合: そのクラウドのオブジェクトストレージと CDN を使用し、Casdoor が同じクラウド内で実行されている場所には Endpoint (Intranet) を設定し、Domain を CDN に設定します。
参考資料
- Casdoor ストレージプロバイダー およびソースコード:
object/storage.go,storage/,routers/frontend_cdn.go - AWS: オブジェクトの所有権の制御と ACL の無効化, Amazon S3 オリジンへのアクセス制限, コンテンツがキャッシュに残存する期間の管理
- MinIO:
mc anonymous set - Microsoft: コンテナーとブロブの匿名読み取りアクセスの設定, Azure Storage アカウントと Azure Front Door の統合
- Google Cloud: データの公開, バックエンドバケットで Cloud CDN をセットアップ
- Alibaba Cloud: オブジェクト ACL, プライベート OSS バケットからのオリジンフェッチ
- Tencent Cloud: COS のための CDN 加速の設定