设置文件和图片上传到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

权限部分看起来像这样:

安装 Bucket 时,我没有打开 ACL,也没有相关信息,并且在我之前的尝试中更改此设置后也无法访问。

补充说明:创建用户时没有“编程访问”设置,以前有,现在没有了。这可能与此有关吗?或者您能否解释一下在新系统中创建用户时如何进行此操作?

我还准备了 CloudFront 和 CDN 域名。我唯一的问题是我无法访问文件。希望我们能找到我遗漏的地方 :slight_smile:

1 个赞

rake uploads:migrate_to_s3
FileStore::ToS3MigrationError: 请提供以下环境变量:(FileStore::ToS3MigrationError)

  • DISCOURSE_S3_BUCKET
  • DISCOURSE_S3_REGION
    以及以下之一:
  • DISCOURSE_S3_ACCESS_KEY_ID
  • DISCOURSE_S3_SECRET_ACCESS_KEY
  • DISCOURSE_S3_USE_IAM_PROFILE

据我所见,它既不是 Access key 也不是 IAM Profile。在我的例子中,我使用的是 IAM Profile。有什么建议吗?

1 个赞

我认为您需要在 yml 文件中定义这些数据。首先,请确保上传过程正常工作,然后再进行迁移。

对了,您是如何配置的?我尝试过这样做,文件可以上传,但在浏览器中无法打开。它显示了“访问被拒绝”错误。

1 个赞

上传和公共读取访问运行正常。

我正在使用附加到 EC2 的 IAM 角色和策略。如果您想了解更多详细信息,请告诉我。

啊,我相信我知道您的情况是怎么回事了。请检查这些配置:

阻止公共访问(存储桶设置)

对象所有权

访问控制列表 (ACL) – 也许这里的设置是您需要的

3 个赞

我没有在说明中看到任何关于启用 ACL 设置的内容,所以我每次都尝试在不触碰它的情况下进行操作。

对我来说这已经不重要了,我将切换到 Cloudflare R2。这个说明在未来对其他人会很有用。谢谢。

2 个赞

我不确定这是最好的配置,但到目前为止,我发现它是这样的。我想请 @team 看看并指导我们。

这是保持安全和正常运行的最佳方式吗?

2 个赞

您能分享更多关于这方面的信息吗?

1 个赞

经过一番努力,我切换到了 R2(别忘了帮助过我的朋友们,致敬)。assets 和 uploads 文件已发布到 clouflare。唯一的问题是,我无法自动将 theme-javascripts 和 stylesheets 文件上传到 R2。有时间我会研究这个问题。

1 个赞

这是技术决策还是成本决策,或是两者兼有?

1 个赞

第一个是技术性的,我无法安装 Amazon,但我已经在使用了 Cloudflare,所以我想为什么不从那里安装 CDN 呢。然后我发现这是一个明智的决定,因为 Cloudflare 为我们开发者推出了这项服务,以对抗那些价格过高的 S3 云系统。这不是很棒吗?

1 个赞

这很好。我会更深入地研究一下。

那么集成到 discourse 中呢?那次经历怎么样?

您也在使用 Cloudflare WAF 吗?

1 个赞

还没有,其实我也不确定是否需要。但我使用了 Cloudflare 的“ARGO”。

2 个赞

我有一个用于图像上传的 S3 存储桶,启用了 ACL,并且有一个已正确配置并分配给我运行独立实例的 EC2 实例的 IAM 角色。但是,我的测试帖子中的 S3 图像 URL 无法查看。我想将 S3 图像托管在一个只能由已登录的 Discourse 用户查看的存储桶中。为什么 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 访问密钥和密钥存储在服务器的 ~/.aws/credentials 文件中来以“正常”方式配置 S3 访问,但是,我不确定这与在容器内运行的应用如何协同工作。

另外,根据这里的指南,您被指示将访问密钥和密钥直接复制粘贴到 Discourse 管理设置的 Web UI 中并在此处保存;我不清楚这些密钥在后端存储在哪里,因为在此处保存它们不会在 app.yml 文件中填充它们。所以我想它们存储在 Postgres 数据库的某个地方?希望是加密的,也许?

我希望通过不将 AWS 访问密钥和密钥存储在 app.yml 中,我将来不会遇到任何问题?是否有其他进程需要密钥驻留在那里?

1 个赞

我已经启用了 AWS Cloudfront 作为 S3 存储桶前面的 CDN 缓存,设置方法如此处所述。但是,配置 Cloudfront 时需要对 S3 访问策略进行一些修改。特别是,似乎有一些策略会将 S3 存储桶访问限制为仅限 Cloudfront,而不是本指南建议的公共访问。是否有人能够审查在使用 Discourse 的 S3 存储桶配置 Cloudfront CDN 时,正确的 S3 存储桶权限策略应该是什么?目前,我的 CDN 正在运行,但不确定是否需要删除 S3 存储桶的任何多余访问权限。

1 个赞

我在一个新的 Aws 存储桶上使用了此主题第一个帖子中显示的存储桶策略。但今天,它出现了 Json 语法错误。

OP/主题第一帖子中给出的策略错误: 在第 4、23、26、29 行出现“缺少 Principal”、“不支持的策略”错误,当我通过阅读 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”错误,我无法克服 #### 使用了我自己的存储桶名称
{
  "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 个赞