Skip to main content
Terraform provisioners enable you to execute commands or scripts either locally or on remote resources. They are especially useful for post-creation configuration tasks such as installing packages or starting services. In this guide, we’ll explore both the remote-exec and local-exec provisioners, their configurations, and best practices for use.

Remote-Exec Provisioner

The remote-exec provisioner allows you to run commands on a remote resource, such as a web server instance. For example, after creating a web server, you might want to update the package list, install NGINX, enable it at startup, and then start the service. The configuration below demonstrates how to use the remote-exec provisioner:
Ensure that network connectivity exists between the machine running Terraform and the remote instance. For Linux, this typically involves SSH, whereas Windows instances require WinRM connectivity.
In the example below, a security group and an SSH key pair resource are also created to manage connectivity and authentication:
To facilitate secure authentication, define a connection block inside your resource configuration. The connection block below enables SSH access by setting the host to the instance’s public IP, the user to “ubuntu,” and retrieves the private key from a local file:
When you run terraform apply, Terraform connects to the instance via SSH as specified in the connection block and executes the inline script. An example output is shown below:

Local-Exec Provisioner

The local-exec provisioner runs commands on the local machine where Terraform is executed. It’s useful for tasks like logging or writing data to a file. For example, to save the public IP address of an EC2 instance to /tmp/ips.txt, you can configure the local-exec provisioner as follows:
After running terraform apply, the instance’s public IP will be appended to the file on your local system. Provisioners run by default after resource creation (create-time provisioners), but you can also execute them before resource destruction. In the example below, one local-exec provisioner runs post-creation and another runs pre-destruction:
When you inspect the file (for example, by executing cat /tmp/instance_state.txt), you might see:

Handling Provisioner Failures

By default, if a provisioner command fails, Terraform will error out and mark any created resources as tainted. You can customize this behavior using the on_failure argument:
  • To force Terraform to fail on error, use:
  • Alternatively, if you want resource creation to succeed even when the provisioner command fails, set on_failure to "continue":

Best Practices

Terraform advises using provisioners only as a last resort. When possible, utilize the inherent features of your resource type to perform configuration actions. For example, rather than using remote-exec provisioner to install software on an AWS EC2 instance, consider using the user_data attribute to initiate scripts during instance launch. Here’s an improved approach using the user_data attribute to install and start NGINX on an EC2 instance:
With this configuration, the initialization script runs automatically during boot, reducing dependency on provisioners for post-creation configuration.

Summary

Terraform provisioners, both remote-exec and local-exec, offer flexible options for performing configuration tasks after resource creation or before destruction. However, for improved efficiency and reliability, consider native configuration options like user_data or metadata provided by cloud providers. Now, please head over to the multiple-choice quiz for this section.

Additional Resources

Watch Video