Set up file and image uploads to S3

So, you want to use S3 to handle image uploads? Here’s the definitive guide, but also see Configure an S3 compatible object storage provider for uploads to see how to configure your app.yml.

S3 registration

Head over to https://aws.amazon.com/free/ and click on Create a Free Account

During the create account process, make sure you provide payment information, otherwise you won’t be able to use S3. There’s no registration fee, you will only be charged for what you use, if you exceed the AWS Free Usage Tier.

Bucket

Go to S3 and click on Create bucket, then fill out the Bucket name. Remember this name because we’ll need it for the next step.

Name of your bucket

Select a Region. You should enter the location (eg. “EU (Frankfurt)”) that is nearest to your users for better performance.

Scroll down a little until you get to the Permissions panel.

  • When you set up the permissions, make sure that you allow public ACLs, otherwise uploads will fail. Uncheck Block all public access and check the bottom two checkboxes. You’ll also have to acknowledge that your settings may make the bucket public in the warning at the top.

User creation

Creating a policy

Sign in to AWS Management Console and search for the “IAM” service to access the AWS Identity and Access Management (IAM) console which enables you to manage access to your AWS resources.

First, click Policies in the sidebar. Then, click on Create Policy and choose the JSON tab:

image

Use the following piece of code as a template for your policy document:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
               "s3:List*",
               "s3:Get*",
               "s3:AbortMultipartUpload",
               "s3:DeleteObject",
               "s3:PutObject",
               "s3:PutObjectAcl",
               "s3:PutObjectVersionAcl",
               "s3:PutLifecycleConfiguration",
               "s3:CreateBucket",
               "s3:PutBucketCORS"
      ],
      "Resource": [
        "arn:aws:s3:::=BUCKET=",
        "arn:aws:s3:::=BUCKET=/*"
      ]
    },
    {
       "Effect": "Allow",
       "Action": [
           "s3:ListAllMyBuckets",
           "s3:ListBucket"
       ],
       "Resource": "*"
    }
  ]
}

:warning: Make sure that these two lines contain the actual name of your bucket. :blush:

image

:star2: If you also intend to do S3 backups, you can include your backup bucket here too like this:

image

Then click on Review Policy and fill out the Name field. For example, you can call it s3-discourse-policy

Then click on Create Policy at the bottom.

Creating a user account

Now that you’ve created the right policy, you’re ready to create the user account. Click on the Users link on the left side of the IAM console and then the Add user button.

Type in a descriptive user name and make sure the “Programmatic access” checkbox is checked.

Setting permissions

The next step in the process is to configure the user’s permissions. Click on the button that says Next: Permissions and then click on «Attach existing policies directly»:
image

Now search for the policy name you created in the previous step (in our case it’s s3-discourse-policy). When you find it, select the checkbox and click on Next: Tags, then Next: Review, then finally Create user.

Here’s the critical step: Make sure you either download the credentials (Download .csv) or you copy and paste somewhere safe both Access key ID and Secret access key values. We will need them in the next step.

Discourse configuration

Now that you’ve properly set up S3, the final step is to configure your Discourse forum. These instructions should work, but the preferred method is to use environment variables and a CDN as described in Configure an S3 compatible object storage provider for uploads.

Make sure you’re logged in with an administrator account and go the Settings section in the admin panel.

Type in “S3” in the textbox on the right to display only the relevant settings:

You will need to:

  • Check the “enable s3 uploads” checkbox to activate the feature
  • Paste in both “Access Key Id” and “Secret Access Key” in their respective text fields
  • Enter =BUCKET= in the “s3 upload bucket” field

You need to append a prefix to the bucket name if you want to use the same bucket for uploads and backups.

Examples of valid bucket settings
  1. Different buckets

    • s3_upload_bucket: =BUCKET=
    • s3_backup_bucket: =BACKUPS=
  2. Different prefixes

    • s3_upload_bucket: =BUCKET=/uploads
    • s3_backup_bucket: =BUCKET=/backups
  3. Prefix for backups

    • s3_upload_bucket: =BUCKET=
    • s3_backup_bucket: =BUCKET=/backups

The “s3_region” setting is optional and defaults to “US East (N. Virginia)”. You should enter the location (eg. “EU (Frankfurt)”) that is nearest to your users for better performance. If you created the bucket manually, you’ll need to select the region you selected during the creation process.

Enjoy

That’s it. From now on, all your images will be uploaded to and served from S3.

Backups

Do you want store backups of your Discourse forum on S3 as well? Take a look at Configure automatic backups for Discourse.

Frequently Asked Questions

I reused the same bucket for uploads and backups and now backups aren’t working. What should I do?

Name of your bucket for backups

The easiest solution is to append a path to the s3_backup_bucket. Here’s an example of how your settings should look afterwards.

  • s3_upload_bucket: =BACKUPS=
  • s3_backup_bucket: =BACKUPS=/backups

You can use the S3 Console to move existing backups into the new folder.

Do I really need to use separate buckets for uploads and backups?

No, you don’t, but it’s usually the easiest way to set-up. Essentially you need to either use two different buckets or a prefix for the backup bucket. For example, the following combinations will work:

  1. Different buckets

    • s3_upload_bucket: =BUCKET=
    • s3_backup_bucket: =BACKUPS=
  2. Different prefixes

    • s3_upload_bucket: =BUCKET=/uploads
    • s3_backup_bucket: =BUCKET=/backups
  3. Prefix for backups (not recommended unless you previously reused the same bucket – see above question)

    • s3_upload_bucket: =BACKUPS=
    • s3_backup_bucket: =BACKUPS=/backups

I’ve enabled S3 uploads in my Discourse instance (which has been going for a while); what do I do with the existing local uploads?

To migrate your existing uploads to S3, you can do a couple of rake tasks. To perform this, you need SSH access, root permissions, and have entered the discourse app (as per Administrative Bulk Operations). Oh, and you have to set some environmental variables in app.yml. Not for the faint-hearted.

Once you have done all that you are ready for the rake tasks:

rake uploads:migrate_to_s3

Once that is done, posts that need to be rebaked will be marked accordingly and will be rebaked by a regular task. If you have resources and are in a hurry, you can issue this command (which is recommended by the above rake task):

rake posts:rebake_uncooked_posts

Once the posts are all rebaked (and the uploads are working well) you no longer need to include uploads in your backups. And as a bonus, you will be able to Restore a backup from the command line in the event of catastrophe (just keep a copy of app.yml somewhere).

One-way door

Unlike many configuration decisions in Discourse, note that using S3 is a “one-way door;” that is, a move that cannot easily be reversed. There is no safe or maintained way to move files out of S3 to be in the local uploads. In particular, the migrate_to_s3 moves more than just post images to S3; files for which there is no reverse path. (For more details, see Migrate_from_s3 problems).

Backing up your S3 assets

Using versioning, or syncing to a different region are all good strategies.

「いいね!」 106

このナラティブを更新する必要があります。そうしないと、できません。インストール後、画像はバケットにアップロードされますが、アクセスできません。何をしても、うまくいきませんでした。最近これを試して、うまくいった人はいますか?

「いいね!」 1

アクセスしようとするとどうなりますか?

CDNはありますか?

どのサービスを使用しましたか?

画像はアップロードされており、バケットの権限で表示できないのですか?

PMを更新する必要がある場合は、何をして、何が起こっているのかについて、より多くの情報を提供する必要があります。

サイトは公開されていますか?どこで

「いいね!」 1

説明を正確に実行し、画像をアップロードしましたが、画像にアクセスできません。例のURL: https://awssorucevap24.s3.eu-central-1.amazonaws.com/original/2X/6/62c89621b0764112e0029bc91c957dd49d75d819.jpeg

パーミッションセクションは以下のようになっています。

バケットをインストールする際にACLを開いていません。それに関する情報がなく、以前試した際にこの設定を変更してもアクセスできませんでした。

追加メモ: ユーザーを作成する際に「プログラムによるアクセス」の設定がありません。これは以前はありましたが、今はもうありません。これに関連しているのでしょうか?または、ユーザー作成時の新しいシステムでどのように設定できるか説明していただけますか?

CloudFrontとCDNドメインも準備しました。唯一の問題は、ファイルにアクセスできないことです。見落としている点が見つかることを願っています :slight_smile:

「いいね!」 1

rake uploads:migrate_to_s3
FileStore::ToS3MigrationError: Please provide the following environment variables: (FileStore::ToS3MigrationError)

  • DISCOURSE_S3_BUCKET
  • DISCOURSE_S3_REGION
    and either
  • DISCOURSE_S3_ACCESS_KEY_ID
  • DISCOURSE_S3_SECRET_ACCESS_KEY
    or
  • DISCOURSE_S3_USE_IAM_PROFILE

アクセスキーまたはIAMプロファイルではないことがわかります。私の場合はIAMプロファイルを使用しています。何か推奨事項はありますか?

「いいね!」 1

YAMLファイルでこのデータを定義する必要があると思います。まず、アップロードプロセスが機能することを確認してから、移行してください。

ちなみに、どのように設定しましたか?私はこれを試しましたが、ファイルはアップロードされましたが、ブラウザで開けませんでした。アクセス拒否エラーが出ていました。

「いいね!」 1

アップロードとパブリック読み取りアクセスは正しく機能しています。

IAMロールとEC2にアタッチされたポリシーを使用しています。詳細が必要な場合はお知らせください。

ああ、あなたのケースで何が起こっているのか分かりました。これらの設定を確認してください。

パブリックアクセスをブロック(バケット設定)

オブジェクト所有権

アクセス制御リスト(ACL)-- おそらくここで解決策が見つかるでしょう

「いいね!」 3

ACL設定の有効化について説明に記載がなかったので、毎回触らずにやってみました。

もう私には重要ではないので、Cloudflare R2に切り替えます。この説明は将来、他の誰かにとって非常に役立つでしょう。ありがとうございます。

「いいね!」 2

これが最善の設定かどうかはわかりませんが、今のところ見つけた方法です。@teamに確認して、私たちを導いてくれるようお願いしたいと思います。

これを安全かつ正しく機能させるための最善の方法はありますか?

「いいね!」 2

これについて、もう少し詳しく教えていただけますか?

「いいね!」 1

かなりの試行錯誤の末、R2に切り替えました(助けてくれた友人たちに感謝します)。アセットとアップロードファイルはCloudflareに公開されています。唯一の問題は、テーマのJavaScriptとスタイルシートファイルをR2に自動的にアップロードできなかったことです。時間があるときにこの問題について調査します。

「いいね!」 1

これは技術的な決定でしたか、それともコストに関する決定でしたか、あるいはその両方でしたか?

「いいね!」 1

最初のものは技術的な話で、Amazonをインストールできませんでしたが、すでにCloudflareを使用していたので、そこからCDNをインストールすればいいのではないかと思いました。そして、Cloudflareが私たち開発者向けに、非常に高価なS3クラウドシステムに対抗してこのサービスをローンチしたのだから、良い決断だったとわかりました。とても素晴らしいと思いませんか?

「いいね!」 1

いいですね。詳しく見てみます。

そして、ディスコースへの統合についてはどうでしたか?どのような経験でしたか?

Cloudflare WAFも使用していますか?

「いいね!」 1

いいえ、まだ使用していません。実際、必要かどうかはわかりません。しかし、Cloudflareの「ARGO」を使用しています。

「いいね!」 2

画像アップロード用の S3 バケットがあり、ACL が有効で、スタンドアロンインスタンスを実行している EC2 インスタンスに適切に設定および割り当てられた IAM ロールがあります。しかし、テスト投稿の S3 画像 URL が表示されません。ログインしている Discourse ユーザーのみが表示できるバケットで S3 画像をホストしたいと考えています。S3 画像への URL 参照に、適切なアクセス用の署名付き URL が含まれていないのはなぜですか? S3 コンソール経由でファイルにアクセスし、AWS 経由で 10 分間など定義された時間だけ署名付き URL をリクエストすると、画像は期待どおりに読み込まれるため、機能することはわかっています。

「いいね!」 1

app.ymlファイルにデータを定義する必要があることを確認していますか?

私はこのようにしました。

# アプリに入る
cd /var/discourse
./launcher enter app

# 環境変数を使用して実行時にコマンドを渡す
DISCOURSE_S3_BUCKET=my-bucket DISCOURSE_S3_REGION=us-east-1 DISCOURSE_S3_ACCESS_KEY_ID=abcdefg DISCOURSE_S3_SECRET_ACCESS_KEY=zxywqrst rake uploads:migrate_to_s3

アクセスキーをYAMLファイルに残したくなかったので、このようにしました。アクセスキーはさまざまな場所にバックアップしています。環境変数経由でAWSシークレットキーを渡す方が、一般的に少し「安全」だと思います。そうですよね?コンテナ内のスクロールバック履歴がどれくらい持続するかはわかりませんが、コンテナが再起動すると消去されると推測しています。

代わりに、サーバーの~/.aws/credentialsファイルにAWSアクセスキーとシークレットキーを保存するという「通常の」方法でS3アクセスを設定したかったのですが、コンテナ内で実行されているアプリでそれがどのように機能するかはよくわかりません。

また、ここのガイドによると、アクセスキーとシークレットキーをDiscourse管理設定のWeb UIにコピー&ペーストして保存するように指示されています。これらのキーがバックエンドのどこに保存されているのかは不明です。ここに保存してもapp.ymlファイルには入力されません。したがって、Postgresデータベースのどこかに保存されていると推測していますか?おそらく暗号化されているのでしょうか?

AWSアクセスキーとシークレットキーをapp.ymlに保存しないことで、将来問題が発生しないことを願っていますか?キーがそこにある必要がある他のプロセスはありますか?

「いいね!」 1

S3バケットの前にCDNキャッシュとしてAWS CloudFrontを有効にしました。これは、ここで説明されているようにセットアップされたS3バケットの前にあります。ただし、CloudFrontの設定中に、S3アクセスポリシーのいくつかの変更が必要になりました。特に、このガイドで推奨されているパブリックアクセスではなく、S3バケットへのアクセスをCloudFrontのみに制限するようなポリシーがあるようです。DiscourseでS3バケットを使用し、CloudFront CDNを使用している場合、正しいS3バケットのアクセス許可ポリシーについて誰かレビューしていただけますか?現在、CDNは機能していますが、S3バケットから余分なアクセス許可を削除する必要があるかどうかはわかりません。

「いいね!」 1

このトピックの最初の投稿に示されているバケットポリシーを新しいAWSバケットで使用しましたが、本日、JSON構文エラーが発生します。

OP/トピックの最初の投稿で提供されたポリシーのエラー: 「Principal がありません」、「サポートされていないポリシー」というエラーが 4 行目、23 行目、26 行目、29 行目で発生し、AWS のドキュメントを読んでそれらのエラーを何とか修正しようとすると、コードの最後に「JSON 構文エラー」が表示されました。
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
               "s3:List*",
               "s3:Get*",
               "s3:AbortMultipartUpload",
               "s3:DeleteObject",
               "s3:PutObject",
               "s3:PutObjectAcl",
               "s3:PutObjectVersionAcl",
               "s3:PutLifecycleConfiguration",
               "s3:CreateBucket",
               "s3:PutBucketCORS"
      ],
      "Resource": [
        "arn:aws:s3:::your-uploads-bucket",
        "arn:aws:s3:::your-uploads-bucket/*"
      ]
    },
    {
       "Effect": "Allow",
       "Action": [
           "s3:ListAllMyBuckets",
           "s3:ListBucket"
       ],
       "Resource": "*"
    }
  ]
}
コンソールでは構文エラーが表示されませんが、「無効な Principal」という 1 つのエラーが表示され、それを克服できませんでした。 #### 独自のバケット名を使用しました
{
  "Id": "Policy1725098748430",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1725098741436",
      "Action": [
        "s3:AbortMultipartUpload",
        "s3:CreateBucket",
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:List*",
        "s3:ListBucket",
        "s3:ListBucketMultipartUploads",
        "s3:PutBucketCORS",
        "s3:PutLifecycleConfiguration",
        "s3:PutObject",
        "s3:PutObjectAcl",
        "s3:PutObjectVersionAcl"
      ],
      "Effect": "Allow",
      "Resource": [
	"arn:aws:s3:::t9478010203",
	"arn:aws:s3:::t9478010203/backups/",
	"arn:aws:s3:::t9478010203/uploads/"
	],
      "Principal": {
        "AWS": [
          "123456789012"
        ]
      }
    }
  ]
}
「いいね!」 1

このトピックは本当に更新が必要ですね。S3/IAMでポリシーをいじっていたら、私もエラーに気づきました。幸い、問題なく動作しているようです!

スキルと知識をお持ちの方で、ポリシーが どうあるべきか を見て更新していただけないでしょうか。@pfaffmanさん

「いいね!」 5