ThisCalculator

Everyday

How to Build a Blog with Terraform and AWS

Updated · Standard formula, shown below

How to Build a Blog with Terraform and AWS

This guide walks you through deploying a serverless blog on AWS using Terraform. You’ll define your infrastructure as code, provision an S3 bucket for static content, CloudFront for content delivery, and a Lambda function for dynamic processing (like contact forms or API calls). By the end, you’ll have a fully automated, scalable blog that costs pennies to run.

What You’ll Need

  • An AWS account with administrative access (for creating IAM roles and resources).
  • Terraform installed on your local machine (version 1.5 or later).
  • AWS CLI installed and configured with credentials (run aws configure).
  • Basic familiarity with HTML/CSS for your blog content.
  • A text editor (VS Code, Sublime, etc.).

Step-by-Step

  1. Create a project directory and navigate into it. This will hold all your Terraform configuration files.
  2. Define your provider. Create a file named main.tf and add the AWS provider block, specifying your preferred region (e.g., us-east-1).
  3. Set up S3 for static content. Add an S3 bucket resource in main.tf with a globally unique name (e.g., my-blog-bucket-2025). Configure it for static website hosting with an index document of index.html and an error document of 404.html.
  4. Add a CloudFront distribution. Create a CloudFront distribution resource that points to your S3 bucket as the origin. Set the default root object to index.html. This gives you HTTPS and global edge caching.
  5. Create a Lambda function for dynamic features. Write a simple Lambda function (e.g., in Python or Node.js) that handles a contact form submission and stores messages in a DynamoDB table. Package your code into a ZIP file and reference it in the Terraform configuration.
  6. Set up IAM roles. Define an IAM role for Lambda with permissions to write to DynamoDB and log to CloudWatch. Attach the appropriate policies.
  7. Add an API Gateway endpoint. If your Lambda function needs to be publicly accessible (e.g., for form submissions), create an API Gateway REST API with a POST method that triggers your Lambda.
  8. Configure outputs. In outputs.tf, print the CloudFront domain name and the S3 bucket website endpoint so you know where your blog is live.
  9. Initialize and apply. Run terraform init to download providers, then terraform plan to review changes, and finally terraform apply to create the resources. Type yes when prompted.
  10. Deploy your blog content. Upload your HTML, CSS, and JS files to the S3 bucket using aws s3 sync ./public s3://your-bucket-name. Wait a few minutes for CloudFront to propagate, then visit your CloudFront URL.

Common Mistakes

  • Using a non-unique S3 bucket name — S3 bucket names are global, so you’ll get an error if the name is taken.
  • Forgetting to set the origin access control — Your S3 bucket should be private, and CloudFront should access it via an Origin Access Control (OAC) to avoid public access.
  • Not configuring the default root object — Without it, visiting the root URL returns an access denied error.
  • Hardcoding AWS credentials in Terraform — Use environment variables or IAM roles instead.
  • Ignoring the Lambda execution role — If the role lacks DynamoDB permissions, the function will fail silently.

Tips

  • Use Terraform modules — Break your configuration into reusable modules for S3, CloudFront, and Lambda to keep it organized.
  • Version your state file — Store Terraform state in an S3 bucket with DynamoDB locking to enable team collaboration and prevent corruption.
  • Automate content deployment — Use a CI/CD pipeline (like GitHub Actions) to run terraform apply and aws s3 sync on every push.
  • Enable CloudFront logging — This helps you debug traffic issues and understand your audience.
  • Set up cost alerts — Even though the blog is cheap, it’s good practice to monitor usage.

Troubleshooting

  • Access denied when visiting the CloudFront URL — Check that the S3 bucket policy allows CloudFront to read objects. Ensure the OAC is correctly attached.
  • Changes not appearing after updating S3 — CloudFront caches content; invalidate the cache by running aws cloudfront create-invalidation --distribution-id YOUR_ID --paths "/*".
  • Terraform apply fails with “BucketAlreadyExists” — Change the bucket name to something unique.
  • Lambda function times out — Increase the timeout in your Terraform configuration (e.g., to 10 seconds). Also check your function’s memory allocation.
  • API Gateway returns 500 — Look at CloudWatch logs for the Lambda function to see the error stack trace.

Frequently Asked Questions

  1. Can I use a custom domain with this setup? Yes, create a Route 53 hosted zone and add an A record that points to your CloudFront distribution. Use an ACM certificate for HTTPS.
  2. How much does this cost? Typically under $1 per month for low traffic. S3 and CloudFront have free tiers, and Lambda charges only when invoked.
  3. Can I use a database like MySQL instead of DynamoDB? Yes, but you’d need to run RDS, which costs more. DynamoDB is serverless and integrates well with Lambda.
  4. How do I update my blog content? Simply overwrite the files in S3, then invalidate the CloudFront cache. This can be automated with a script or CI/CD.
  5. Is this setup secure? Yes, as long as you keep the S3 bucket private and use Origin Access Control. Also, use HTTPS via CloudFront’s default certificate or your own ACM certificate.
  6. Can I use a static site generator like Hugo or Jekyll? Absolutely. Build your site locally, then upload the generated HTML files to S3.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.