AWS Logo
Menu
Host Your Portfolio on AWS: S3, CloudFront, Route 53 & CI/CD

Host Your Portfolio on AWS: S3, CloudFront, Route 53 & CI/CD

A step-by-step guide for seamlessly hosting a portfolio website on AWS with S3, CloudFront, Route 53, CodeBuild & CodePipeline for automated CI/CD deployment.

Published Nov 3, 2024
Last Modified Nov 17, 2024

Introduction

A personal portfolio website has become an essential tool in the digital world, acting as a powerful, interactive resume. It’s a space to display your skills, showcase your projects, and share your professional story with prospective employers, clients, and collaborators. More than a traditional resume, a portfolio site provides an immersive experience that highlights your technical capabilities, creativity, and dedication to your craft.
Hosting a portfolio on AWS boosts reliability, scalability, and security. By utilizing AWS services such as S3 for storage, CloudFront for rapid content delivery, Route 53 for DNS management, and CodeBuild with CodePipeline for continuous deployment, you can maintain a resilient, high-performing site. This guide provides a complete walkthrough to set up and launch your portfolio on AWS, ensuring a seamless, professional online presence.
If you'd like to skip manual configuration and explore how to automate hosting your portfolio using Infrastructure as Code, check out my follow-up guide here.

AWS Resources Used

Route 53

S3

AWS Certificate Manager (ACM)

CloudFront

AWS CodeBuild

AWS CodePipeline


Background

AWS offers powerful tools that make hosting a static website straightforward. However, with so many guides, resources, and configuration options, the setup process can often feel overwhelming. This guide aims to simplify that process, making it easy to navigate AWS resources while building something impressive.
This section explains how key components of AWS work together for a static site. If you’re already familiar with these AWS services, feel free to skip ahead to the Tutorial section.

Creating a Static Website on AWS

The simplest approach to create a static website on AWS is to upload your HTML files to an S3 bucket, making them publicly accessible.
By pairing this with a custom domain and an Alias record in a Hosted Zone through Route 53, you can have a functional, branded website up and running with minimal configuration.
static website with s3 http diagram
Static Website with HTTP
While simple and effective, this setup can have two potential issues (depending on your requirements):

Potential Issues

1) 'www' Redirection:
If your S3 bucket is configured for example.com, navigating to www.example.com will result in a 404 error. To resolve this, you can create a second S3 bucket specifically for www.example.com and configure it to redirect requests to the root bucket (example.com), which hosts your website files.
static website with s3 and www-redirect http diagram
Static Website with HTTP and www-Redirect
2) HTTPS Support:
One limitation of S3 website endpoints is their lack of native HTTPS support, which is often essential for security and user trust. Adding CloudFront in front of your S3 bucket and attaching an SSL certificate from AWS Certificate Manager (ACM) can enable HTTPS, along with global caching for faster load times and improved performance.
static website with s3+cloudfront https diagram
Static Website with HTTPS

Solution

When you combine these ideas, you end up with a static website hosted on S3 with a custom domain through Route 53, HTTPS for security, CloudFront for faster load times and caching, and full support for both www and non-www requests.
static website with s3+cloudfront and www-redirect https diagram
Static Website with HTTPS and www-Redirect

Adding a CI/CD Pipeline

After creating a functional website, you’ll set up a CI/CD pipeline using AWS CodeBuild and AWS CodePipeline. This pipeline will automate future updates and invalidate the CloudFront cache, ensuring that changes go live instantly whenever code is pushed to your GitHub repository.
aws codebuild & codepipeline diagram
CI/CD Pipeline Using AWS CodeBuild & AWS CodePipeline
Now that you understand what you'll be building, let's begin!

Tutorial

1. Route 53 & Hosted Zones

Consider purchasing a custom domain name for your personal portfolio. A domain like FirstnameLastname.com is memorable, professional, and typically costs around $10-$15 per year. You will create and configure a Hosted Zone for the domain that you use.
A public hosted zone is a container that holds information about how you want to route traffic on the internet for a specific domain, such as example.com, and its subdomains (acme.example.com, zenith.example.com).
  1. Navigate to the Route 53 service in the AWS Console.
  • You have two options for setting up your domain.

Option 1: Purchasing and Registering a New Domain Directly Through AWS

You can purchase and register a domain directly through AWS within the Route 53 service, which simplifies configuration and reduces setup steps.
  1. From the left-hand menu, under the Domains section, click on Registered Domains, then choose Register Domains to start the registration process.
  2. After choosing, purchasing, and registering your new domain, it will appear in the Hosted Zones section once approved, where you can manage its DNS settings.

Option 2: Using an Existing Domain from Another Provider

If you have an existing domain, or wish to purchase one through another provider, you can use that domain with AWS by creating a hosted zone and updating its DNS settings to point to AWS Nameservers.
  1. From the left-hand menu, click on Hosted Zones, then choose Create Hosted Zone to create a new hosted zone.
  2. For the Domain name, enter your existing domain without a www-prefix (e.g., example.com). Adding a description is optional.
  3. For Type, choose Public hosted zone, and then click Create hosted zone to complete the setup.
  4. Back in the Hosted Zones section, navigate to your newly created zone, and take note of the Nameservers in the NS record. They should look something like this:
  • ns-620.awsdns-13.net.
  • ns-156.awsdns-19.com.
  • ns-1191.awsdns-20.org.
  • ns-1922.awsdns-48.co.uk.
5. Go to your domain provider's DNS settings for your domain. There should be an option to change the Nameservers. Replace the current Nameservers with the AWS Nameservers in the previous step.
Note: Your domain provider might issue a warning against changing Nameservers. This can be safely ignored. The changes can take up to 24 hours to propagate (but usually only take a few minutes). Once complete, all future DNS settings for this domain will be managed through AWS in the hosted zone you created.
You will return to Route 53 later in the tutorial to finish configuration.

2. Portfolio Website Assets

You have a lot of options when it comes to building your portfolio, typically using files like HTML, CSS, JavaScript, and images. My preferred setup is with React and Next.js, where running npm run build quickly generates all the necessary production assets. There are numerous free resources available to download portfolio templates if you need a starting point, or you can clone my repository to access files from my portfolio.
For simplicity, however, this tutorial will only require an index.html file displaying 'Hello World' and a 404.html file displaying '404 Not Found.'

index.html

404.html

3. S3 Buckets

You'll be creating two S3 buckets: one as the root bucket to store the portfolio website files, and a second redirect bucket for redirecting 'www' traffic to the root bucket.
Note: If you’d prefer your website to redirect to a 'www' prefix instead, simply reverse these roles.

Create the Root Bucket

  1. Navigate to the S3 service in the AWS Console and ensure you're in your preferred region.
  2. Create an S3 Bucket for the root bucket.
    • Click Create bucket to set up a General purpose S3 bucket and name it after your domain, without the 'www' prefix (e.g., example.com)
    • Ensure ACLs disabled (recommended) is selected.
    • Uncheck 'Block all public access' and confirm the acknowledgement warning to ensure the bucket is accessible to the public and internet-facing.
    • Enable Bucket Versioning and select Server-side encryption with Amazon S3 managed keys (SSE-S3) for encryption.
    • Disable Bucket Key and Object Lock (in Advanced settings) and click Create bucket.
  3. Upload Website Assets
    • Access your bucket and use the uploader to add your website files to the S3 bucket.
    • Ensure your index.html and 404.html files are located in the root directory of the bucket.
  4. Enable Static Website Hosting
    • Go to the Properties tab in the bucket, scroll to the bottom, edit Static website hosting to select Enable, and ensure that Host a static website is selected.
    • Specify the Index document, which for this tutorial is index.html. Additionally, set the Error document to 404.html. and press Save Changes.
    • Take note of the Bucket website endpoint at the bottom of the Properties page (which you will use to test the website after the next step).
  5. Add a Bucket Policy
    • Go to the Permissions tab and click Edit to add the necessary Bucket Policy (below) which allows public access. Replace BUCKET_NAME in the policy with your actual bucket name (e.g., example.com) and press Save changes.
Test the Root Bucket
  • Navigate to the root bucket website endpoint from the previous step. If everything is set up correctly, you should see 'Hello world' (or your own index page).

Create the Redirect Bucket

  1. Create another S3 Bucket for the redirect bucket.
    • Click Create bucket to set up a General purpose S3 bucket and name it after your domain, with the 'www' prefix (e.g., www.example.com)
    • Ensure ACLs disabled (recommended) is selected.
    • Uncheck 'Block all public access' and confirm the acknowledgement warning to ensure the bucket is accessible to the public and internet-facing.
    • Disable Bucket Versioning and select Server-side encryption with Amazon S3 managed keys (SSE-S3) for encryption.
    • Disable Bucket Key and Object Lock (in Advanced settings) and click Create bucket.
  2. Do not upload Website Assets
    • This bucket will not contain any assets. Its only purpose is to redirect to your root bucket.
  3. Enable Static Website Hosting
    • Access your bucket and go to the Properties tab in the bucket, scroll to the bottom, edit Static website hosting to select Enable, and ensure that Redirect requests for an object is selected.
    • For the Host name, enter the name of your non-www domain that you will redirect to (e.g., example.com)
    • For the Protocol select http and press Save Changes.
    • Take note of the Bucket website endpoint at the bottom of the Properties page (which you will use to test the website next).
Note: A Bucket Policy isn't required for this bucket.
Test the Redirect Bucket
  • At this point, if you navigate to the rucket website endpoint it should redirect you to your root domain (e.g., example.com) over an http connection. You should receive a 403 Error, which you'll address later when setting up CloudFront.

4. AWS Certificate Manager (ACM)

To secure your website, you’ll need to attach an SSL certificate. ACM simplifies the process of requesting and attaching certificates.

Create an SSL Certificate

  1. Navigate to the Certificate Manager service in the AWS Console and make sure your region is set to US-East-1, as this is required for global certificates.
  2. In Certificate Manager click Request, confirm that Request a public certificate is selected, and click Next.
  3. For the Fully qualified domain name (FQDN), enter the hosted zone domain name you created earlier in Route 53 (e.g., example.com)
  4. Click Add another name to this certificate and enter the www-prefixed version of your domain (e.g., www.example.com).
  5. Set the Validation method to DNS validation and choose RSA 2048 for the Key algorithm.
  6. Click Request to finalize the certificate request. This SSL certificate will be used in the next step for setting up the CloudFront distributions.
Note: It will take a few minutes for your certificate to validate and be issued.
  • If you purchased and registered your domain through AWS, validation will be automatic.
  • If you're using an external domain managed through AWS, add the CNAME records to your Hosted Zone in Route 53. You can do this manually by entering the CNAME names and values, or by opening the certificate and selecting Create Records in Route 53 under the Domains section.

5. CloudFront Distributions

To handle both www and non-www requests, you’ll need to create two separate CloudFront distributions: one pointing to the root S3 bucket and the other pointing to the redirect S3 bucket. Both distributions will use the SSL certificate created in the previous step.
Note: If you’d prefer your website to redirect to a 'www' prefix instead, simply reverse these roles.

Create the 'root' CloudFront Distribution

  1. Navigate to the CloudFront service in the AWS Console.
  2. Create a CloudFront distribution for the root bucket.
    • Click Create distribution and for the Origin domain select the root S3 bucket you created earlier (e.g., example.com.s3.amazonaws.com).
    • After selecting your S3 bucket, choose Use website endpoint.
    • Leave the rest of the settings in the Origin section as default.
  3. Configure Default Cache Behavior
    • Under Viewer protocol policy choose Redirect HTTP to HTTPS.
    • Under Cache key and origin requests ensure that CachingOptimized is selected.
    • Leave the rest of the settings as default.
  4. Set Web Application Firewall (WAF)
    • Set the WAF to Do not enable security protections.
  5. Configure Domain and SSL
    • In the final Settings section, set the Alternate Domain Name (CNAME) to the non-www domain you created earlier (e.g., example.com).
    • Select the SSL certificate you requested in the previous step and for the Security Policy choose TLSv1.2_2021.
    • Under Supported HTTP versions select both HTTP/2 and HTTP/3.
    • Leave the rest of the settings as default, and click Create distribution.
  6. In the General tab of the 'root' distribution, note the ARN and Domain name, as you'll need these in the next section.

Create the 'redirect' CloudFront Distribution

  1. Create another CloudFront distribution for the redirect bucket.
    • Click Create distribution and for the Origin domain select the redirect S3 bucket you created earlier (e.g., www.example.com.s3.amazonaws.com).
    • After selecting your S3 bucket, choose Use website endpoint.
    • Leave the rest of the settings in the Origin section as default.
  2. Configure Default Cache Behavior
    • Under Viewer protocol policy choose Redirect HTTP to HTTPS.
    • Under Cache key and origin requests ensure that CachingOptimized is selected.
    • Leave the rest of the settings as default.
  3. Set Web Application Firewall (WAF)
    • Set the WAF to Do not enable security protections.
  4. Configure Domain and SSL
    • In the final Settings section, set the Alternate Domain Name (CNAME) to the www-prefixed domain you created earlier (e.g., www.example.com).
    • Select the SSL certificate you requested in the previous step and for the Security Policy choose TLSv1.2_2021.
    • Under Supported HTTP versions choose both HTTP/2 and HTTP/3.
    • Leave the rest of the settings as default, and click Create distribution.
  5. In the General tab of the 'redirect' distribution, note the Domain name, as you'll need this in the next section.

6. S3 Bucket Policy

You need to update the bucket policy of your root S3 bucket to grant read access to the 'root' CloudFront distribution, allowing it to access and cache the website files.

Modify the Root Bucket Policy

  1. Navigate back to the S3 service in the AWS Console and ensure you're in the region you created your buckets in.
  2. Select the root bucket (e.g., example.com) and go to the Permissions tab.
  3. Click Edit to add the Bucket policy (below) in order to grant CloudFront permission to read the bucket’s contents.
  4. Replace BUCKET_NAME with your root bucket name (e.g., example.com) and ACCOUNT_NUMBER/DISTRIBUTION_ID with the values from the ARN of your 'root' CloudFront distribution.
Test CloudFront Distributions
  1. After updating the bucket policy, confirm that the CloudFront distributions have finished deploying. Once deployments are complete, test their functionality by accessing the CloudFront domain names from the previous steps.
  2. Your 'root' CloudFront distribution should load your HTTPS-secured webpage.
  3. Your 'redirect' CloudFront distribution should redirect to your HTTPS root domain (e.g., https://example.com).
Note: This redirection will not fully function until the A records are set in Route 53 in the next step. You just want to make sure it redirects correctly.

7. Route 53 Alias Records

The final step is to create 'A' Alias Records in Route 53, allowing your custom domain name to point to these distributions.

Create an Alias Record for the Root Domain (non-www)

  1. Navigate back to the Route 53 service in the AWS Console.
  2. From the left-hand menu, click on Hosted Zones, then select the Hosted Zone you created earlier (e.g. example.com).
  3. Click Create record to create a new record.
  4. Under Record name leave the subdomain blank.
  5. For the Record type select A - Routes traffic to an IPv4 address and some AWS resources.
  6. Choose Alias and under Route traffic to select:
    • Choose endpoint: Alias to CloudFront distribution.
    • Choose distribution: select the CloudFront distribution that serves your root domain (e.g., example.com (NON-WWW-CLOUDFRONT-DOMAIN.cloudfront.net)).
  7. Leave the default settings for other options, and click Create records.

Create an Alias Record for the www-prefixed Domain

  1. Click Create record to create another new record.
  2. Under Record name for the subdomain enter www.
  3. For the Record type select A - Routes traffic to an IPv4 address and some AWS resources.
  4. Choose Alias and under Route traffic to select:
    • Choose endpoint: Alias to CloudFront distribution.
    • Choose distribution: select the CloudFront distribution that serves your redirect domain (e.g., www.example.com (WWW-CLOUDFRONT-DOMAIN.cloudfront.net)).
  5. Leave the default settings for other options, and click Create records.
Test Website endpoints
Once both Alias records are created and propagated, test your domains (both www and non-www versions) to ensure traffic routes correctly to the CloudFront distributions. You should now be able to access your website using your custom domain name, with or without the www prefix.
Note: It will probably take 5-10 minutes for the changes to fully propagate, and your website endpoints to be accessible.
After confirming that your endpoints work, congratulations! You’ve successfully created a live portfolio website using your custom domain.
  • If you do not plan to update it often or prefer to update files manually in the root S3 bucket, you can stop here.
  • To set up a continuous integration/continuous deployment (CI/CD) pipeline that automates future code updates from a GitHub repository, continue to the next section of the tutorial.

8. AWS CodeBuild

To set up a continuous integration/continuous deployment (CI/CD) pipeline that automatically updates your website, you'll start with AWS CodeBuild. This project will handle compiling and testing your code as part of the update process.
Note: This section assumes your portfolio website files are stored in a personal GitHub repository. If they aren’t yet, take a moment now to create a new repository and commit your files to it.

Create a CodeBuild IAM Role

  1. Navigate to the IAM service in the AWS Console.
  2. Create a new Role for the CodeBuild service.
    • In the left navigation, choose Roles, then click Create role.
    • Select AWS service, under Use case select CodeBuild, and click Next.
    • Search for and select the following policy: CloudFrontFullAccess, then click Next.
    • Enter CodeBuildServiceRole as the name for the role, then press Create role.
Note: This role will allow CodeBuild to have access to CloudFront for the purpose of creating invalidations.

Create a CodeBuild Project

  1. Navigate to the CodeBuild service in the AWS Console and ensure you're in your preferred region.
  2. Click Create Project and for Project name enter Build-GitHubPortfolio.
  3. In the Source section:
    • Under Source provider select GitHub.
    • For Credential select Default Source Credential, then Manage default source credential.
    • For Credential Type, select GitHub App and create a new GitHub connection. Name the connection (e.g., GitHub-CI-CD-Connection).
    • Click Connect to GitHub to authorize. After authorization, choose Install a new app. Under Only select repositories, select your portfolio repository (or choose All repositories if you prefer full access to all your repositories).
    • Once the app is installed, click Connect.
    • Select your new GitHub-CI-CD-Connection under Connection and click Save.
    • Choose your repository from the dropdown.
  4. In the Primary source webhook events section:
    • Make sure Rebuild every time a code change is pushed to this repository is not selected.
      • You'll handle the rebuild trigger through CodePipeline.
  5. In the Environment section:
    • For Provisioning model, select On-demand.
    • For Environment image, choose Managed image.
    • For Compute, select EC2.
    • For Operating system, choose Amazon Linux.
    • For Runtime, select Standard.
    • For Image, choose aws/codebuild/amazonlinux2-x86_64-standard:5.0.
    • For Image version, set to Always use the latest image for this runtime version.
    • For Service role, select Existing service role and choose CodeBuildServiceRole, which you just created.
    • Make sure Allow AWS CodeBuild to modify this service role so it can be used with this build project is selected.
  6. In the Buildspec section:
    • Select Insert build commands, click Switch to editor, and enter the following build commands.
    • Replace YOUR_DISTRIBUTION_ID with the Distribution_ID from the ARN of your 'root' CloudFront distribution.
Note: This buildspec is tailored for building a Next.js project. You may need to adjust it slightly if using another framework, like Gatsby or Create React App.
7. Leave the rest of the options as default and click Create build project.
Test the CodeBuild project
  • Click the Start build button. If everything is configured correctly, you should see a green checkmark and a Succeeded message under the Status section after a few minutes.

9. AWS CodePipeline

Finally, you'll configure AWS CodePipeline to automate the full deployment process.

Create a Pipeline with CodePipeline

  1. Navigate to the CodePipeline service in the AWS Console and ensure you're in your preferred region.
  2. Click Create pipeline to start the setup process and select Build custom pipeline.
  3. Choose Pipeline settings:
    • For Pipeline name enter Pipeline-GitHubPortfolio.
    • For Execution mode select Queued (Pipeline type V2 required).
    • Ensure New service role is selected, keeping the default Role name.
    • Check the box for Allow AWS CodePipeline to create a service role so it can be used with this new pipeline, then click Next.
  4. Add Source stage:
    • For Source provider select GitHub (via GitHub App).
    • Select GitHub-CI-CD-Connection, which you created earlier, and select your portfolio repository.
    • Select main as your Default branch (or your actual default branch, if different).
    • For Output artifact format select CodePipeline default.
    • Check the box for Enable automatic retry on stage failure.
    • For the Trigger settings:
      • For Trigger Type select Specify filter.
      • For Event Type select Push.
      • For Filter Type select Branch.
      • For Branches under Include enter main (or your default branch).
    • Click Next.
  5. Add Build Stage:
    • Select Other build providers.
    • Choose AWS CodeBuild from the dropdown, then select Build-GitHubPortfolio, which you created earlier.
    • For Build type select Single build.
    • Ensure the Region is set to your pipeline region.
    • For Input artifacts, ensure SourceArtifact is selected.
    • Check the box for Enable automatic retry on stage failure, then click Next.
  6. Add Deploy Stage:
    • For Deploy provider select Amazon S3.
    • Ensure the Region is set to your pipeline region.
    • For Input artifacts, ensure BuildArtifact is selected.
    • For Bucket name select your root bucket (e.g., example.com).
    • Leave S3 object key blank.
    • Check the box for Extract file before deploy.
    • Ensure Configure automatic rollback on stage failure is checked, then click Next.
  7. Finalize the Pipeline
    • Review the configuration, then click Create pipeline.
    • Monitor the initial pipeline run to confirm each stage succeeds.
Great job! Your CI/CD pipeline is now set up and ready for deployment.

Conclusion

In this tutorial, you walked through setting up a complete, automated deployment pipeline for a personal portfolio website hosted on AWS. Starting with domain configuration in Route 53, you created a static website hosted in S3 and accelerated by CloudFront. You enabled SSL with AWS Certificate Manager to secure your site, then set up a CI/CD pipeline using CodeBuild and CodePipeline. This pipeline automatically triggers on changes to your GitHub repository, compiling and testing the code before deploying updates directly to your S3 bucket, with CloudFront invalidations ensuring the latest content is displayed immediately.
With this setup, you now have a fully automated and scalable system for deploying and managing your portfolio website. This approach not only saves time but also provides a professional, resilient online presence that can grow with you. Congratulations on setting up a robust and efficient deployment pipeline with AWS!
If you'd like to explore how to automate hosting your portfolio using Infrastructure as Code, check out my follow-up guide here.
 

Comments