Last updated on 26th February 2026

Deploy Infrastructure with Terraform

This guide walks you through deploying infrastructure with Terraform using DeployHQ's Custom Action protocol. Custom Actions run CLI tools inside Docker containers during your deployment pipeline, making it straightforward to manage infrastructure as code directly from DeployHQ.

Prerequisites

Before you begin, ensure you have:

  • Beta Features Enabled: Custom Actions require beta features to be enabled in your account settings
  • A Terraform Project: A repository containing your Terraform configuration files (.tf files)
  • Cloud Provider Credentials: Access keys for your target provider (AWS, GCP, or Azure)
  • Remote State Backend (Recommended): An S3 bucket, GCS bucket, or Azure Storage Account configured for remote state

Setting Up the Server

  1. Open your project in DeployHQ and navigate to Servers.
  2. Click New Server and select Custom Action as the protocol.
  3. Under Image Source, select Curated Template.
  4. Choose Terraform from the template dropdown. This sets the Docker image to hashicorp/terraform:latest.
  5. Enter your Terraform commands in the Commands field:
   cd /data/infrastructure
   terraform init -input=false
   terraform plan -input=false -out=tfplan
   terraform apply -input=false tfplan
  1. Set Halt on error to stop the deployment if any command fails.
  2. Click Create Server.

Configuring Credentials

Terraform authenticates with cloud providers using environment variables. Add these to your server's environment variables in DeployHQ.

AWS

Variable Value
AWS_ACCESS_KEY_ID Your AWS access key
AWS_SECRET_ACCESS_KEY Your AWS secret key
AWS_DEFAULT_REGION Target region (e.g., us-east-1)

Google Cloud

Variable Value
GOOGLE_CREDENTIALS Service account JSON key (full contents)
GOOGLE_PROJECT Your GCP project ID

Azure

Variable Value
ARM_CLIENT_ID Service principal application ID
ARM_CLIENT_SECRET Service principal password
ARM_SUBSCRIPTION_ID Your Azure subscription ID
ARM_TENANT_ID Your Azure tenant ID

Example Commands

Basic Apply

The simplest setup runs init, plan, and apply in sequence:

cd /data/infrastructure
terraform init -input=false
terraform apply -input=false -auto-approve

Plan and Apply with Saved Plan

For safer deployments, save the plan to a file and apply it explicitly:

cd /data/infrastructure
terraform init -input=false
terraform plan -input=false -out=tfplan
terraform apply -input=false tfplan

Targeted Apply

Apply changes to specific resources only:

cd /data/infrastructure
terraform init -input=false
terraform apply -input=false -auto-approve -target=aws_ecs_service.app

Remote State Configuration

Running Terraform through DeployHQ means each deployment starts in a fresh container. You must use a remote state backend to persist your state file between runs.

Add a backend block to your Terraform configuration:

terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "deployhq/terraform.tfstate"
    region = "us-east-1"
  }
}

Other supported backends include GCS (gcs), Azure Storage (azurerm), and Terraform Cloud (remote).

Multi-Environment Usage

To deploy different environments (staging, production), you can use Terraform workspaces or variable files.

Using Variable Files

Store environment-specific variables in separate .tfvars files and reference them in your commands:

cd /data/infrastructure
terraform init -input=false
terraform apply -input=false -auto-approve -var-file=environments/production.tfvars

You can use DeployHQ text variables to make this dynamic:

cd /data/infrastructure
terraform init -input=false
terraform apply -input=false -auto-approve -var-file=environments/%server%.tfvars

Using Workspaces

Select a workspace before applying:

cd /data/infrastructure
terraform init -input=false
terraform workspace select production || terraform workspace new production
terraform apply -input=false -auto-approve

Troubleshooting

"Backend initialization required":

  • Ensure your remote state backend credentials are configured as environment variables on the server
  • Verify the backend bucket or storage account exists and is accessible

"Error acquiring the state lock":

  • A previous deployment may still hold the lock. Wait for it to complete, or use terraform force-unlock LOCK_ID if you are sure no other operation is running

"No changes. Infrastructure is up-to-date":

  • This is normal when your infrastructure matches your configuration. The deployment will still succeed.

Credential errors:

  • Double-check that environment variables are set correctly on the DeployHQ server
  • Ensure the credentials have sufficient permissions for the resources being managed
  • For AWS, verify the IAM user or role has the required policies attached

Timeout errors:

  • Custom Actions have a 30-minute timeout per command. Large infrastructure changes may exceed this limit.
  • Consider breaking large changes into smaller, targeted applies