Articles

Why I use Terraform for SaaS infrastructure

I do not want my production server setup to be a checklist in my head.

If I need a server, firewall, SSH user, private network, and hardening rules, I want those decisions written down in code. Terraform is the cleanest way I have found to do that for a small SaaS.

HashiCorp describes Terraform as infrastructure as code for building, changing, and versioning infrastructure. The versioning is the part I care about.

The problem with ClickOps

Clicking around a cloud dashboard is fine once.

The second time, you forget something:

  • a firewall rule
  • an SSH key
  • a server location
  • a server network setting
  • a hardening step
  • a backup note

The third time, your production environment and your notes disagree.

For a solo SaaS, this is where Terraform is useful. I am not trying to build a giant platform team workflow. I just want the server setup to be repeatable.

What Terraform gives me

Terraform lets me define the infrastructure in plain files:

main.tf
variables.tf
providers.tf
outputs.tf

The provider talks to Hetzner Cloud. The configuration says what should exist. terraform plan shows the proposed changes before anything happens. terraform apply makes those changes.

That flow is exactly what I want an AI coding agent to use too. The agent can inspect the files and tell me what will change before touching production infrastructure.

How Stacknaut uses Terraform

Stacknaut ships Terraform as a separate repo because infrastructure has a different lifecycle from app code.

The Terraform repo provisions:

  • a Hetzner Cloud server
  • a cloud firewall
  • a private network
  • Ubuntu setup through cloud-init
  • SSH hardening
  • Docker installation
  • fail2ban
  • unattended security updates
  • swap
  • Docker cleanup

Then Kamal takes over deployment.

That split matters. Terraform creates the server. Kamal deploys the app. I do not want Terraform managing app releases, and I do not want my deploy tool creating the base server from scratch.

Why Hetzner fits this

Hetzner is simple enough that Terraform stays readable.

For most early SaaS products, one server is enough. You can run the frontend, backend, API, Postgres, and logging collector on the same machine while you are finding product-market fit.

That keeps the infrastructure small:

  • one server
  • one firewall
  • one deploy target
  • one backup story

No Kubernetes, no multi-account cloud setup, and no pile of managed services before the product has revenue.

The agent benefit

AI agents are better when the system is inspectable.

Terraform gives the agent real files to read:

  • what server type is used
  • what ports are open
  • what SSH user exists
  • what cloud-init does
  • what output should be copied into Kamal

Without that, the agent has to ask what you clicked in a dashboard six months ago. Who knows.

With Terraform, the answer is in the repo.

What I would not use Terraform for

I would not add Terraform just to provision one throwaway demo.

If the app is a weekend prototype, click a button somewhere and move on. But once I care about the app enough to charge money, I want infrastructure that can be rebuilt.

Stacknaut starts on the rebuilt side of that line. The Terraform repo gives you the server foundation, and the app repo gives you the Kamal deploy path on top of it.

See the actual included setup in Stacknaut's Terraform infrastructure docs.

Deploy without platform sprawl

Use the same Kamal + Hetzner setup I ship with.

Stacknaut includes the app, deployment config, and Terraform repo so your agent works against a complete production path.

What you get in Stacknaut

  • Kamal deploy.yml, Dockerfiles, Caddy config, and smart deploy scripts
  • Terraform for a hardened Hetzner server with firewall and fail2ban
  • Postgres and log collection wired as production accessories

2e75a5fa