Incapaz de configurar o bucket S3

Olá,

Estou tentando configurar uploads para o S3 e parece que os uploads estão funcionando corretamente, mas as requisições GET estão falhando por um motivo estranho. Parece que o Discourse está adicionando um “.cn” ao URI do objeto carregado.

Após fazer o upload da imagem no meu bucket S3, a URL pública é:

https://hobig...bucket-eu.s3.eu-central-1.amazonaws.com/original/1X/5e894113...48918.jpeg

mas quando inspeciono o navegador, meu fórum Discourse está tentando carregar (note o .cn):

https://hobig...bucket-eu.s3.eu-central-1.amazonaws.com.cn/original/1X/5e894113...48918.jpeg

Alguém sabe por que isso está acontecendo?

Aqui estão minhas configurações de administrador:

Você deve seguir as instruções em Configurar um provedor de armazenamento de objetos compatível com S3 para uploads e/ou Set up file and image uploads to S3 e colocar essas configurações em seu arquivo yml em vez de no banco de dados/UX.
Você não precisa configurar um endpoint para a AWS. Você quer configurar uma CDN.

1 curtida

Olá @pfaffman,

Parece que você pode ter colado acidentalmente o mesmo guia duas vezes.

Quando você menciona “configurações no seu arquivo yml”, você poderia esclarecer a qual arquivo YAML está se referindo? Você talvez esteja falando sobre o arquivo app.yml localizado na pasta /var/discourse/containers?

Além disso, se eu configurar minha integração S3/CloudFront diretamente através do arquivo YAML, essas configurações substituiriam o que está configurado na seção de administração do Discourse?

Obrigado!

Desculpe. Um desses deveria ter sido Set up file and image uploads to S3.

Veja os tópicos vinculados que descrevem como configurar o S3, mas sim, o app.yml é o que você deseja alterar (já que você não mencionou web_only.yml)

Sim. Inseri-los no arquivo YML os oculta da UX.

Olá @pfaffman,

Eu tenho meu bucket S3, configuração do CloudFront e a origem do CloudFront configurada para o meu bucket S3. Aqui está a minha configuração atual do app.yml:

ENV:
  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: eu-central-1
  DISCOURSE_S3_ACCESS_KEY_ID: AKIAWPLPUxxxxxx
  DISCOURSE_S3_SECRET_ACCESS_KEY: PaXQu7pKxxxx
  DISCOURSE_S3_CDN_URL: https://dsuxxxhrz2qn.cloudfront.net
  DISCOURSE_S3_BUCKET: hobigxxxxbucket-eu

Após reconstruir o aplicativo com ./launcher rebuild app, quando visito o site, ele apenas mostra o loader sem carregar nada. Ao inspecionar a aba de rede, descobri que ele não consegue buscar os ativos estáticos pré-compilados (principalmente .js), o que presumo ser porque eles não estão no meu bucket S3. Você pode verificar aqui: forum.hobiguru.com.

Também tentei executar a tarefa rake de migração, mas sem sucesso:

root@ubuntu-s-1vcpu-1gb-fra1-01-app:/var/www/discourse# rake uploads:migrate_to_s3 --trace


** Invoke uploads:migrate_to_s3 (first_time)
** Invoke environment (first_time)
** Execute environment


** Execute uploads:migrate_to_s3
Por favor, note que migrar para S3 atualmente não pode ser revertido!
[CTRL+c] para cancelar, [ENTER] para continuar
Migrando uploads para S3 para 'default'...
Alguns uploads não foram migrados para o novo esquema. Executando a migração, isso pode levar algum tempo...
rake aborted!
FileStore::ToS3MigrationError: Alguns uploads não puderam ser migrados para o novo esquema. Você precisa corrigir isso manualmente. (FileStore::ToS3MigrationError)
/var/www/discourse/lib/file_store/to_s3_migration.rb:156:in `migrate_to_s3'
/var/www/discourse/lib/file_store/to_s3_migration.rb:59:in `migrate'
/var/www/discourse/lib/tasks/uploads.rake:126:in `migrate_to_s3'
/var/www/discourse/lib/tasks/uploads.rake:106:in `block in migrate_to_s3_all_sites'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management/null_instance.rb:36:in `each_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management.rb:21:in `each_connection'
/var/www/discourse/lib/tasks/uploads.rake:104:in `migrate_to_s3_all_sites'
/var/www/discourse/lib/tasks/uploads.rake:100:in `block in <main>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `block in execute'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `execute'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `synchronize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `invoke_with_call_chain'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:188:in `invoke'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:188:in `invoke_task'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `block (2 levels) in top_level'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `block in top_level'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:147:in `run_with_threads'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:132:in `top_level'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:83:in `block in run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:214:in `standard_exception_handling'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:80:in `run'
bin/rake:13:in `<top (required)>'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli/exec.rb:58:in `load'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli/exec.rb:58:in `kernel_load'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli/exec.rb:23:in `run'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli.rb:455:in `exec'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor/command.rb:28:in `run'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor.rb:527:in `dispatch'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli.rb:35:in `dispatch'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor/base.rb:584:in `start'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli.rb:29:in `start'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/exe/bundle:28:in `block in <top (required)>'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/exe/bundle:20:in `<top (required)>'
/usr/local/bin/bundle:25:in `load'

Minha intenção original era usar o S3 apenas para armazenar uploads de usuários, e adicionei o CDN apenas para lidar com isso. No entanto, agora estou enfrentando um novo problema: os ativos estáticos do meu aplicativo também estão sendo servidos através do CDN, o que eu não pretendia. :confused:

Existe alguma maneira de fazer upload de todos os ativos estáticos no lançamento do aplicativo para o bucket S3 e, em seguida, servi-los através do CDN, ou talvez uma maneira de servir apenas os uploads de usuários através do CDN, ou existe uma solução melhor para isso?

Talvez eu ainda esteja perdendo algo óbvio? sei lá
Obrigado pela sua ajuda!

Suspeito que seja porque você não seguiu as instruções.

Sim. Entendo. Isso é possível, mas você não conseguiu fazer funcionar. Esta é a maneira recomendada; é bem documentada e centenas de pessoas fazem dessa forma.

1 curtida

Desculpe, você está certo, eu pulei essa parte exatamente. Adicionei o seguinte ao meu app.yml e agora ele está carregando o fórum corretamente:

after_assets_precompile:
    - exec:
        cd: $home
        cmd:
          - sudo -E -u discourse bundle exec rake s3:upload_assets
          - sudo -E -u discourse bundle exec rake s3:expire_missing_assets

No entanto, os uploads de usuários ainda não estão funcionando corretamente. Após o upload no bucket S3 (corretamente), a imagem é servida como:

//my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg

que, claro, não é um caminho S3 ou CDN válido.

No guia a que você se refere, há esta seção que parece relevante:

DISCOURSE_CDN_URL é uma CDN que aponta para o seu hostname Discourse e armazena em cache as requisições. Ela será usada principalmente para assets que podem ser puxados: CSS e outros assets de tema.

DISCOURSE_S3_CDN_URL é uma CDN que aponta para o seu bucket de armazenamento de objetos e armazena em cache as requisições. Ela será usada principalmente para assets que podem ser enviados: JS, imagens e uploads de usuários.

Recomendamos que sejam diferentes e que os administradores configurem ambos.

No entanto, não tenho certeza do que definir como DISCOURSE_CDN_URL? Devo defini-lo com o mesmo valor de DISCOURSE_S3_CDN_URL: https://dsxxxxx2qn.cloudfront.net ou ter uma instância de CDN separada criada?

Por outro lado, talvez seja algo totalmente diferente :confused:

Muito obrigado por toda a ajuda!

Você precisa configurar a CDN e usá-la com o seu domínio desejado no lado da AWS. Além disso, no DNS.

Mas por quê? Praticamente ninguém nunca vê essa URL.

1 curtida

Olá Jake, não tenho certeza se entendi corretamente o que você quis dizer. Você poderia elaborar um pouco mais?

Você talvez quis dizer que, em vez de configurar o bucket S3 como a origem da CDN, eu deveria configurar meu domínio forum.hobiguru.com como a origem? Se for o caso, não acho que isso mudaria nada, já que é o fórum discourse que gera esses URLs que não levam a lugar nenhum, por exemplo, //my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg

Eu adicionei DISCOURSE_CDN_URL: https://dsuxxxhrz2qn.cloudfront.net também e agora estou esperando o aplicativo ser reconstruído :crossed_fingers:

ATUALIZAÇÃO: não, isso também não funcionou :confused:

Eu realmente aprecio a ajuda.
Obrigado

Você simplesmente não pode nomear um subdomínio apenas em app.yml. Ninguém pode usá-lo sem as informações corretas de DNS. E como o envio de seus arquivos acontece a partir da AWS, você também precisa configurar esse lado, se quiser usar CDN.

Mas, novamente. Os usuários veem a URL do Discourse, se quiserem vê-la. Raramente alguém que não seja um administrador está fazendo algo que deseja. E os usuários praticamente nunca veem a URL de mídias ou outros arquivos estáticos.

Portanto, meu ponto de vista é que você está perdendo tempo à toa se não quiser usar CDN. E isso pode ser inteligente se você tiver um público global, e alguns deles estiverem em conexões de nível estadual ruins.

Eu moro na Finlândia. Não obtenho nenhum benefício real se um site do outro lado do mundo, na Austrália, usa CDN (de um servidor localizado a 1000 km de mim). O gargalo real vem de como esse site é construído, como se muitas chamadas PHP desnecessárias fossem usadas sem recursos suficientes.

Mas, basicamente, você não pode usar uma URL cdn.example.tld sem colocar cdn pelo menos no DNS.

Olá @Jagster

Na verdade, eu não quero usar um CDN — só quero que todos os uploads de usuários sejam armazenados no S3 e servidos diretamente de lá, embora o CloudFront seja realmente uma solução melhor do que o S3 diretamente.

Meu problema surgiu quando tentei configurar o S3 (especificamente para servir assets, não uploads), e o @pfaffman sugeriu que eu seguisse o guia Configurar um provedor de armazenamento de objetos compatível com S3 para uploads e configurasse um CDN.

Em relação ao seu comentário:

“Você simplesmente não pode nomear um subdomínio apenas em app.yml. Ninguém pode usá-lo sem informações de DNS adequadas. E como o carregamento dos seus arquivos acontece a partir da AWS, você também tem que configurar esse lado, se quiser usar CDN.”

Desculpe, mas não entendi bem o que você quis dizer com este parágrafo. Você poderia elaborar um pouco mais ou esclarecer? Você está dizendo que preciso configurar registros de DNS para o meu bucket S3 ou que há algo específico que preciso ajustar no lado da AWS?

Obrigado antecipadamente pela sua ajuda!

Olá novamente a todos,

Queria dar seguimento ao meu post anterior e partilhar que fiz alguns progressos.

O que está a funcionar agora

  • Os uploads de utilizadores estão a ser servidos corretamente do meu bucket S3 através do CDN (CloudFront), o que é ótimo!

No entanto, ainda estou a enfrentar um problema com os assets pré-compilados

Os assets pré-compilados ainda não estão a ser servidos corretamente do CDN.

Quando defino o DISCOURSE_CDN_URL para o URL do CloudFront (ou seja, https://dsuqioxhrz2qn.cloudfront.net), os URLs dos assets pré-compilados tornam-se:

O problema é que estes caminhos não existem no meu bucket S3. Os assets pré-compilados são carregados sob a pasta /assets/* no S3 (por exemplo, /assets/locales, /assets/plugins, /assets/scripts), mas não existe uma pasta /stylesheets/ e, claro, o carregamento desses URLs resulta em 403 forbidden.

Se, no entanto, altero o DISCOURSE_CDN_URL: https://forum.hobiguru.com, então o meu fórum está a funcionar corretamente, mas os assets estão agora a ser servidos do servidor (por exemplo, https://forum.hobiguru.com/) e não do CDN (por exemplo, https://forum.hobiguru.com/stylesheets/admin_308d905aa5c03567866fec50e9a28d8721ab0463.css?__ws=forum.hobiguru.com)

A minha configuração atual (para contexto) é:

app.yaml

DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: eu-central-1
DISCOURSE_S3_ACCESS_KEY_ID: AKIA......LQMB
DISCOURSE_S3_SECRET_ACCESS_KEY: PaXQu7pKN.....fJNY
DISCOURSE_S3_CDN_URL: https://dsuqioxhrz2qn.cloudfront.net  # Ensure CDN URL points to CloudFront
DISCOURSE_CDN_URL: https://forum.hobigur.com # NOTICE THIS!
DISCOURSE_S3_BUCKET: hobiguru-s3-bucket-eu

e os hooks de pré-compilação:

hooks:
  after_assets_precompile:
    - exec:
        cd: $home
        cmd:
          - sudo -E -u discourse bundle exec rake s3:upload_assets
          - sudo -E -u discourse bundle exec rake s3:expire_missing_assets

Parece que, após a pré-compilação dos assets, eles são carregados para o S3 numa determinada estrutura, mas depois, quando carregados através do CDN, o caminho para os objetos está um pouco incorreto.