Introduction

In this post, I’ll walk you through deploying a Hugo static site to AWS S3 with a custom domain and SSL certificate using Terraform. We’ll create a complete infrastructure-as-code solution that’s reusable and production-ready.

What We’re Building

  • Hugo static site hosted on AWS S3
  • Custom domain with SSL certificate
  • CloudFront CDN for global distribution
  • Route53 for DNS management
  • Terraform module for reusable infrastructure

Prerequisites

  • AWS CLI configured
  • Terraform installed
  • Hugo installed
  • A domain name you own

Step 1: Setting Up Hugo

First, create a new Hugo site:

hugo new site quickstart
cd quickstart
git init
git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke themes/ananke
echo "theme = 'ananke'" >> hugo.toml

Step 2: Creating the Terraform Infrastructure

Using the Terraform Module

Create a terraform/main.tf file to use the module:

provider "aws" {
  region = "eu-central-1"
}

provider "aws" {
  alias  = "us_east_1"
  region = "us-east-1"
}

module "hugo_website" {
  source = "github.com/username/terraform-hugo-s3-module"
  
  domain_name = "example.com"
  aws_region  = "eu-central-1"
  
  providers = {
    aws.us_east_1 = aws.us_east_1
  }
}

Key Components

  1. S3 Bucket: Configured for static website hosting
  2. Route53: DNS management and certificate validation
  3. ACM Certificate: SSL/TLS encryption
  4. CloudFront: Global CDN for fast content delivery

Step 3: Making It Modular

To make the infrastructure reusable, I created a Terraform module:

terraform-hugo-s3-module/
├── main.tf              # Core resources
├── variables.tf         # Input variables
├── outputs.tf          # Output values
├── examples/basic/     # Usage example
└── tests/              # Module tests

Module Usage

module "hugo_website" {
  source = "github.com/username/terraform-hugo-s3-module"
  
  domain_name = "example.com"
  aws_region  = "eu-central-1"
  
  providers = {
    aws.us_east_1 = aws.us_east_1
  }
}

Step 4: Deployment Process

1. Deploy Infrastructure

cd terraform
terraform init
terraform plan
terraform apply

2. Update DNS

Since the domain wasn’t previously in Route53, Terraform creates a new hosted zone. Check the nameservers in the AWS Console (Route53 > Hosted Zones) or via Terraform output:

terraform output nameservers

Update your domain registrar with these Route53 nameservers and wait for DNS propagation (24-48 hours).

3. Configure Hugo Deploy

Add deployment configuration to hugo.toml:

[[deployment.targets]]
name = "aws"
URL = "s3://example.com?region=eu-central-1"

4. Deploy Hugo Site

hugo deploy

Step 5: Challenges and Solutions

Certificate Validation

The ACM certificate initially showed “pending validation.” This was resolved by:

  1. Ensuring the domain uses Route53 nameservers
  2. Waiting for DNS propagation (24-48 hours)
  3. Terraform automatically creates validation DNS records

Regional Considerations

  • S3 bucket: Can be in any region (eu-central-1)
  • ACM certificate: Must be in us-east-1 for CloudFront
  • CloudFront: Global service

Benefits of This Approach

  1. Infrastructure as Code: Version-controlled, repeatable deployments
  2. Scalable: CloudFront provides global CDN
  3. Secure: Automatic SSL certificate management
  4. Cost-effective: S3 static hosting is very affordable
  5. Reusable: Terraform module can deploy multiple sites

Module Features

The final Terraform module includes:

  • ✅ S3 static website hosting
  • ✅ Route53 DNS management
  • ✅ ACM SSL certificate with auto-validation
  • ✅ CloudFront CDN distribution
  • ✅ Optional www redirect
  • ✅ Configurable tags and regions
  • ✅ Comprehensive tests

Conclusion

This setup provides a robust, scalable solution for hosting Hugo sites on AWS. The Terraform module makes it easy to deploy multiple sites with consistent infrastructure.

The combination of Hugo’s fast static site generation and AWS’s reliable infrastructure creates an excellent foundation for modern websites.

Next Steps

  • Set up automated deployments with GitHub Actions
  • Add CloudFront cache invalidation
  • Implement blue-green deployments
  • Add monitoring and alerting

The complete Terraform module and example code are available in the project repository.