Skip to main content
This lesson covers remote provisioners in Terraform and how to use the remote-exec provisioner to run commands inside newly created virtual machines. Remote provisioners let Terraform connect to a VM over the network and execute commands inside the guest operating system — for Linux VMs Terraform typically uses SSH, and for Windows VMs it uses WinRM. This is distinct from configuring a VM through cloud-provider APIs; remote provisioners log into the machine and run commands directly.
The image is an infographic explaining remote provisioning (remote-exec) methods for virtual machines, showing Linux VMs using SSH and Windows VMs using WinRM.

Typical use cases

Remote provisioners are best for targeted, small-scale bootstrapping tasks that should run immediately after a VM is created:
  • Install software right after deployment (e.g., Nginx, Docker, or other runtime dependencies).
  • Run initialization or bootstrap scripts to prepare the system before apps are deployed.
  • Apply small configuration tweaks after infrastructure creation (e.g., enable a service, update a config file, restart a daemon).
Remote provisioners are useful for quick post-deployment steps when you do not want to introduce a full configuration-management system (Ansible, Chef, Puppet) for minor tasks. They are not designed to replace configuration management for long-term, complex configuration.
The image lists three use cases: installing software (with logos for NGINX and Docker), running initialization scripts (with PowerShell logos), and applying configuration tweaks post-deployment.

Requirements and constraints

Before using remote provisioners ensure the following:
The image displays a list of requirements for network access, including the need for a specific port for SSH, a correct username and private key, and a public IP or reachable hostname.
Prefer SSH key-based authentication for Linux VMs and avoid embedding plaintext secrets in your Terraform files. Use an absolute path or pass keys via variables (Terraform does not expand ~ in file() calls).

Example: remote-exec to install Apache (apache2)

This concise example shows a core Terraform configuration that creates a Linux VM on Azure and uses a remote-exec provisioner to update packages, install Apache, and write a simple index page. Notes on the example:
  • Add the provisioner "remote-exec" block inside the VM resource.
  • Use the connection block to tell Terraform how to reach the VM (SSH for Linux).
  • Prefer SSH key authentication. Never store production secrets inline.
main.tf (core resources and provisioner)
variables.tf
terraform.tfvars (example values)

Run and validate

Typical workflow commands: Example terminal sequence:

Troubleshooting: platform image errors

If you see an error such as:
This indicates the chosen publisher/offer/sku/version is not available in the selected region. Use the Azure CLI to list offers, SKUs, and images available in your target region and then update source_image_reference. Helpful Azure CLI commands (example using Canada Central and publisher Canonical):
You can filter JSON output with --query to find a non-deprecated version.

Example apply output (successful)

When the apply completes and the provisioner runs successfully, the Apache index page will be available at the VM public IP in a browser.
Avoid embedding plaintext passwords or secrets in your Terraform code. Prefer SSH keys or use a secrets manager. Also be cautious when exposing SSH or HTTP ports on public IP addresses.

Summary

Remote provisioners (especially remote-exec) let Terraform execute commands inside VMs after provisioning and are ideal for quick bootstrapping and minor post-deploy adjustments. Use them sparingly — they are not a substitute for full configuration-management tooling. Ensure proper network reachability, authentication, and secure handling of credentials so your provisioners can run reliably.

Watch Video