How I Finally Got a DigitalOcean Spaces Bucket to Default Public (Spoiler: Ditch Per-Bucket Keys)
Software engineer and entrepreneur based in San Francisco.
Software engineer and entrepreneur based in San Francisco.
By the end of this guide you'll know:
403 Forbidden
policy errors.I thought making a bucket public on DigitalOcean Spaces would be a ten-second checkbox. Instead I burned an afternoon chasing 403 Forbidden
errors and second-guessing my JSON.
Here's the truth I wish I'd known from the start: if you leave Per-Bucket Access Keys enabled you can't modify most bucket policies—period. Turn that feature off, switch to a regular all-or-nothing access key, and everything snaps into place.
Below is the exact sequence that finally worked for me, with the false turns called out so you don't repeat them.
DigitalOcean's per-bucket keys sound great on paper: tight scoping, least-privilege, all that good stuff. Unfortunately the current implementation blocks PutBucketPolicy
, PutBucketLogging
, and a few other S3 calls—even if the UI insists the key has those permissions.
Fix: In the Spaces dashboard, open your bucket ➜ Settings ➜ toggle Per-Bucket Access Keys off. Grab a classic Spaces key (or create a new one) that has full account-wide access. Use that for every command below.
If you're still seeing 403s after this step, double-check that your CLI is using the new key.
s3cmd
(AWS CLI Works, But s3cmd
is Friendlier Here)# macOS
brew install s3cmd
# Ubuntu / Debian
sudo apt-get install s3cmd
Run s3cmd --configure
and drop in your Spaces key, secret, and region (for me: sfo3
). When it asks for the endpoint, use sfo3.digitaloceanspaces.com
(swap for your region).
This is the zero-friction route I recommend.
s3cmd setacl s3://YOUR_BUCKET --acl-public
s3cmd setacl s3://YOUR_BUCKET/ --acl-public --recursive
s3cmd put local-file.jpg s3://YOUR_BUCKET/remote-file.jpg --acl-public
That's it. Skip the rest of the post unless you love yak-shaving.
Feel like you must use a proper policy? Fine—just remember the Per-Bucket Keys warning above.
public-policy.json
:{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_BUCKET/*"
}
]
}
aws s3api put-bucket-policy \
--bucket YOUR_BUCKET \
--endpoint-url https://YOUR_REGION.digitaloceanspaces.com \
--policy file://public-policy.json
If that still throws a 403, triple-check that you're using a non-scoped key.
Back in early 2025 you had to open a support ticket to enable server access logging. As of July 2025 the feature is rolled out for everyone—no ticket required.
Enable it with a single call:
aws s3api put-bucket-logging \
--bucket YOUR_SOURCE_BUCKET \
--endpoint-url https://YOUR_REGION.digitaloceanspaces.com \
--bucket-logging-status '{
"LoggingEnabled": {
"TargetBucket": "your-log-destination-bucket",
"TargetPrefix": "logs/"
}
}'
If you get a 403 here, you already know the likely cause: you forgot to disable Per-Bucket Access Keys.