amazon-s3aws-sdkdigital-oceandigital-ocean-spaces

Cannot upload files with ACL public-read to Digital Ocean spaces


I'm trying to upload images to a Digital Ocean space from the browser. These images should be public. I'm able to upload the images successfully.

However, though the ACL is set to public-read, the uploaded files are always private.

I know they're private because a) the dashboard says that the permissions are "private", and b) because the public urls don't work, and c) manually changing the permissions to "public" in the dashboard fixes everything.

Here's the overall process I'm using.

  1. Create a pre-signed URL on the backend
  2. Send that url to the browser
  3. Upload the image to that pre-signed url

Any ideas why the images aren't public?

Code

The following examples are written in TypeScript and use AWS's v3 SDK.

Backend

This generates the pre-signed url to upload a file.

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'

const client = new S3Client({
    region: 'nyc3',
    endpoint: 'https://nyc3.digitaloceanspaces.com',
    credentials: {
        accessKeyId: process.env.DIGITAL_OCEAN_SPACES_KEY,
        secretAccessKey: process.env.DIGITAL_OCEAN_SPACES_SECRET,
    },
})

const command = new PutObjectCommand({
    ACL: 'public-read',
    Bucket: 'bucket-name',
    Key: fileName,
    ContentType: mime,
})

const url = await getSignedUrl(client, command)

The pre-signed url is then sent to the browser.

Frontend

This is the code on the client to actually upload the file to Digital Ocean. file is a File object.

const uploadResponse = await fetch(url, {
    headers: {
        'Content-Type': file.type,
        'Cache-Control': 'public,max-age=31536000,immutable',
    },
    body: file,
    method: 'PUT',
})

Metadata


Solution

  • Turns out that for Digital Ocean, you also need to set the public-read ACL as a header in the put request.

    //front-end
    const uploadResponse = await fetch(url, {
        headers: {
            'Content-Type': file.type,
            'Cache-Control': 'public,max-age=31536000,immutable',
            'x-amz-acl': 'public-read', // add this line
        },
        body: file,
        method: 'PUT',
    })