Configurar cargas de archivos e imágenes a 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 Me gusta

Esta narrativa necesita ser actualizada. O no puedo. Después de la instalación, las imágenes se suben al bucket, pero no puedo acceder a ellas. No importa lo que hice, no funcionó. ¿Alguien ha intentado esto recientemente y lo ha conseguido?

1 me gusta

¿Qué sucede cuando intentas acceder a ellos?

¿Tienes una CDN?

¿Qué servicio utilizaste?

¿Se cargaron las imágenes y los permisos del bucket no te permiten verlas?

Si el PM necesita ser actualizado, tendrás que proporcionar más información sobre lo que hiciste y lo que está sucediendo.

¿El sitio es público? ¿Dónde?

1 me gusta

Sigo la explicación al pie de la letra. Subo las imágenes. Sin embargo, no se puede acceder a las imágenes. URL de ejemplo: https://awssorucevap24.s3.eu-central-1.amazonaws.com/original/2X/6/62c89621b0764112e0029bc91c957dd49d75d819.jpeg

La sección de permisos se ve así:

No abro la ACL al instalar el Bucket, no hay información al respecto y no puedo acceder a ella incluso cuando cambio esta configuración en mis intentos anteriores.

Nota adicional: No hay una configuración de “Acceso programático” al crear un usuario, hace mucho tiempo que existía, ya no está. ¿Podría estar relacionado con esto? ¿O puede explicar cómo podemos hacerlo en el nuevo sistema al crear un usuario?

También preparé el dominio de cloudfront y cdn. Mi único problema es que no tengo acceso a los archivos. Espero que podamos encontrar lo que me perdí :slight_smile:

1 me gusta

rake uploads:migrate_to_s3
FileStore::ToS3MigrationError: Por favor, proporcione las siguientes variables de entorno: (FileStore::ToS3MigrationError)

  • DISCOURSE_S3_BUCKET
  • DISCOURSE_S3_REGION
    y una de las siguientes:
  • DISCOURSE_S3_ACCESS_KEY_ID
  • DISCOURSE_S3_SECRET_ACCESS_KEY
    o
  • DISCOURSE_S3_USE_IAM_PROFILE

Según lo que veo, no es ni la clave de acceso NI el perfil IAM. En mi caso, estoy usando el perfil IAM. ¿Alguna recomendación aquí?

1 me gusta

Creo que necesitas definir estos datos en un archivo yml. Primero, asegúrate de que el proceso de carga funcione y luego migra.

¿Cómo lo configuraste, por cierto? Intenté hacer esto, los archivos se subían pero no se abrían en el navegador. Daba un error de acceso denegado.

1 me gusta

La carga y el acceso de lectura pública funcionan correctamente.

Estoy usando el rol y la política de IAM adjuntos a EC2. Avísame si quieres más detalles al respecto.

Ah, creo que sé lo que está pasando en tu caso. Revisa estas configuraciones:

Bloquear acceso público (configuración del bucket)

Propiedad del objeto

Lista de control de acceso (ACL) – Probablemente aquí está el truco para ti

3 Me gusta

No vi nada en la explicación sobre cómo activar la configuración de ACL, así que intenté hacerlo sin tocarla cada vez.

Ya no es importante para mí, cambiaré a Cloudflare R2. Esta explicación será muy útil para alguien más en el futuro. Gracias.

2 Me gusta

No estoy seguro de si esta es la mejor configuración, pero es la forma en que la encontré hasta ahora. Quiero pedirle al @equipo que le eche un vistazo y nos guíe.

¿Es esta la mejor manera de mantenerlo seguro y funcionando correctamente?

2 Me gusta

¿Podrías compartir más detalles sobre esto?

1 me gusta

Después de algunos esfuerzos, cambié a R2 (no olvidemos a los amigos que ayudaron, respeto). Los archivos de assets y uploads se publican en clouflare. El único problema es que no pude conseguir que los archivos theme-javascripts y stylesheets se subieran automáticamente a R2. Investigaré este problema cuando tenga tiempo.

1 me gusta

¿Fue una decisión técnica, de costos o ambas?

1 me gusta

El primero es técnico, no pude instalar Amazon, pero ya estaba usando Cloudflare, así que pensé, ¿por qué no instalar CDN desde allí? Y luego vi que fue una buena decisión porque Cloudflare lanzó este servicio para nosotros, los desarrolladores, frente a los sistemas de nube S3 excesivamente caros. ¿No es muy bueno?

1 me gusta

Me gusta. Le echaré un vistazo más a fondo.

¿Y qué hay de la integración en Discourse? ¿Cómo fue esa experiencia?

¿También estás utilizando Cloudflare WAF?

1 me gusta

No, no lo he usado, de hecho, no estoy seguro de si lo necesitaré. Pero uso “ARGO” de Cloudflare.

2 Me gusta

Tengo un bucket S3 para cargas de imágenes con ACL habilitado y un rol IAM configurado correctamente y asignado a la instancia EC2 que ejecuta mi instancia independiente. Sin embargo, las URL de imágenes S3 en mis publicaciones de prueba no se pueden ver. Me gustaría alojar imágenes S3 en un bucket que solo puedan ver los usuarios de Discourse registrados. ¿Por qué las referencias de URL a imágenes S3 no incluyen una URL pre-firmada para un acceso adecuado? Si accedo al archivo a través de la consola S3 y solicito una URL pre-firmada a través de AWS por un período de tiempo definido, como 10 minutos, la imagen se cargará como se esperaba, así que sé que puede funcionar.

1 me gusta

¿Estamos seguros de que debe almacenarse en el archivo app.yml?

Lo hice de esta manera;

# entrar en la aplicación
cd /var/discourse
./launcher enter app

# pasar las variables de entorno con el comando en tiempo de ejecución
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

Lo hice de esta manera ya que no quería que mi clave de acceso permaneciera en el archivo YAML porque la respaldo en varios lugares. Pasar la clave secreta de AWS a través del entorno es ~generalmente~ un poco más “seguro”. Creo, ¿verdad? No estoy seguro de cuánto tiempo persiste el historial de desplazamiento dentro del contenedor de la aplicación, supongo que se borra después de que el contenedor se reinicia.

Quería configurar el acceso a S3 de la manera “normal” almacenando la Clave de Acceso y la Clave Secreta de AWS en el archivo ~/.aws/credentials del servidor, sin embargo, no estoy completamente seguro de cómo funcionaría eso con la aplicación ejecutándose dentro del contenedor.

Además, según la guía aquí, se te instruye a copiar y pegar las claves de Acceso y Secreto en la interfaz web de Configuración de Administración de Discourse y guardarlas allí; no me queda claro dónde se almacenan estas claves en el backend, ya que al guardarlas aquí no se rellena el archivo app.yml con ellas. ¿Así que supongo que están en la base de datos Postgres en algún lugar? ¿Con suerte cifradas, tal vez?

Espero que al no almacenar las claves de Acceso y Secreto de AWS en el app.yml, no tenga problemas en el futuro. ¿Hay algún otro proceso que requiera que las claves vivan allí?

1 me gusta

Activé AWS Cloudfront para una caché CDN delante de mi bucket S3, configurado como se describe aquí. Sin embargo, la configuración de Cloudfront requirió algunas modificaciones en las políticas de acceso de S3. En particular, parece haber algunas políticas que restringirían el acceso al bucket S3 solo a Cloudfront, en lugar del acceso público que sugiere esta guía. ¿Alguien puede revisar cuáles deberían ser las políticas de permisos correctas para el bucket S3 si se está utilizando una CDN de Cloudfront con el bucket S3 en Discourse? Actualmente, mi CDN está funcionando, pero no estoy seguro de si necesito eliminar algún permiso de acceso extralimitado del bucket S3.

1 me gusta

Usé esta política de bucket que se muestra en la primera publicación de este tema, en un nuevo bucket de AWS. Pero a día de hoy, está dando un error de sintaxis JSON.

Error al dar la política dada en la OP/1ª publicación del tema: Da errores de "Principal faltante", "Política no admitida" en las líneas 4, 23, 26, 29, y cuando logro solucionar esos errores de alguna manera leyendo la documentación de AWS, entonces aparece "Error de sintaxis JSON" hacia el final del 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": "*"
    }
  ]
}
El que intenté crear, que no muestra ningún error de sintaxis en la consola, excepto un error de "Principal no válido", que no pude superar #### Usé mis propios nombres 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 me gusta

Este tema realmente necesita una actualización. Estuve en S3/IAM modificando la política y también noté los errores. ¡Afortunadamente, parece funcionar bien!

Me pregunto si a alguien con las habilidades y el conocimiento necesarios le importaría echar un vistazo y actualizar cuál debería ser la política. ¿@pfaffman?

5 Me gusta