おそらく自分自身の質問に答える形になりますが、Garage をあなたのランブック(手順書)と合わせて使用しようとした際のメモをいくつか記載します。
1. Garage はファイルへの「権限タグ」をサポートしていません(これが Garage の真のギャップです)
Amazon では、各ファイルを個別に「公開」または「プライベート」としてタグ付けできます。Garage はこれを実装していません。
Discourse はデフォルトでこれを使用しようとします。こそこそとした点は、Discourse が「このファイルを保存し、公開としてマークせよ」と指示した際、Garage がリクエストを受け入れ、タグを静かに無視したことです。そのため、基本的なアップロードは問題なく見え、誰かがアップロードをプライベートに設定しようとした初めての場合にのみ、後になって問題が発生しました。
解決策: Discourse にタグの使用を停止させる(設定項目1つ)。Cloudflare の R2 も同様のギャップがあり、同じ解決策が適用されます。Garage はバケットレベルで独自の方法で権限を処理しており、それが私たちに必要なすべてです。
2. Discourse はバケット名を特定の形式にするよう要求します(Garage の欠陥ではありません)
Discourse は「garage サーバー上の uploads バケット」とは言いません。サブドメインのようにバケット名を前方に結合した uploads.garage を要求します。これをオフにするオプションはありません。
私たちのネットワークにはその名前を知っているものが何もなかったため、Discourse はまったく接続できず、インストールは途中で失敗しました。
解決策: Garage にその命名形式を与え、名前を登録しました。設定が2行です。
これは Garage の問題ではなく、Discourse の既知の癖です。これが Oracle のストレージが Discourse の公式「動作しない」リストに掲載されている理由です。
3. 画像には公開用の Web アドレスが必要でした(Garage に関係ありません)
Discourse は各画像のアドレスを投稿に永久に書き込みます。事前に公開アドレスを指定しないと、内部アドレス(サーバーのみがアクセス可能)が保存されてしまい、すべての投稿を再構築しない限り、訪問者にとって画像は永遠に壊れた状態になります。
解決策: 最初のアップロード前に CDN アドレスを設定しました。Amazon や R2 などでも同じでした。
注: これらのすべてはサイレント(無音)でした。「未サポート」というメッセージは出ませんでした。1つはリクエストを受け入れて無視し、1つはネットワークエラーのように見え、1つは正常に動作しているように見えました。
したがって、これを初めて試みる新規ユーザーや、Michael のランブックを Garage と合わせて使用しようとする人が念頭に置いておくべき初期の事項です。
フォーラムがデプロイされた現在、私たちの経験に基づく完全な AI メモは以下の通りです:
Cloudflare トンネルの背後にあるセルフホスト型 Garage(S3)上での Discourse 実行 — メモ
Garage は「S3 互換オブジェクトストレージプロバイダーの構成」互換性テーブルに掲載されていませんので、ここにデータポイントを示します。設定: Garage v2.3.0、2コンテナの Discourse、Debian 13、単一ノード、外部 nginx の代わりに Cloudflare トンネル。前置きとして: これはまだ本番トラフィックのない小規模なデプロイメント1つですので、「動作する」として扱ってください。「Maker Forums 規模での実戦テスト済み」としては扱わないでください。
動作します。CLI ではなく、Discourse 自身のコードパス(UploadCreator、OptimizedImage、ListObjectsV2、HeadObject/GetObject のバイト完全なラウンドトリップ、マルチパート、delete、remove_upload、および BackupRestore::Backuper がバックアップバケットへの書き込みと BackupStore#files / #download_file による読み取り)に対して検証しました。ライフサイクル構成が機能するため、s3_configure_tombstone_policy は実際に効果を持ち、静かに無視されることはありません。PutBucketCors も機能するため、手動の CORS は問題ありません。
バーチャルホストスタイルのアドレシングを構成する必要があり、構成しないと db:migrate が壊れます。Discourse はエンドポイント http://garage:3900 とバケット “uploads” をホスト uploads.garage:3900 に変換し、s3_helper.rb や site_settings.yml にはパススタイルのオプションがどこにもありません。2つの要素が必要です:garage.toml の [s3_api] 下の root_domain、およびバケットごとに解決可能な DNS 名(Docker DNS にワイルドカードがないため、バケットごとに Docker ネットワークエイリアス)。これを逃した場合の症状は、SiteIconManager.ensure_optimized! 中の getaddrinfo に関する Aws::Waiters エラーであり、ストレージ障害ではなくネットワーク障害のように見えます。新しいバケットごとに新しい名前が必要です。
Garage は PutObjectAcl / GetObjectAcl を実装していないため、s3_use_acls を false に設定します — R2 と同じです。ここに2つの罠があります。第一に、–acl public-read を付けた PutObject は静かに受け入れられ、ヘッダーは無視されるため、基本的なアップロードテストは通過し、セキュアアップロードへの移行時に後になって壊れます。第二に、DISCOURSE_S3_USE_ACLS はシャドウされたグローバル変数ではありません — app.yml に設定しても何の効果もありません。環境変数に入れていたにもかかわらず、最初の起動で true として検出されました。これはサイト設定である必要があり、何の警告もないため、再構築後毎回再確認する必要があります。
CDN を前面に配置する場合、それを Garage の WEB エンドポイント(:3902)に向け、S3 API(:3900)には向けません。匿名読み取りは Web エンドポイントでのみ機能し、S3 API は認証されていないリクエストを正しく 403 で拒否するため、:3900 をターゲットにした CDN は、資格情報が完全に有効であってもすべての画像で失敗します。また、アップロードバケットで
garage bucket website --allowを実行し、[s3_web] 下に root_domain を設定する必要があります。アップロードバケットでのみ有効にしてください — バックアップバケットは決して匿名で読み取り可能であってはいけません。ListObjectVersions は Garage で NotImplemented を返します。問題ありません:s3_helper.rb と file_store/s3_store.rb を grep して list_object_versions / object_versions を検索してもゼロヒットです。Discourse は S3 オブジェクトバージョニングを使用しません;トombstone の有効期限はライフサイクルルールとプレフィックスです。
aws-cli や mc でのテストは互換性を証明しません。どちらもカスタムエンドポイントに対してパススタイルアドレシングをデフォルトにします;Discourse はバーチャルホストスタイルのみを使用します。私の CLI テストは 15/16 でグリーンライトのように見えました、しかし実際のインストールはアドレシングの違いで即座に失敗しました。同じストア、同じ資格情報、同じ操作です。未証明の S3 バックエンドを評価している場合は、実際の Discourse を動かしてください — 使い捨ての単一コンテナインスタンスで十分です、そしてコンテンツが存在する前に実行することがすべてであり、S3 → ローカルは一方通行です。
Cloudflare トンネルに特化して: external-nginx-for-SSL セクションは適用されません(TLS はエッジで終了し、certbot も、80/443 のインバウンドもありません)、しかし real-IP アウトレット構成は依然として必須であり、むしろ重要かもしれません。X-Forwarded-For の代わりに real_ip_header CF-Connecting-IP を使用してください — トンネルが唯一のイングラSPATHである場合、それは単一の明確なエッジセット値です。既知の公開 IP から投稿し、nginx がログに記録したものを確認して検証してください;これを設定しないと、Discourse はすべてのリクエストに対してコネクタの Docker アドレスを記録し、インターネット全体を1つのクライアントとしてレート制限します。external-nginx アプローチと比較して失うのは、再構築中のメンテナンスページです — cloudflared はそれを提供できません。
広く(誤って)伝えられていることに対する軽微な修正、私自身も含めて: DISCOURSE_S3_CDN_URL は格納された URL に不可逆的に焼き付けられるわけではありません。upload.url は内部ホストを持つ生の S3 URL を格納しますが、Discourse は Discourse.store.cdn_url / UrlHelper.cook_url を介してレンダリング時に CDN ホストを置換します。後で設定しても回復可能です — コストは
rake posts:rebakeです、なぜなら posts.cooked は cook 時の HTML をキャッシュするからです。それでも最初のアップロード前に設定してください;ただし、設定しなかったからといってパニックにならないでください。Garage に関連しない2つの運用上の注記。./launcher は DISCOURSE_S3_SECRET_ACCESS_KEY を含む完全な docker run コマンドをプレーンテキストでエコーするため、ブートストラップログは秘密情報を含みます — 騒がしいインストール後にキーをローテーションする価値があります。また、単一ノードの Garage でも、何かを格納する前に
layout assign+layout applyを必要とし、replication_factor = 1 は複製を意味しないため、バックアップジョブが唯一の耐久性となります。