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.

:warning: Since April 2023, new S3 buckets have ACLs disabled by default (“Bucket owner enforced”). You have two options:

Option A — ACLs disabled (simpler): Keep the AWS defaults (ACLs disabled, all public access blocked). Later, set s3_use_acls to false in Discourse. Uploads will be served via presigned URLs or a CDN. You can also omit s3:PutObjectAcl and s3:PutObjectVersionAcl from the IAM policy below.

Option B — ACLs enabled (legacy, Discourse default): Change Object Ownership to “ACLs enabled” (choose “Bucket owner preferred”). Then 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.

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: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:

:information_source: If you chose Option A above (ACLs disabled), you can remove s3:PutObjectAcl and s3:PutObjectVersionAcl from the policy since they are only needed when s3_use_acls is enabled.

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»:

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
  • If you chose Option A (ACLs disabled) for your bucket, set s3_use_acls to false

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.

Last edited by @JammyDodger 2024-05-25T10:58:50Z

Check documentPerform check on document:
106개의 좋아요
Configure an S3 compatible object storage provider for uploads
Configure automatic backups for Discourse
After setting up S3 - Access denied
S3 region vs. Discourse region
IAM and bucket policy for S3 access
Optimize images before uploading?
Setting up s3: what happens to previous uploads?
Images are disappearing off of s3!
Enable a CDN for your Discourse
Setting up SSL with my domain name and Discourse instance
Downloading remote images disabled due to disk space
Extend S3 configuration for other S3 API compatible services
Upload img/content via image/content host
Migrate_to_s3 fails because of logo images
Access Denied error message when trying to upload images
Please explain how hosting photos within the forum works. Does that get crazy expensive?
Uploading Images stalls and does not translate to img src tag
File Reference and Deletion, will it really be deleted?
Backups failing, and admin page inaccessible
Would it be worth resizing uploaded images (to save space)?
Using s3: "backup with uploads" settings
S3: Failed to optimize image: no images defined
S3 Backup ... suspect access issue
Backups have started failing due to server time being wrong
Awareness for path dependencies when setting up a discourse forum
Hosting the pictures on external storage
Best Practices for Backups
Broken Images and Their S3 URLs
Can't upload PDF to S3
Image upload error: The bucket does not allow ACL's
S3 Bucket objects restricted access policy as per Discourses groups
Understanding Uploads, Images, and Attachments
Error in rebuilding using minio as object store
S3 bucket policy current example
The s3 cdn url setting makes no effect
Problems with Patreon Login, Force HTTPS, and S3 CDN (three) Issues
Cron task to sync local backups to DigitalOcean Spaces
Help restoring - system hung at midnight
Upload objects to private S3 is not working
Placeholder Forms
After setting up S3 - Access denied
Upload objects to private S3 is not working
Can I increase the 1024000 kb limit on attachment?
More descriptive warning when recategorising a topic into a category with moderator approval
The bucket does not allow ACLs
Incorrect S3 warning in admin menu
Install Discourse on Amazon Web Services (AWS)
Questions about migration of files such as images and videos
Configure automatic backups for Discourse
Can't restore backup with images on S3
My images are not working
Image uploads path in posts will not change after rebake and remap
Automatic backup not working
S3 programmatic access checkbox
Rebuilds taking a long time with a large number of uploads (chown performance)
Automatic backup not working
How to make Discourse faster for image-heavy communities?
Broken Images and Their S3 URLs
S3 and Cloudfront - Setup Not Working
Configure an S3 compatible object storage provider for uploads
S3 and Cloudfront - Setup Not Working
Problem with Backblaze for backup- Failed to list backups from S3: Signature validation failed
Issues with changing File/Image upload location to S3 Server from local storage
S3 connect with discourse error
:cn: How to back up Discourse to S3 | Discourse 如何备份到 S3
Policy and permission issues with s3 buckets?
Configure an S3 compatible object storage provider for uploads
Getting CORS error while uploading images
MKJ's Opinionated Discourse Deployment Configuration
CloudFront - “S3 bucket access” setting
Unable to setup S3 bucket
Unable to setup S3 bucket
S3 uploads working but generating warnings
Separate S3 access keys for backups and uploads?
How to post pictures via API?
How might we better structure #howto?
Configure an S3 compatible object storage provider for uploads
Where to Upload a File
Configure automatic backups for Discourse
S3 backups for multisite show up in root directory of bucket
Digital file repository in forum
An AWS S3 Integration with Discourse Tutorial would be nice
S3 and Cloudfront - Setup Not Working
S3 and Cloudfront - Setup Not Working
Configure an S3 compatible object storage provider for uploads
Policy and permission issues with s3 buckets?
My forum stop working... could not do Rebuild App
Policy and permission issues with s3 buckets?
Policy and permission issues with s3 buckets?
S3 migrating certs- how does this affect Discourse sites?
Backups failing, and admin page inaccessible
Imgur upload built into the post buttons
Free Hosting Plan and AWS
Capacity planning / Resource requirements
S3 Backup ... suspect access issue
How to run rake tasks?
How to develop discourse in a team?
AWS S3 Object Ownership

이 설명서를 업데이트해야 합니다. 아니면 제가 할 수 없습니다. 설치 후 이미지가 버킷에 업로드되지만, 제가 접근할 수 없습니다. 무엇을 해도 작동하지 않았습니다. 최근에 이걸 시도해서 성공하신 분 계신가요?

1개의 좋아요

그것들에 접근을 시도하면 어떤 일이 발생하나요?

CDN을 사용하고 있나요?

어떤 서비스를 사용했나요?

이미지가 업로드되었지만 버킷 권한 때문에 볼 수 없는 건가요?

PM(개인 메시지)이 업데이트되어야 한다면, 무엇을 했고 어떤 일이 일어나고 있는지 더 많은 정보를 제공해야 합니다.

사이트가 공개되어 있나요? 어디에 있나요?

1개의 좋아요

설명하신 내용을 그대로 따랐습니다. 사진을 업로드했습니다. 하지만 이미지에 접근할 수 없습니다. 예시 URL: https://awssorucevap24.s3.eu-central-1.amazonaws.com/original/2X/6/62c89621b0764112e0029bc91c957dd49d75d819.jpeg

권한 섹션은 다음과 같습니다:

버킷 설치 시 ACL을 열지 않았으며, 이에 대한 정보가 없습니다. 이전 시도에서 이 설정을 변경해도 여전히 접근할 수 없습니다.

추가 참고 사항: 사용자를 생성할 때 “프로그램matic 접근” 설정이 없습니다. 과거에는 있었지만 이제는 없습니다. 이것이 관련이 있을까요? 아니면 새 시스템에서 사용자를 생성할 때 어떻게 해야 하는지 설명해 주실 수 있을까요?

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 파일은 Cloudflare에 게시되어 있습니다. 유일한 문제는 테마의 자바스크립트와 스타일시트 파일을 R2로 자동으로 업로드할 수 없다는 점입니다. 시간이 날 때 이 문제를 조사해 보겠습니다.

1개의 좋아요

이것은 기술적 결정이었나요, 비용 관련 결정이었나요, 아니면 둘 다인가요?

1개의 좋아요

첫 번째는 기술적인 문제인데, Amazon을 설치하지 못했지만 이미 Cloudflare을 사용 중이어서 왜 거기서 CDN을 설치하지 않나 생각했어요. 그리고 나서 Cloudflare이 지나치게 비싼 S3 클라우드 시스템에 대응하여 개발자들을 위해 이 서비스를 출시했다는 걸 보고 좋은 결정이었다고 느꼈어요. 정말 멋지지 않나요?

1개의 좋아요

좋네요. 더 자세히 살펴볼게요.

디스코스에 통합하는 건 어땠나요? 그 경험은 어땠나요?

클라우드플레어 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 액세스 키와 시크릿 키를 서버의 ~/.aws/credentials 파일에 저장하여 S3 액세스를 “일반적인” 방식으로 설정하고 싶었습니다. 하지만 컨테이너 내부에서 실행되는 앱과 이것이 어떻게 작동하는지 정확히 모르겠습니다.

또한, 여기의 가이드에 따르면 액세스 키와 시크릿 키를 Discourse 관리자 설정 웹 UI에 복사/붙여넣기하고 저장하라고 안내합니다. 하지만 여기서 저장할 때 app.yml 파일에 해당 키가 입력되지 않기 때문에, 백엔드에서 이 키들이 어디에 저장되는지 명확하지 않습니다. Postgres 데이터베이스 어딘가에 저장되는 건가요? 암호화되어 있기를 바랍니다.

app.yml에 AWS 액세스 키와 시크릿 키를 저장하지 않으면 향후 문제가 발생하지 않을 것이라 기대합니다. app.yml에 키가 있어야 하는 다른 프로세스가 있을까요?

1개의 좋아요

여기에서 설명한 대로 설정된 S3 버킷 앞에 CDN 캐시로 AWS CloudFront를 활성화했습니다. 하지만 CloudFront를 구성하는 과정에서 S3 액세스 정책의 일부 수정이 필요했습니다. 특히, 이 가이드에서 제안하는 공개 액세스 대신 S3 버킷 액세스를 CloudFront로만 제한하는 정책들이 있는 것 같습니다. Discourse에서 S3 버킷과 함께 CloudFront CDN을 사용하는 경우, 올바른 S3 버킷 권한 정책은 무엇인지 검토해 주실 수 있는 분이 있을까요? 현재 제 CDN은 정상적으로 작동하고 있지만, S3 버킷에서 불필요한 액세스 권한을 제거해야 하는지 확신이 서지 않습니다.

1개의 좋아요

이 토픽의 첫 번째 게시물에 나와 있는 이 버킷 정책을 새 AWS 버킷에 적용했습니다. 하지만 현재 JSON 구문 오류가 발생하고 있습니다.

토픽의 OP/첫 번째 게시물에 제시된 정책 적용 시 발생하는 오류: 4, 23, 26, 29번째 줄에서 "Missing Principal", "Unsupported Policy" 오류가 발생하며, AWS 문서를 참고하여 해당 오류를 어떻게든 수정하면 코드 말미에서 "Json Syntax Error"가 발생합니다.
{
  "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": "*"
    }
  ]
}
직접 생성해 본 정책으로, 콘솔에는 "Invalid 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개의 좋아요