Amazon S3
Before you begin
An AWS account with permission to create IAM users/policies and S3 buckets.
For the full WordPress workflow beyond provider credentials, see the WordPress S3 Media Offload complete guide. If you are comparing providers before deployment, read Cloudflare R2 vs Amazon S3 for WordPress Media. WooCommerce stores can also use the Amazon S3 storage for WooCommerce media guide for product-image and catalog-specific checks.
Steps
-
Bucket — S3 console → Buckets → create or choose one; note the name and region. Object Ownership is usually “Bucket owner enforced” (ACLs disabled) — this plugin never sets object ACLs.
-
IAM user — IAM console → Users → Create user → programmatic access only (no console password needed).
-
Policy — attach an inline policy scoped to your bucket:
{"Version": "2012-10-17","Statement": [{ "Sid": "ListBucket", "Effect": "Allow","Action": ["s3:ListBucket", "s3:GetBucketLocation"],"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME" },{ "Sid": "ObjectReadWrite", "Effect": "Allow","Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject","s3:AbortMultipartUpload", "s3:ListMultipartUploadParts"],"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*" }]}To scope to a key prefix instead, add a
Conditionwiths3:prefixon theListBucketstatement and change the object-actionsResourcetobucket/PREFIX/*— then set the same prefix in Universal Storage → Storage. The Universal Storage → Health screen generates this policy pre-filled for your current bucket/prefix. -
Access key — IAM → your user → Security credentials → Create access key (“Application running outside AWS”). The secret is shown once — store it now.
-
In Universal Storage → Settings, choose provider Amazon S3, enter the bucket, region, and the access key/secret, then Test connection. When Amazon S3 is selected, custom endpoint and path-style settings from previous S3-compatible configurations are ignored so the connection test targets AWS S3 directly.
Public delivery
The plugin never sets public-read ACLs. For public delivery, use a CDN (CloudFront with
Origin Access Control is the standard pattern) or a bucket policy allowing
s3:GetObject, and set that hostname as the CDN/Base URL in Universal Storage →
Storage.
Verify it worked
Test connection on the Storage screen passes all steps (client, bucket, upload, HEAD, delete). If your bucket has no public read path configured, the test also warns you about that explicitly rather than letting it fail silently at delivery time.
Troubleshooting
Amazon S3 PermanentRedirect / 301 wrong endpoint
If Amazon S3 returns PermanentRedirect or HTTP 301 Moved Permanently, the bucket is
being addressed through the wrong S3 endpoint. AWS documents PermanentRedirect as a
request that must be sent to the endpoint specified for that bucket. A wrong-Region
request can also surface as a redirect-style or Region-related error depending on the
Region and request path.
Check these in order:
- Open the bucket in AWS and confirm its actual Region.
- Make sure the Region configured in Universal Storage matches that bucket Region.
- Use the normal Amazon S3 provider preset instead of carrying over a custom endpoint from an S3-compatible provider.
- Re-run Test connection.
- From CLI, run
wp universal-storage testto reproduce the request outside the admin button. - If you are debugging another client or SDK, inspect the S3 XML error response for the endpoint/Region AWS expects instead of blindly following a cached redirect.
AWS references: Request routing and S3 error responses.
AccessDenied/403 — the IAM policy is missing, attached to the wrong user, or scoped to
the wrong bucket/prefix. Confirm under IAM → Users → your plugin’s user → Permissions. Run
wp universal-storage test for a CLI-side check independent of the admin button.