AWS S3 + CloudFront + Custom Domain/SSL + Signed URL

I know there are many tutorials out there about these topics, but it still took me +3 hours to configure them correctly 😂 I have read and watched every individual topic, but when it came to actually set them up, I just couldn’t get it right 😭

I hope it is not a shame to blame the fact that most of the tutorials focus on diving deep into a single topic, definitely not a combination of S3, CloudFront, custom domain with Certificate Manager and Route 53, and signed URL. More importantly, AWS “user-friendly” and “aesthetically pleasing” console dashboard just confounds me (please forgive me, I switched from Digital Ocean where the UI/UX is just amazing) 😵


At the end of the post, we should be able to achieve uploading a file to S3 via a signed URL and viewing that file ONLY via a custom domain served over HTTPS whose certificate is managed by AWS Certificate Manager.

This post is all about steps, no topic deep dive.



Step 1: create a new bucket.

Step 2: go with default for the rest configurations, especially “Block Public Access” settings.

  • We want to block all public access (default) because this prevents anyone from accessing our bucket or content in the bucket directly.

Step 3: add CORS.

  • Once S3 bucket is created successfully, navigate to the bucket “Permissions“ settings.
  • Scroll all the way to the bottom where we should find CORS settings.
  • Click “Edit” and copy and paste the following JSON (feel free to tweak it to meet your app security requirement).
"AllowedHeaders": [
"AllowedMethods": [
"AllowedOrigins": [
"ExposeHeaders": [],
"MaxAgeSeconds": 3000

Certificate Manager

Prerequisite: On the Certificate Manager dashboard, please make sure we are on region us-east-1. If not, switch to this region before proceeding with the following steps.

Step 1: add domain names.

  • This domain name will be the alternative domain name to access CloudFront.

Step 2: select validation methods.

  • Make sure to select DNS validation if the domain is owned by you (I guess yes).

Step 3: add tags (skip if not necessary).

Step 4: review.

Step 5: validation.

  • Expand the domain dropdown.
  • Click that “Create record in Route 53” blue button.
  • Once the modal pops up, click the “Create” button.

Step 6: verification.

  • Navigate back to the Certificate Manager home page.
  • We should see the status change from “Pending” to “Issued”.
  • This process may take around 10 minutes, so be patient 🙃


Step 1: configure “Origin Settings”

  • Pay attention to settings circled in green because we need to change their values.
  • Origin Domain Name: select the S3 bucket we just created. IMPORTANT: I’d recommend adding the S3 region in the auto-populated option to avoid IllegalLocationConstraintException issue. So it will end up looking like this: <bucket>.s3.<region>
  • Origin ID: auto-filled once “Origin Domain Name” is selected.
  • Restrict Bucket Access: select “Yes”.
  • Origin Access Identity: select “Create a new Identity”.
  • Comment: auto-filled when we select “Create a new Identity”.
  • Grant Read Permissions on Bucket: select “Yes, Update Bucket Policy”.

Step 2: configure “Default Cache Behavior Settings”.

  • Viewer Protocol Policy: select “Redirect HTTP to HTTPS”.

Step 3: configure “Distribution Settings”.

  • Alternative Domain Names (CNAMEs): the domain name typed here should be identical to what we have added when we set up the Certificate Manager.
  • SSL Certificate: select “Custom SSL Certificate”, and in the input box below, select the certificate we have created. If this option is greyed out, it probably means the certificate is not created in us-east-1 (pay attention to the prerequisite for Certificate Manager setup).

Step 4: click the “Create Distribution” blue button.

  • Deploying a new CloudFront will take a while, so just be patient here :)

Step 5: verify it is ready.

  • Go back to the CloudFront home page. We should be seeing our new distribution created successfully.


Route 53

Step 1: go to Route 53 dashboard and click the “Hosted zones” link.

Step 2: on the hosted zone page, click your domain name.

Step 3: create an A record.

  • Record name: just need to fill in the subdomain.
  • Record type: select “A” record.
  • Alias: toggle it on.
  • Route traffic to: select “Alias to CloudFront distribution”.
  • Then in the last dropdown box, select the CloudFront distribution domain name created earlier. If not sure, we can always go back to the CloudFront home page to verify it.


I hope the above steps take you less than 30 mins. Now it is time to test our setup.

Upload a File via Signed URL

Simply run the file below, we should be able to upload any file to S3 via a signed URL.

View the File via Direct S3 URL

Since we blocked all public access to the bucket and its content, we should see an access denied error if we try to access the file via a direct S3 URL.

View the File via CloudFront URL

Expected to see the file.

View the File via Custom Domain URL

Expected to see the file.


🥳 Congrats! You made it! I hope you had fun navigating the AWS console and clicking the “grey” and “blue” buttons 😏

Give it some 👏 and share it with others if this step-by-step tutorial helped you! Much appreciated ❤️

I aim to save people from the overwhelming tsunami of information.