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.

What This Post Covers
Why limited (per-bucket) access keys cause
403 Forbiddenon bucket-level operations.Two ways to make objects public by default:
--acl-publicvia s3cmd and a JSON bucket policy.How to enable Spaces access logs through the S3-compatible API.
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.
1. Use a Full-Access Spaces Key for Bucket-Level Changes
Spaces access keys come in two scopes: full access and limited (per-bucket) access (DigitalOcean docs).
Two practical implications:
- Limited keys are currently incompatible with bucket policies (bucket policy docs).
- Bucket-level features like access logs require bucket-level permissions; use a full-access key to configure them.
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.
2. Option A: Use ACLs with 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).
a. (Optional) Enable public directory listings
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
b. Make existing objects public (recursive)
s3cmd setacl s3://YOUR_SPACE/ --acl-public --recursive
c. Upload new objects as public
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.
3. Option B: Use a Bucket Policy for Public Reads (No Per-Upload ACL)
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.)
- Create
public-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_SPACE/*"
}
]
}
- Apply it with the AWS CLI (endpoint is required for Spaces):
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).
4. (Optional) Configure Spaces Access Logs
DigitalOcean documents Spaces access logs (including constraints and the expected API shape) here: Configure access logs.
- Create
logging.json:
{
"LoggingEnabled": {
"TargetBucket": "your-log-destination-bucket",
"TargetPrefix": "logs/"
}
}
The target bucket must be different from the source bucket.
- Enable logging:
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
tl;dr
- Use a full-access key for
PutBucketPolicyandPutBucketLogging. - For “public objects”, either:
- Use ACLs (
s3cmd put ... --acl-public), or - Use a bucket policy that allows
s3:GetObjectonarn:aws:s3:::YOUR_SPACE/*.
- Use ACLs (