A Jamstack is a modern architecture for building websites; JAM stands for JavaScript, APIs, and Markup. Jamstacks are deployed on a CDN, and content is stored on a cloud services provider. In addition to the speed and simplicity of deploying static content served from a CDN, there are other advantages such as maintaining content with git, modern build tools to generate the static content, automated builds, atomic deploys, and instant cache validation.
While build tools have simplified the process of creating content ready for deployment on a CDN, creating the infrastructure to serve the content remains complicated. You can use a cloud provider’s web interface or script the build using a CLI tool if you want to manage your infrastructure instead of using a hosted solution. The alternative is to use infrastructure as code tool to automate building and deploying cloud resources. This article demonstrates how to create a jamstack website and deploy it on AWS using Pulumi.
Creating Your Website with Hugo
There are many static site generators, but we’ll use Hugo to build the site for this example. We’ll use Docker to run Hugo in a container. If you have Docker installed, create a directory to hold the website and change into that directory.
$ mkdir hugo
$ cd hugo
$ docker run --rm -it -v $(pwd):/src klakegg/hugo:0.72.0-alpine shell
The docker run command will fetch the container (klakegg/hugo:0.72.0-alpine), map the current directory to the src directory in the container, and open a shell.
In the container command line, we will use hugo to create a new site called platypus.
Next, we’ll customize the site with a theme. There are many themes available, but for this example, we’ll use the ananke theme. Download the theme to the container, unzip it, and rename the unzipped directory to ananke.
$ wget https://github.com/budparr/gohugo-theme-ananke/archive/master.zip
$ unzip master.zip
$ cp -rf gohugo-theme-ananke-master ./themes/ananke
$ rm -rf master.zip gohugo-theme-ananke-master/
Configure the site by editing the config.toml file with the following.
baseURL = "http://www.<your_domain>.com/"
languageCode = "en-us"
title = "Platypus"
theme = "ananke"
Use hugo to create a new markdown page in the posts directory.
Now it’s time to add content to your site. You can use your favorite editor to write and edit content in your working directory on your machine instead of using the container shell. Edit the markdown file, below is an example page but feel free to add your content.
Finally, we can build the static site with Hugo in the container command line.
Hugo will create a public directory with the static website.
Building the Cloud Infrastructure
Configuring a static website can be complicated when using either the AWS web interfaces or the AWS CLI. To deploy a static website, we need to create and configure the following cloud resources.
- Amazon S3 to store the website’s contents
- Amazon CloudFront for the CDN serving content
- Amazon Route53 to set up the DNS for the website
- Amazon Certificate Manager for securing the site via HTTPS
Using Pulumi to deploy Infrastructure as Code, we can create and build our infrastructure using either TypeScript or Python. If you haven’t installed Pulumi and configured it to work with your AWS credentials, follow the Getting Started with AWS guide.
To get started building our infrastructure, we’ll download the Python example for setting up a static website with AWS. There are many examples on our GitHub repository, but we can clone just the AWS Static Website example using a sparse checkout which clones only the directory we specify,
Your project directory should look like this:
Configuring and Deploying the Website
Now that we have a project to build the website, we will need to configure it so that it uses your domain name. Here are the steps to get it running.
Set the AWS region, you can use any region:
Edit
Pulumi.website-testing.yamlto set the configuration parameters. The first parameter is thetargetDomain, which is the domain for the website (e.g., www.example.com). The parent domain must be a Route53 Hosted Zone in the same AWS account as where the Pulumi program is running. The second parameter ispathToWebsiteContents, the relative path to the website’s contents created in Hugo.config:aws:region: us-east-1static-website:targetDomain: www.<your_domain>.comstatic-website:pathToWebsiteContents: ../publicRun
pulumi upto preview and deploy changes. After the preview is displayed, you will be prompted if you want to continue and deploy the website. When all the resources have been created, you will see a listing of the resources similar to this:
The website has been deployed, and you can browse it with your domain URL. Since this is a test deployment, don’t forget to shut down and delete the cloud resources by running pulumi destroy.
Examine the Code
Let’s take a look at how the cloud resources are created, configured, and populated. First up is the S3 bucket where the static website is stored.
We add the website content by crawling the public directory and converting the files to S3 objects.
Now that we have our content in an S3 bucket, we turn to configure and create the CDN that serves the website. The first task is to create an SSL/TLS certificate based on the domain name hosted on Route 53 DNS if we didn’t specify the optional certificateArn config value of an existing certificate.
We also create a bucket to hold the CDN logs for the website.
Now that we have an SSL/TLS certificate and a S3 bucket to store logs, we can create the CDN. In the CDN resource definition, origin sets the S3 bucket as the content source, the domain name, and the ports for serving content. We can also set the cache_behavior, the price class, access restrictions, the logging configuration, and other parameters.
To complete the deployment, we set the alias_a_record to point the CDN to our domain name in Route 53.
In a single program, we’ve created all the cloud resources to deploy our content and served it via a CDN.
Conclusion
Building modern websites is evolving from provider-managed Content Management Systems or user-managed LAMP stacks. Static websites deployed in the cloud are popular because they separate content generation from the infrastructure that serves content. However, building and maintaining cloud infrastructure can be complicated and require multiple steps when using web client for configuration. A website using inexpensive storage such as S3 and serving content via Cloudfront can be deployed, versioned, and maintained using your favorite programming language. The Pulumi examples repository has many more code samples that demonstrate how to build and deploy cloud infrastructure across different cloud providers, using your favorite programming language.
Learn how to automate your cloud infrastructure with Pulumi’s Getting Started tutorials and User Guides, or join us on Slack if you have questions.