How We Set Up This Blog in 20 Minutes

Join the conversation — view and comment on this post on LinkedIn.

Last week we published a LinkedIn post about how we built our own background coding agents. Someone in the comments asked for more technical details.

LinkedIn comment asking for more details on how we built it

I actually had them. The original draft had much more detailed information about the architecture. But after discussing it with the team, we decided to trim it down for LinkedIn. The technical stuff was interesting, but it didn’t belong there.

That left me with a pile of good content and nowhere to put it. We needed an engineering blog.

From zero to blog in five minutes

I opened Claude Code and asked it to find the best Ruby gem for building a static blog. It suggested Bridgetown: a modern, actively maintained static site generator built on Ruby. A quick check on GitHub confirmed it was solid: good documentation, regular releases, responsive maintainers.

I told Claude to set it up. Five minutes later I had a working blog with my full post loaded in, super easy.

Deploying to AWS

We run most of our infrastructure on AWS, so the choice was obvious. For a static blog, you don’t need much: an S3 bucket to hold the files and CloudFront in front of it for caching and HTTPS. It’s simple, performant, and costs almost nothing to run.

We manage all our infrastructure with the AWS CDK, and the blog was no different. The entire setup is about 60 lines of TypeScript split across two stacks.

The first stack creates an ACM certificate with DNS validation. It has to live in us-east-1 because that’s what CloudFront requires:

this.certificate = new acm.Certificate(this, "Certificate", {
  domainName: props.domainName,
  validation: acm.CertificateValidation.fromDns(),
});

The second stack is the actual blog infrastructure: a private S3 bucket and a CloudFront distribution using Origin Access Control:

const bucket = new s3.Bucket(this, "Bucket", {
  blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
});

const distribution = new cloudfront.Distribution(this, "Distribution", {
  defaultBehavior: {
    origin: origins.S3BucketOrigin.withOriginAccessControl(bucket),
    viewerProtocolPolicy:
      cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
    cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
    responseHeadersPolicy:
      cloudfront.ResponseHeadersPolicy.SECURITY_HEADERS,
    functionAssociations: [
      {
        function: rewriteFunction,
        eventType: cloudfront.FunctionEventType.VIEWER_REQUEST,
      },
    ],
  },
  domainNames: [props.domainName],
  certificate: props.certificate,
});


new CfnOutput(this, "BucketName", { value: bucket.bucketName });
new CfnOutput(this, "DistributionDomainName", {
  value: distribution.distributionDomainName,
});
new CfnOutput(this, "DistributionId", {
  value: distribution.distributionId,
});

There’s also a small CloudFront Function that rewrites URLs so clean paths like /2026/02/23/my-post resolve to the right index.html. The CDK wires up all the IAM permissions and Origin Access Control policies automatically.

The stack outputs the S3 bucket name, the CloudFront distribution ID (both needed by the deploy script), and the CloudFront domain name — something like <id>.cloudfront.net. The last step is pointing your subdomain at it: a CNAME record mapping blog.example.com to the CloudFront domain. Once DNS propagates, you’re live.

The deploy script is a single command that builds the site, syncs to S3, and invalidates the CloudFront cache.

Matching the brand

This was the part that impressed me the most. I wanted the blog to look like our main website, not like a generic template. So I pointed Claude at the site and asked it to replicate the branding.

It pulled the right color schemes, matched the fonts (DM Sans for body text, DM Mono for code), and styled the layout to feel like part of the same product, all without me having to specify any of those details. I didn’t need to provide a style guide or hex codes, Claude just looked at the site and figured it out, using its Chrome integration.

The whole thing only took a few minutes.

Why this matters

Setting up a polished, branded engineering blog used to be a multi-hour side project. Pick a framework, figure out how it works, fiddle with CSS until the colors match, configure deployment. It’s the kind of task that lives on your to-do list for months because it’s never urgent enough to prioritize.

With Claude Code, it was 20 minutes.

If you’re sitting on technical content that doesn’t have a home yet, just start. The setup cost is basically zero now.

Slack message from a teammate: wow we have an engineering blog now?!