Intro — summary
Building a website used to mean clicking through a registrar, a DNS console, a CDN dashboard, and an admin center, hoping every setting matched the last time someone did it. Infrastructure as Code (IaC) replaces that hope with a record: the website's infrastructure is written down as code, reviewed like any other change, tested before it touches production, and applied by a machine that does exactly what the code says. This post explains why we build that way — more secure, more manageable, faster — using the stonewardsystems.com build as the example, honestly including the parts that are still manual.
Summary of the content below: (1) what IaC changes about building a site, (2) how the Stoneward build actually went, step by step, (3) what is still manual and why that honesty matters, (4) what comes next.
The details
What IaC changes
Three properties do most of the work. First, review: a change to DNS, CDN, or hosting goes through the same pull-request review as a change to the website itself, so a second pair of eyes sees it before it goes live. Second, repeatability: the same code that built the test site builds the production site, so “it worked on test” actually means something. Third, audit: every applied change leaves a trail — which run, which commit, which DNS change ID, which pull-zone ID — so any question about “what changed, and when?” has an answer that is not somebody's memory.
Security follows from those three. Fewer humans with standing access to production consoles, fewer one-off clicks that nobody recorded, and permissions that are narrow by construction: the automation that deploys a site cannot also administer the organization, because it was never given that permission.
Manageability follows too. When a second domain needs the same shape — registration, DNS, CDN, mail — the factory pattern reuses the same code instead of re-learning the manual path. And when something breaks, the code is the documentation: it says what the site is supposed to be, which makes “what is it now, and what should it be?” a comparison instead of an investigation.
Speed is the consequence, not the goal. The first domain through a new factory is slower than clicking through consoles, because the factory itself has to be built. Every domain after it is faster, because the pattern already exists.
How the Stoneward build actually went
The build followed one rule throughout: test first, then production, and never production without a test that passed. A GitHub organization and a website repository were set up with separate test and production branches. The domain's DNS zone was created with its records, the CDN pull zones and storage were created for test and production, certificates were issued, and a deploy workflow published the test site, verified it live, and only then promoted the same content to production. The live site serves over HTTPS on both its test and production addresses.
Every step landed in an audit trail with its run IDs, commit hashes, DNS change IDs, and zone IDs, and the plan itself was kept current as the work landed — including a mid-build correction to the plan's own rule about blocked work (see below).
What is still manual, and why that honesty matters
Not everything can be code, and claiming otherwise would be the most dangerous sentence in this post. Some steps are manual by nature: creating an organization, installing an application, the OAuth handshake that connects a cloud account, creating an API token, and registrar and admin-center work that has no API equivalent. Those steps were done by a human, logged as manual, and paired with the code equivalent they will converge to — so the next domain does more in code and less by hand, instead of re-learning the manual path each time.
The same honesty applies to blocked work. Mid-build, the plan's rule was corrected: a package stalled on someone else becomes a tracked open thread with an owner and a next action, and work moves on to the next unblocked thing. A wait or a failure is recorded as an open item, not a stoppage. Only a step's own downstream steps wait on it. That rule is part of why the site went live on schedule despite open email items: the email package waits on its owner, and nothing else waited with it.
What comes next
The factory's next step is turning its remaining manual Microsoft 365 work — domain verification, mailing-list creation, DKIM enablement — into API-driven steps, so future domains repeat those in code too. The pattern stays the same: design first, build the module, validate it locally, test it on the test path, and only then apply it to production with a human approval at the consent step. The blog post you are reading went through that same path: draft, test site, approval, production.
References
- Stoneward Systems website: https://stonewardsystems.com/
- Stoneward Systems test site: https://test.stonewardsystems.com/
- Terraform documentation: https://www.terraform.io/
- Bunny CDN documentation: https://bunny.net/



