Transferring a static website from DigitalOcean to AWS


I’ve been hosting a static site on DigitalOcean for some time. While it used to be free, I’ve now exhausted my resources and am currently billed $5 a month by DigitalOcean. Although this cost is minimal, Id really like to consolidate my side projects into one platform.

DigitalOcean offers an uncomplicated method to deploy React/static apps with auto GitHub deployment (which I highly recommend to anyone looking for a simple/easy solution) here. However, if you desire greater control and an even more cost-effective solution, AWS’s S3 and Cloudfront are great choices. AWS’s S3 bucket provides 5GB of free storage, and Cloudfront offers 1TB of free data transfer. This means we can reduce cost significantly for a small static website.

Create S3 bucket

Setting up an S3 bucket is straightforward:

  1. Navigate to AWS S3 and choose Create Bucket.
  2. Name the bucket: I recommend using a name similar to your domain, such as <MY-DOMAIN>.com.
  3. Choose or note the bucket’s region: For instance, my default is set to us-east-1.

For now, that’s all for the bucket setup. We’ll adjust permissions later based on Cloudfront’s requirements.

Ensure the following default settings are maintained:

  • ACL Disabled
  • Block All public access
  • Bucket versioning disabled
  • No Tags
  • Server-side encryption with Amazon S3 managed keys (SSE-S3) selected
  • Bucket Key enabled

Create Cloudfront Distribution

  1. Navigate to AWS Cloudfront and choose Create Distribution.
  2. When prompted for an Origin domain, select the S3 bucket you created.
  3. For Origin access, choose Origin access control settings (recommended).
  4. Create a control setting by clicking on the Create control setting button. You can leave the defaults or add a description if desired.
  5. Under Viewer protocol policy, I prefer to select “Redirect HTTP to HTTPS”.
  6. For Default root object - optional, specify your site’s root file. Typically, this is “index.html”, but it could differ based on your site’s structure.

Once the distribution is created at the top of the browser it will ask you to copy the policies for the S3 bucket. Select copy and go back into your S3 bucket.

In your S3 bucket go to the bucket Permissions.

Edit your Bucket policy

It should look something like this

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<BUCKET_NAME>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::<CLOUDFRONT_DISTRABUTION_ID>:distribution/<CLOUDFRONT_DISTRABUTION_ID>"
                }
            }
        }
    ]
}

Create IAM User

  1. Navigate to the IAM management console in AWS.
  2. Click on Create user.
  3. Skip the option Provide user access to the AWS Management Console - optional.
  4. On the Permissions options page, choose Attach policies directly. This will allow the user specific access permissions needed for deployment.
  5. Add AmazonS3FullAccess and CloudFrontFullAccess (this probably isn’t the most secure if you are worried about super tight security.
  6. Once the user is created you will want to create an access key. Go back into the user that was created and select the Security credentials tab select Create access key under the Access keys section. Select the use case I used Third-party service add a tag if desired. Download the csv or copy the actions to your clipboard. If you don’t download the csv or temporarily save these keys you will need to go through this process again

Create Github repo

If you’re reading this guide, I assume you’re familiar with creating GitHub repositories. If not, GitHub offers comprehensive documentation here.

Update Github action secrets

To secure your AWS credentials, use GitHub’s secrets management. Navigate to your GitHub repository’s settings, find the “Secrets” section, and add your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

Update Github actions

For deployment, create a GitHub action in your repo. I typically name it deploy.yml, but you can choose another name if you prefer.

name: Deploy to AWS

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Build React App
        run: |
          npm install
          npm run build

      - name: Deploy to S3
        uses: jakejarvis/s3-sync-action@master
        with:
          args: --follow-symlinks --delete
        env:
          AWS_S3_BUCKET: <BUCKET_NAME>
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: 'us-east-1' # change this to your AWS region
          SOURCE_DIR: 'build'

      - name: Invalidate CloudFront Distribution
        uses: chetan/invalidate-cloudfront-action@v1.3
        with:
          distribution: <CLOUDFRONT_DISTRABUTION_ID>
          paths: '/*'
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: 'us-east-1' # change this to your preferred AWS region
          DISTRIBUTION: <CLOUDFRONT_DISTRABUTION_ID>
          PATHS: '/*'

Now that all the fun stuff is over we can add a domian name

Update URL with Namecheap(This might be different if you use a different domain provider)

To ensure users can access your static website via your custom domain name (e.g., www.example.com), you’ll need to configure your domain in Namecheap to point to the AWS Cloudfront distribution. Here’s how you can achieve this:

  1. Get Your Cloudfront Domain Name: After creating your Cloudfront distribution, AWS provides a domain name for that distribution. It usually looks something like d12345abcdexample.cloudfront.net.
  2. Login to Namecheap:
    • Visit the Namecheap website and sign in to your account.
    • From the dashboard, navigate to Domain List on the left sidebar.
    • Click on the Manage button next to the domain you want to update.
  3. Update DNS Records:
    • In the domain management page, go to the Advanced DNS tab.
    • Here, you’ll likely see existing DNS records. You’ll need to add a new CNAME record.
      • For the Host field, if you want to use www (as in www.example.com), enter www.
      • For the Value field, enter the Cloudfront distribution domain name, e.g., d12345abcdexample.cloudfront.net.
      • Ensure the TTL (Time to Live) is set to Automatic.
    • If you want to redirect the root domain (e.g., example.com) to your Cloudfront distribution, you can add another CNAME record:
      • For the Host field, enter @.
      • For the Value field, again input your Cloudfront domain name.
  4. SSL/TLS Configuration: Ensure that your Cloudfront distribution is set up to handle HTTPS requests, and that you have an SSL certificate (either from AWS Certificate Manager or another provider) associated with it.
  5. Propagation: After updating your DNS settings, it may take anywhere from a few minutes to 48 hours for the changes to propagate across the internet. During this period, some users might still see the old site, or the site might be inaccessible for a short while.