Thuta Learning
AdvancedDevOpsintermediate

Provisioners (local-exec, remote-exec)

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Understand Provisioners (local-exec, remote-exec) without any of the intimidation
  • Get hands-on running terraform commands and HCL code yourself
  • Apply this concept in a real project right away

Let's think about it this way for a second

If you want to run a command after a resource is created (say, running a setup script right after a server is created), you can use `provisioner "local-exec"` (runs a command on the machine that's running Terraform) or `provisioner "remote-exec"` (connects via SSH/WinRM to the resource you just created and runs a command there). But Terraform doesn't track a provisioner's execution in its state — if a provisioner fails, you can end up with a resource that's created but only half set up. HashiCorp itself calls provisioners a 'last resort' and pushes you toward Ansible, cloud-init, or a dedicated configuration management tool instead.

Let's connect this to a real scenario

Writing `resource "aws_instance" "web" { ... provisioner "remote-exec" { inline = ["sudo apt update", "sudo apt install -y nginx"] } }` auto-runs an Nginx install script right after the server is created — but in production, it's better to split this kind of 'server setup' logic out into Ansible or cloud-init (a boot-time script), and let Terraform focus purely on creating infrastructure.

Let's look at it together

hcl
resource "aws_instance" "web" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.micro"

  provisioner "remote-exec" {
    inline = [
      "sudo apt update",
      "sudo apt install -y nginx",
    ]

    connection {
      type = "ssh"
      user = "ubuntu"
      host = self.public_ip
    }
  }

  provisioner "local-exec" {
    command = "echo ${self.public_ip} >> inventory.txt"
  }
}
You should see
$ terraform apply
aws_instance.web: Creating...
aws_instance.web: Provisioning with 'remote-exec'...
aws_instance.web (remote-exec): Connecting to remote host via SSH...
aws_instance.web: Creation complete after 45s

5-minute try-it

Add a `local-exec` provisioner (easy to practice since it doesn't need an SSH connection) to a `local_file` resource (from the Basic chapter) — confirm the command runs once the resource is created.

A quick word of caution

Don't reach for provisioners as your 'first' choice — consider cloud-init (like AWS's `user_data` argument) or a dedicated configuration management tool (Ansible) first.

Easy traps

  • Relying on provisioners in production without realizing that if a provisioner fails, Terraform marks the resource as 'tainted' and may destroy and recreate it on the next apply
  • Cramming all of a server's setup logic (software installs, config file writes) into provisioners instead of using Ansible/cloud-init — this makes the Terraform config messy

Now try it yourself

Add a `local-exec` provisioner (easy to practice since it doesn't need an SSH connection) to a `local_file` resource (from the Basic chapter) — confirm the command runs once the resource is created.

You'll know it worked when: $ terraform apply aws_instance.web: Creating... aws_instance.web: Provisioning with 'remote-exec'... aws_instance.web (remote-exec): Connecting to remote host via SSH... aws_instance.web: Creation complete after 45s

Provisioners (local-exec, remote-exec) | Thuta Learning