Configurar uploads de arquivos e imagens para o 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 curtidas

Esta narrativa precisa ser atualizada. Ou não consigo. Após a instalação, as imagens são carregadas no bucket, mas não consigo acessá-las. Não importa o que eu fiz, não funcionou. Alguém tentou isso recentemente e conseguiu fazer funcionar?

1 curtida

O que acontece quando você tenta acessá-los?

Você tem um CDN?

Que serviço você usou?

As imagens foram carregadas e as permissões do bucket não permitem que você as veja?

Se o PM precisar ser atualizado, você precisará fornecer mais informações sobre o que fez e o que está acontecendo.

O site é público? Onde

1 curtida

Eu sigo a explicação exatamente. fazendo upload de imagens. No entanto, as imagens não podem ser acessadas. URL de exemplo: https://awssorucevap24.s3.eu-central-1.amazonaws.com/original/2X/6/62c89621b0764112e0029bc91c957dd49d75d819.jpeg

A seção de permissões se parece com isto:

Eu não abro o ACL ao instalar o Bucket, não há informações sobre isso, e eu não consigo acessá-lo mesmo quando mudo essa configuração em minhas tentativas anteriores.

Nota adicional: Não há a configuração de “Acesso programático” ao criar um usuário, isso existia há muito tempo, não está mais lá. Pode estar relacionado a isso? Ou você pode explicar como podemos fazer isso no novo sistema ao criar um usuário?

Eu também preparei o domínio cloudfront e cdn. Meu único problema é que não tenho acesso aos arquivos. Espero que possamos encontrar o que eu perdi :slight_smile:

1 curtida

rake uploads:migrate_to_s3
FileStore::ToS3MigrationError: Por favor, forneça as seguintes variáveis de ambiente: (FileStore::ToS3MigrationError)

  • DISCOURSE_S3_BUCKET
  • DISCOURSE_S3_REGION
    e ou
  • DISCOURSE_S3_ACCESS_KEY_ID
  • DISCOURSE_S3_SECRET_ACCESS_KEY
    ou
  • DISCOURSE_S3_USE_IAM_PROFILE

Pelo que vejo, não é nem Chave de Acesso OU Perfil IAM. No meu caso, estou usando Perfil IAM. Alguma recomendação aqui?

1 curtida

Acho que você precisa definir esses dados em um arquivo yml. Primeiro, certifique-se de que o processo de upload funcione e, em seguida, migre.

Como você o configurou, aliás? Tentei fazer isso, os arquivos estavam sendo enviados, mas não abriam no navegador. Estava dando um erro de acesso negado.

1 curtida

O upload e o acesso de leitura pública estão funcionando corretamente.

Estou usando a função e a política do IAM anexadas ao EC2. Me avise se você quiser mais detalhes sobre isso.

Ah, acredito que sei o que está acontecendo no seu caso. Verifique estas configurações:

Bloquear acesso público (configurações do bucket)

Propriedade do objeto

Lista de controle de acesso (ACL) – Provavelmente aqui está o truque para você

3 curtidas

Não vi nada na explicação sobre ativar a configuração de ACL, então tentei fazê-lo sem tocá-la todas as vezes.

Não é mais importante para mim, mudarei para o cloudflare R2. Esta explicação será muito útil para outra pessoa no futuro. Obrigado.

2 curtidas

Não tenho certeza se esta é a melhor configuração, mas é como a encontrei até agora. Quero pedir à @equipe para dar uma olhada e nos orientar.

Esta é a melhor maneira de mantê-la segura e funcionando corretamente?

2 curtidas

Você poderia compartilhar mais detalhes sobre isso?

1 curtida

Após algum esforço, mudei para R2 (não vamos esquecer os amigos que ajudaram, respeito). Os arquivos de assets e uploads são publicados no Cloudflare. O único problema é que não consegui fazer com que os arquivos theme-javascripts e stylesheets fossem enviados automaticamente para o R2. Pesquisarei este problema quando tiver tempo.

1 curtida

Foi uma decisão técnica, de custo ou ambas?

1 curtida

O primeiro é técnico, não consegui instalar a Amazon, mas já estava usando o Cloudflare, então pensei por que não instalar o CDN de lá. E então vi que foi uma boa decisão porque o Cloudflare lançou este serviço para nós desenvolvedores contra os sistemas de nuvem S3 excessivamente caros. Não é muito bom?

1 curtida

É bom. Vou dar uma olhada mais a fundo.

E quanto à integração no discourse? Como foi essa experiência?

Você também está usando o Cloudflare WAF?

1 curtida

Não, ainda não usei, na verdade não tenho certeza se vou precisar. Mas uso o Cloudflare “ARGO”.

2 curtidas

Tenho um bucket S3 para uploads de imagens com ACL habilitado e uma função IAM devidamente configurada e atribuída à instância EC2 que executa minha instância autônoma. No entanto, as URLs de imagem S3 em minhas postagens de teste não podem ser visualizadas. Gostaria de hospedar imagens S3 em um bucket que só pode ser visualizado por usuários do Discourse logados. Por que as referências de URL para imagens S3 não incluem uma URL pré-assinada para acesso adequado? Se eu acessar o arquivo via console S3 e solicitar uma URL pré-assinada via AWS por um tempo definido, como 10 minutos, a imagem será carregada como esperado, então sei que pode funcionar.

1 curtida

Temos certeza de que isso deve ser armazenado no arquivo app.yml?

Eu fiz assim;

# entrar no app
cd /var/discourse
./launcher enter app

# passar as variáveis de ambiente com o comando em tempo de execução
DISCOURSE_S3_BUCKET=meu-bucket DISCOURSE_S3_REGION=us-east-1 DISCOURSE_S3_ACCESS_KEY_ID=abcdefg DISCOURSE_S3_SECRET_ACCESS_KEY=zxywqrst rake uploads:migrate_to_s3

Eu fiz isso, pois não queria que minha chave de acesso ficasse no arquivo YAML, pois faço backup dela em vários lugares. Passar a chave secreta da AWS pelo ambiente é ~geralmente~ um pouco mais “seguro”. Eu acho, certo? Não tenho certeza de quanto tempo o histórico de scrollback dentro do contêiner do aplicativo persiste, suponho que seja limpo após a reinicialização do contêiner.

Eu queria, em vez disso, configurar o acesso S3 da maneira “normal”, armazenando a Chave de Acesso e a Chave Secreta da AWS no arquivo ~/.aws/credentials do servidor, no entanto, não tenho certeza de como isso funcionaria com o aplicativo sendo executado dentro do contêiner.

Além disso, conforme o guia aqui, você é instruído a simplesmente copiar e colar as chaves de Acesso e Secreta na interface web de Configurações de Administrador do Discourse e salvá-las lá; não está claro para mim onde essas chaves estão sendo armazenadas no back-end, já que salvá-las aqui não preenche o arquivo app.yml com elas. Então, suponho que estejam no banco de dados Postgres em algum lugar? Espero que criptografadas, talvez?

Espero que, ao não armazenar as chaves de Acesso e Secreta da AWS no app.yml, eu não tenha problemas no futuro? Existe algum outro processo que exija que as chaves fiquem lá?

1 curtida

Fui em frente e ativei o AWS Cloudfront para um cache de CDN na frente do meu bucket S3, que foi configurado conforme descrito aqui. No entanto, a configuração do Cloudfront exigiu algumas modificações nas políticas de acesso S3. Em particular, parecem existir algumas políticas que restringiriam o acesso ao bucket S3 apenas ao Cloudfront, em vez do acesso público que este guia sugere. Alguém é capaz de revisar quais deveriam ser as políticas de permissões corretas do bucket S3 se você estiver usando o Cloudfront CDN com seu bucket S3 no Discourse? Atualmente, meu CDN está funcionando, mas não tenho certeza se preciso remover quaisquer permissões de acesso extranás do bucket S3.

1 curtida

Usei esta política de bucket mostrada na primeira postagem deste tópico, em um novo bucket AWS. Mas neste dia, está dando erro de sintaxe JSON.

Erro ao fornecer política dada na OP/1ª postagem do tópico: Apresenta erros de "Principal ausente", "Política não suportada" nas Linhas 4, 23, 26, 29 e quando consigo corrigir esses erros de alguma forma lendo a documentação da AWS, então surge "Erro de sintaxe JSON" no final do código.
{
  "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": "*"
    }
  ]
}
A que tentei criar, que não mostra nenhum erro de sintaxe no console, exceto um erro de "Principal inválido", que não consegui superar #### Usei meus próprios nomes de bucket
{
  "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 curtida

Este tópico realmente precisa de uma atualização - eu estava mexendo na política no S3/IAM e notei os erros também. Felizmente, parece funcionar bem!

Gostaria de saber se alguém com as habilidades e o conhecimento necessários se importaria de dar uma olhada e atualizar como a política deveria ser. @pfaffman?

5 curtidas