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 (
.tffiles) - 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
- Open your project in DeployHQ and navigate to Servers.
- Click New Server and select Custom Action as the protocol.
- Under Image Source, select Curated Template.
- Choose Terraform from the template dropdown. This sets the Docker image to
hashicorp/terraform:latest. - 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
- Set Halt on error to stop the deployment if any command fails.
- 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_IDif 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