Make a DigitalOcean Space Public by Default (ACLs and Bucket Policies)
Software engineer and founder with a background in finance and tech. Currently building aVenture.vc, a platform for researching private companies. Based in San Francisco.


Software engineer and founder with a background in finance and tech. Currently building aVenture.vc, a platform for researching private companies. Based in San Francisco.


This guide covers:
403 Forbidden on bucket-level operations.--acl-public via s3cmd and a JSON bucket policy.DigitalOcean Spaces is S3-compatible, but not every S3 operation works with every kind of Spaces access key.
If you’re using a limited (per-bucket) key and you try to configure a bucket policy or access logs, you can hit 403 Forbidden. The fix is to use a full-access key for bucket-level configuration, then pick the public-access approach that matches your use case.
Terminology note: DigitalOcean calls it a Space; the S3 API calls it a bucket.
Spaces access keys come in two scopes: full access and limited (per-bucket) access (DigitalOcean docs).
Two practical implications:
If you only need object uploads/downloads and you’re keeping things private, limited keys are still useful. For the rest of this post, assume you’re using a full-access key.
s3cmd (Fastest Way to Make Objects Public)This is the simplest approach when you’re fine with setting public access at upload time (or retroactively on existing objects).
Install s3cmd (DigitalOcean has a Spaces-specific walkthrough in the s3cmd reference):
# macOS
brew install s3cmd
# Ubuntu / Debian
sudo apt-get install s3cmd
Run s3cmd --configure and enter your Spaces key + secret. When it asks for the endpoint, use YOUR_REGION.digitaloceanspaces.com (for example, sfo3.digitaloceanspaces.com).
This controls whether anonymous users can list objects. If you don’t want public listing, skip this step.
s3cmd setacl s3://YOUR_SPACE/ --acl-public
s3cmd setacl s3://YOUR_SPACE/ --acl-public --recursive
s3cmd put local-file.jpg s3://YOUR_SPACE/remote-file.jpg --acl-public
If you use s3cmd (or another S3-compatible client) in your deploy pipeline, the key detail is: you must include --acl-public (or x-amz-acl: public-read) on new uploads if you want them public via ACLs.
If your goal is “every object in this Space is publicly readable” without remembering ACL flags, a bucket policy is cleaner: allow s3:GetObject on arn:aws:s3:::YOUR_SPACE/* (bucket policy docs).
This only applies to standard Spaces buckets. (Spaces Cold Storage does not support bucket policies.)
public-policy.json:{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_SPACE/*"
}
]
}
aws --endpoint-url https://YOUR_REGION.digitaloceanspaces.com \
s3api put-bucket-policy \
--bucket YOUR_SPACE \
--policy file://public-policy.json
If you see 403 Forbidden here, double-check that you’re using a full-access key (not limited/per-bucket).
DigitalOcean documents Spaces access logs (including constraints and the expected API shape) here: Configure access logs.
logging.json:{
"LoggingEnabled": {
"TargetBucket": "your-log-destination-bucket",
"TargetPrefix": "logs/"
}
}
The target bucket must be different from the source bucket.
aws --endpoint-url https://YOUR_REGION.digitaloceanspaces.com \
s3api put-bucket-logging \
--bucket YOUR_SOURCE_BUCKET \
--bucket-logging-status file://logging.json
To verify:
aws --endpoint-url https://YOUR_REGION.digitaloceanspaces.com \
s3api get-bucket-logging \
--bucket YOUR_SOURCE_BUCKET
PutBucketPolicy and PutBucketLogging.s3cmd put ... --acl-public), ors3:GetObject on arn:aws:s3:::YOUR_SPACE/*.