If you’ve ever copied an Amazon S3 link and hit a cryptic PermanentRedirect error, you’ve met one of S3’s oldest quirks: bucket region‑specific endpoints. In this post we’ll demystify S3 URLs, show you the right pattern to use, and share quick troubleshooting steps.
TL;DR
- S3 buckets live in one AWS region. Your URL must target that region.
- The legacy global endpoint
https://s3.amazonaws.com/…only works directly for buckets in us-east-1. - Prefer the virtual‑hosted style URL with the regional endpoint:
|
1 2 |
https://<bucket>.s3.<region>.amazonaws.com/<key> |
Example (bucket in us-east-2):
|
1 2 |
https://assets.acme.com.s3.us-east-2.amazonaws.com/favicon/favicon.ico |
Why the global URL fails
When you request https://s3.amazonaws.com/<bucket>/<key> for a bucket not in us-east-1, S3 returns:
|
1 2 3 4 5 6 |
<Error> <Code>PermanentRedirect</Code> <Message>The bucket you are attempting to access must be addressed using the specified endpoint.</Message> <Endpoint>assets.acme.com.s3.amazonaws.com</Endpoint> </Error> |
That’s S3 telling you: “Use the bucket’s regional endpoint instead.”
S3 URL styles (and which to use)
1) Virtual‑hosted style (recommended)
|
1 2 |
https://<bucket>.s3.<region>.amazonaws.com/<key> |
- Modern, region‑aware, works with most clients and browsers.
- Required for features like S3 Object Lambda, Dual‑Stack (IPv6), and Transfer Acceleration variants.
2) Path style (legacy but still supported for many cases)
|
1 2 |
https://s3.<region>.amazonaws.com/<bucket>/<key> |
- Works, but AWS recommends virtual‑hosted style for the long haul.
Note: Legacy “global” path style
https://s3.amazonaws.com/<bucket>/<key>only directly serves objects from us-east-1 buckets. Anywhere else, you’ll get the redirect above.
Quick: what region is my bucket in?
Use the AWS CLI:
|
1 2 |
aws s3api get-bucket-location --bucket <bucket-name> |
- If the result is empty or
null, it’s us-east-1. - Otherwise you’ll see a region like
us-east-2,eu-west-1, etc.
In code/SDKs, always set the client region (e.g., AWS_REGION=us-east-2). Most SDKs then build the right endpoint automatically.
Copy‑paste recipes
Assume:
- Bucket:
assets.acme.com - Region:
us-east-2 - Object key:
favicon/favicon.ico
| Purpose | URL |
|---|---|
| Recommended (virtual‑hosted) | https://assets.acme.com.s3.us-east-2.amazonaws.com/favicon/favicon.ico |
| Alternative (path) | https://s3.us-east-2.amazonaws.com/assets.acme.com/favicon/favicon.ico |
| Dual‑stack (IPv4/IPv6) | https://assets.acme.com.s3.dualstack.us-east-2.amazonaws.com/favicon/favicon.ico |
| Transfer Acceleration* | https://assets.acme.com.s3-accelerate.amazonaws.com/favicon/favicon.ico |
* Transfer Acceleration must be enabled on the bucket and uses the global edge network. Not region‑scoped in the hostname.
Special case: website hosting vs. REST endpoints
S3 has two different endpoint families:
- REST/JSON API endpoints (the ones above): for direct object access and SDKs.
- Static website hosting endpoints: for buckets with “Static website hosting” enabled.
Website endpoints look like:
|
1 2 3 |
http://<bucket>.s3-website-<region>.amazonaws.com/ http://<bucket>.s3-website.<region>.amazonaws.com/ # some regions |
Use website endpoints only when you’ve enabled website hosting and want index/error document behavior and clean paths. They don’t support HTTPS with your own domain by themselves; use CloudFront for HTTPS and caching.
Custom domains (the right way)
If you want https://assets.acme.com/<key> under your own domain:
- Put CloudFront in front of your S3 bucket.
- Add your TLS certificate in ACM for the custom domain.
- Point DNS (CNAME/ALIAS) to the CloudFront distribution.
Avoid CNAME’ing a custom domain directly to an S3 website endpoint for production HTTPS. CloudFront gives you SSL, caching, geo‑performance, and security controls.
Common errors and fixes
PermanentRedirect
- Cause: Using
s3.amazonaws.com(global) for a non‑us-east-1bucket. - Fix: Switch to
https://<bucket>.s3.<region>.amazonaws.com/<key>.
AccessDenied
- Cause: Object or bucket is private, or Block Public Access is on.
- Fix: Use a pre‑signed URL or adjust bucket policy/object ACL as appropriate.
NoSuchKey
- Cause: Wrong key path, casing mismatch (S3 is case‑sensitive).
- Fix: Verify exact key including folder prefixes and case.
Pre‑signed URLs (secure, time‑limited links)
If your bucket isn’t public, generate a time‑limited link:
|
1 2 |
aws s3 presign s3://<bucket>/<key> --expires-in 3600 |
The output is a fully signed URL you can share; no public permissions required.
Checklist before you share an S3 link
- I’m using the regional virtual‑hosted URL pattern.
- The bucket region is confirmed.
- The object key (including case and prefixes) is correct.
- Permissions are set (public object or presigned URL).
- If I need a custom domain + HTTPS, I’m using CloudFront.
Final thoughts
Once you remember that buckets are regional, the rest falls into place. Favor the virtual‑hosted regional pattern, and you’ll avoid redirects, odd edge cases, and broken links.
Got a gnarly S3 URL or policy puzzle? Send it our way—Reliable Penguin loves untangling cloud quirks.




