<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shamnad Shaji</title>
    <description>The latest articles on DEV Community by Shamnad Shaji (@shamnad_shaji).</description>
    <link>https://dev.to/shamnad_shaji</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1615040%2Fda683b5e-bef3-4563-8d62-ab5236289820.jpg</url>
      <title>DEV Community: Shamnad Shaji</title>
      <link>https://dev.to/shamnad_shaji</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shamnad_shaji"/>
    <language>en</language>
    <item>
      <title>Common Mistakes When Accessing Files from a Custom URL Using CloudFront and S3</title>
      <dc:creator>Shamnad Shaji</dc:creator>
      <pubDate>Sat, 05 Apr 2025 05:32:40 +0000</pubDate>
      <link>https://dev.to/aws-builders/common-mistakes-when-accessing-files-from-a-custom-url-using-cloudfront-and-s3-1ah0</link>
      <guid>https://dev.to/aws-builders/common-mistakes-when-accessing-files-from-a-custom-url-using-cloudfront-and-s3-1ah0</guid>
      <description>&lt;p&gt;Working with &lt;strong&gt;Amazon CloudFront and S3&lt;/strong&gt; is a popular and powerful combo when it comes to hosting static files, configuring custom URLs, or enabling features like &lt;strong&gt;Apple Universal Links&lt;/strong&gt; (via &lt;code&gt;apple-app-site-association&lt;/code&gt;). But it's also easy to make configuration mistakes that can cause frustrating errors like &lt;strong&gt;"Access Denied"&lt;/strong&gt; or &lt;strong&gt;"NoSuchKey"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through one of the most common mistakes, one that I recently ran into myself and how to fix it quickly.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❌ The Problem: “Access Denied” or 404 from CloudFront
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz07uohzjzato6uyh6zei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz07uohzjzato6uyh6zei.png" alt="access denied" width="800" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s say you want to serve a file like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://your-cloudfront-url/.well-known/apple-app-site-association
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You upload the file with name apple-app-site-association, to your S3 bucket and configure a CloudFront distribution. In the process, you set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Origin Domain&lt;/strong&gt;: &lt;code&gt;your-bucket.s3.region.amazonaws.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin Path&lt;/strong&gt;: &lt;code&gt;/.well-known/apple-app-site-association&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything seems perfect, but when you try to access the file through CloudFront, you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AccessDenied
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The specified key does not exist.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔍 What Went Wrong
&lt;/h2&gt;

&lt;p&gt;Here’s the &lt;strong&gt;key misunderstanding&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;Origin Path&lt;/code&gt; in CloudFront is not the full file path, it’s a prefix that's automatically added to every request path.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, if your CloudFront request is for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/.well-known/apple-app-site-association
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And your origin path is also set to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/.well-known/apple-app-site-association
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then CloudFront tries to fetch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;S3: /.well-known/apple-app-site-association/.well-known/apple-app-site-association
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which obviously doesn’t exist — hence the error.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ The Correct Setup
&lt;/h2&gt;

&lt;p&gt;Here’s how to fix and simplify things:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Remove the Origin Path&lt;/strong&gt; from your CloudFront origin settings.&lt;/p&gt;

&lt;p&gt;✅ In your S3 bucket:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a folder called &lt;code&gt;.well-known&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Upload your file inside that folder:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; .well-known/apple-app-site-association
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2enxhu3v090xtpq6x84e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2enxhu3v090xtpq6x84e.png" alt="s3 folder structure" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Make sure &lt;strong&gt;CloudFront&lt;/strong&gt; has access (via &lt;strong&gt;Origin Access Control&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvnfug2hpfk6dwre7zgo4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvnfug2hpfk6dwre7zgo4.png" alt="origin access control" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Leave &lt;strong&gt;Origin path - optional&lt;/strong&gt; as empty&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Secure Bucket Policy for CloudFront OAC&lt;/strong&gt;:&lt;br&gt;
   Add this to your bucket policy (replace &lt;code&gt;ACCOUNT_ID&lt;/code&gt; and &lt;code&gt;DISTRIBUTION_ID&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowCloudFrontAccessViaOAC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cloudfront.amazonaws.com"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::your-bucket-name/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="nl"&gt;"AWS:SourceArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:cloudfront::ACCOUNT_ID:distribution/DISTRIBUTION_ID"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Make sure your bucket has public access &lt;strong&gt;disabled&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftik6qjbekfxsievkrut9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftik6qjbekfxsievkrut9.png" alt="s3 public access disabled" width="800" height="816"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Now, test the file at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://your-cloudfront-url/.well-known/apple-app-site-association
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎉 It should work!&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Takeaway
&lt;/h2&gt;

&lt;p&gt;When working with CloudFront and S3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep the &lt;strong&gt;Origin Path empty&lt;/strong&gt; unless you &lt;strong&gt;really need&lt;/strong&gt; it.&lt;/li&gt;
&lt;li&gt;Structure your &lt;strong&gt;S3 folders to match your desired URL path&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;CloudFront &lt;strong&gt;appends the request path to the origin path&lt;/strong&gt;, so watch out for unnecessary nesting.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🔄 Bonus Tip: Content-Type for apple-app-site-association
&lt;/h2&gt;

&lt;p&gt;If you’re hosting &lt;code&gt;apple-app-site-association&lt;/code&gt;, don’t forget to set the correct &lt;strong&gt;Content-Type&lt;/strong&gt; in S3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;application/json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the file doesn’t have a &lt;code&gt;.json&lt;/code&gt; extension, Apple expects it to have the correct &lt;code&gt;Content-Type&lt;/code&gt; header.&lt;/p&gt;




&lt;p&gt;Hope this helps you avoid the same mistake and get your setup running smoothly.&lt;br&gt;&lt;br&gt;
If this saved you hours of debugging, you’re not alone 😄  &lt;/p&gt;

&lt;p&gt;Let me know in the comments if you’ve run into other CloudFront/S3 gotchas!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>aws</category>
      <category>s3</category>
      <category>cloudfront</category>
    </item>
  </channel>
</rss>
