No se puede configurar el bucket de S3

Hola,

Estoy intentando configurar las cargas de S3 y parece que las cargas funcionan correctamente, pero las solicitudes GET fallan por una razón extraña. Parece que Discourse está añadiendo un “.cn” a la URI del objeto subido.

Después de subir la imagen a mi bucket de S3, la URL pública es:

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

pero cuando inspecciono el navegador, mi foro de Discourse está intentando cargar (nota el .cn):

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

¿Alguien sabe por qué está sucediendo esto?

Aquí están mis configuraciones de administrador:

Debes seguir las instrucciones de Configurar un proveedor de almacenamiento de objetos compatible con S3 para cargas y/o Set up file and image uploads to S3 y poner esos ajustes en tu archivo yml en lugar de en la base de datos/UX.
No necesitas configurar un endpoint para AWS. Sí quieres configurar una CDN.

1 me gusta

Hola @pfaffman,

Parece que podrías haber pegado accidentalmente la misma guía dos veces.

Cuando mencionas “configuración en tu archivo yml”, ¿podrías aclarar a qué archivo YAML te refieres? ¿Quizás estás hablando del archivo app.yml ubicado en la carpeta /var/discourse/containers?

Además, si configuro mi integración S3/CloudFront directamente a través del archivo YAML, ¿esas configuraciones anularían lo que está configurado en la sección de administración de Discourse?

¡Gracias!

Lo siento. Uno de ellos debería haber sido Set up file and image uploads to S3.

Consulta los temas enlazados que describen cómo configurar S3, pero sí, app.yml es lo que quieres cambiar (ya que no mencionaste web_only.yml).

Sí. Introducirlos en el archivo YML los oculta de la UX.

Hola @pfaffman,

Tengo mi bucket S3, configuración de CloudFront y el origen de CloudFront configurado en mi bucket S3. Aquí está mi configuración actual de 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

Después de reconstruir la aplicación con ./launcher rebuild app, cuando visito el sitio web, solo muestra el cargador sin cargar nada. Al inspeccionar la pestaña de red, descubrí que no puede obtener los activos estáticos precompilados (principalmente .js), lo que supongo que se debe a que no están en mi bucket S3. Puedes verificarlo aquí: forum.hobiguru.com.

También intenté ejecutar la tarea de migración rake, pero sin éxito:

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
Ten en cuenta que migrar a S3 actualmente no se puede revertir.
[CTRL+c] para cancelar, [ENTER] para continuar
Migrando cargas a S3 para 'default'...
Algunas cargas no se migraron al nuevo esquema. Ejecutando la migración, esto puede tardar un poco...
rake aborted!
FileStore::ToS3MigrationError: Algunas cargas no pudieron ser migradas al nuevo esquema. Necesitas arreglar esto 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'

Mi intención original era usar S3 solo para almacenar las cargas de usuarios, y agregué la CDN solo para manejar eso. Sin embargo, ahora me enfrento a un nuevo problema: los activos estáticos de mi aplicación también se están sirviendo a través de la CDN, lo cual no era mi intención. :confused:

¿Hay alguna forma de subir todos los activos estáticos al lanzar la aplicación al bucket S3 y luego servirlos a través de la CDN, o tal vez una forma de servir solo las cargas de los usuarios a través de la CDN, o hay una mejor solución para esto?

¿Quizás todavía me estoy perdiendo algo obvio? No sé.
¡Gracias por tu ayuda!

Sospecho que es porque no seguiste las instrucciones.

Sí. Entiendo. Eso es posible, pero no pudiste hacer que funcionara. Esta es la forma recomendada; está bien documentada y cientos de personas lo hacen de esta manera.

1 me gusta

Lo siento, tienes razón, me salté esa parte. Añadí lo siguiente a mi app.yml y ahora carga el foro correctamente:

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 obstante, las cargas de usuarios todavía no funcionan correctamente. Después de la carga en el bucket de S3 (correctamente), la imagen se sirve como:

//my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg
que, por supuesto, no es una ruta válida de S3 o CDN.

En la guía a la que te refieres, hay esta sección que parece relevante:

DISCOURSE_CDN_URL es una CDN que apunta a tu nombre de host de Discourse y almacena en caché las solicitudes. Se utilizará principalmente para activos extraíbles: CSS y otros activos temáticos.

DISCOURSE_S3_CDN_URL es una CDN que apunta a tu bucket de almacenamiento de objetos y almacena en caché las solicitudes. Se utilizará principalmente para activos insertables: JS, imágenes y cargas de usuarios.

Recomendamos que sean diferentes y que los administradores configuren ambos.

Sin embargo, no estoy seguro de qué establecer como DISCOURSE_CDN_URL. ¿Debería establecerlo al mismo valor que DISCOURSE_S3_CDN_URL: https://dsxxxxx2qn.cloudfront.net o crear una instancia de CDN separada?

De nuevo, quizás sea algo totalmente diferente :confused:

¡Muchas gracias por toda la ayuda!

Tienes que configurar CDN y usar tu dominio deseado en el lado de AWS. Además en DNS.

Pero, ¿por qué? Prácticamente nadie ve nunca esa URL.

1 me gusta

Hola Jake, no estoy seguro de entender bien a qué te refieres. ¿Podrías explicarlo un poco más?

¿Quizás quisiste decir que en lugar de configurar el bucket de S3 como origen de la CDN, debería configurar mi dominio forum.hobiguru.com como origen? Si es así, no creo que eso cambie nada, ya que es el foro de Discourse el que genera esas URL que no llevan a ninguna parte, por ejemplo: //my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg

Procedí a añadir también DISCOURSE_CDN_URL: https://dsuxxxhrz2qn.cloudfront.net y ahora estoy esperando a que la aplicación se reconstruya :crossed_fingers:

ACTUALIZACIÓN: tampoco funcionó :/\n\nAgradezco mucho la ayuda.
Gracias

Simplemente no puedes nombrar un subdominio solo en app.yml. Nadie puede usarlo sin la información DNS adecuada. Y dado que la entrega de tus archivos se realiza desde AWS, también tienes que configurar ese lado, si quieres usar CDN.

Pero de nuevo. Los usuarios ven la URL de Discourse, si quieren verla. Es bastante raro que alguien que no sea un administrador quiera hacer algo. Y los usuarios prácticamente nunca ven la URL de los medios u otros archivos estáticos.

Así que mi punto de vista es que estás perdiendo el tiempo en vano si no quieres usar CDN. Y eso puede ser inteligente si tienes una audiencia global, y algunos de ellos están detrás de conexiones de nivel estatal deficientes.

Vivo en Finlandia. No obtengo ningún beneficio real si un sitio al otro lado del mundo, en Australia, usa CDN (desde un servidor que se encuentra a 1000 km de mí). El verdadero cuello de botella proviene de cómo está construido ese sitio, como si se usan muchas llamadas PHP innecesarias sin suficientes recursos.

Pero básicamente no puedes usar una URL cdn.example.tld sin poner cdn al menos en DNS.

Hola @Jagster

En realidad, no quiero usar una CDN en absoluto; solo quiero que todas las cargas de usuarios se almacenen en S3 y se sirvan directamente desde allí, aunque CloudFront es realmente una mejor solución que S3 directamente.

Mi problema surgió cuando intenté configurar S3 (específicamente para servir activos, no cargas), y @pfaffman sugirió que siguiera la guía Configurar un proveedor de almacenamiento de objetos compatible con S3 para cargas y configurara una CDN.

Con respecto a tu comentario:

“Simplemente no puedes nombrar un subdominio solo en app.yml. Nadie puede usarlo sin la información de DNS adecuada. Y como tus archivos se sirven desde AWS, también tienes que configurar ese lado, si quieres usar una CDN.”

Lo siento, pero no entendí del todo a qué te referías con este párrafo. ¿Podrías elaborar un poco más o aclarar? ¿Estás diciendo que necesito configurar registros DNS para mi bucket S3 o que hay algo específico que necesito ajustar en el lado de AWS?

¡Gracias de antemano por tu ayuda!

Hola de nuevo a todos,

Quería dar seguimiento a mi publicación anterior y compartir que he avanzado un poco.

Lo que funciona ahora

  • Las cargas de usuario se sirven correctamente desde mi bucket S3 a través de la CDN (CloudFront), ¡así que eso es genial!

Sin embargo, todavía tengo un problema con los assets precompilados

Los assets precompilados todavía no se sirven correctamente desde la CDN

Cuando configuro DISCOURSE_CDN_URL a la URL de CloudFront (es decir, https://dsuqioxhrz2qn.cloudfront.net), las URL de los assets precompilados se convierten en:

  • https://dsuqioxhrz2qn.cloudfront.net/stylesheets/color_definitions_shades-of-blue_7_1_e6f11758f9c015d1e5ed9b08c437e9c5c267c932.css?__ws=forum.hobiguru.com
  • https://dsuqioxhrz2qn.cloudfront.net/stylesheets/discourse-presence_308d905aa5c03567866fec50e9a28d8721ab0463.css

El problema es que estas rutas no existen en mi bucket S3. Los assets precompilados se cargan en la carpeta /assets/* en S3 (por ejemplo, /assets/locales, /assets/plugins, /assets/scripts), pero no hay una carpeta /stylesheets/ y, por supuesto, la carga de esas URL resulta en un error 403 forbidden.

Si, en cambio, cambio DISCOURSE_CDN_URL: https://forum.hobiguru.com, entonces mi foro funciona correctamente, pero los assets ahora se sirven desde el servidor (por ejemplo, https://forum.hobiguru.com/) y no desde la CDN (por ejemplo, https://forum.hobiguru.com/stylesheets/admin_308d905aa5c03567866fec50e9a28d8721ab0463.css?__ws=forum.hobiguru.com)

Mi configuración actual (para contexto) es:

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_BUCKET: hobiguru-s3-bucket-eu
DISCOURSE_S3_CDN_URL: https://dsuqioxhrz2qn.cloudfront.net  # Asegúrate de que la URL de la CDN apunte a CloudFront
DISCOURSE_CDN_URL: https://forum.hobigur.com # ¡OBSERVA ESTO!

y los hooks de precompilación:

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 después de precompilar los assets, se cargan en S3 en una estructura determinada, pero luego, cuando se cargan a través de la CDN, la ruta a los objetos está un poco desviada.