name: dh-infra type: on-demand trigger: - /dh:terraform - /dh:bootstrap description: Infrastructure-as-code operations with Terraform. Use when user wants to run terraform, manage infrastructure, bootstrap new hosts, change infrastructure, or says "terraform", "infrastructure", "IaC", "provision".
Dockhand Infrastructure
Manage infrastructure-as-code operations with Terraform for Hetzner Cloud resources. Enforces environment-based safety workflows.
Environment Safety Model
| Environment | Workflow | Direct Apply |
|---|---|---|
| prod | PR-first required | Blocked |
| test | Direct allowed | confirmed=true |
| global | PR-first required | Blocked |
Core Operations
Plan Changes
Preview infrastructure changes before applying:
terraform_plan environment="prod"
→ Shows diff of proposed changes
→ No state modification
→ Safe to run anytime
For all environments:
terraform_plan environment="global"
terraform_plan environment="prod"
terraform_plan environment="test"
Apply Changes
Test environment (direct allowed):
terraform_plan environment="test"
→ Review changes
terraform_apply environment="test" confirmed=true
→ Applied directly
Production/Global (PR workflow):
- Create feature branch
- Make Terraform changes
- Run
terraform_planto verify - Create PR with plan output
- Merge after review
- Apply from main branch (CI/CD or manual)
View Current State
Inspect current Terraform state:
terraform_show environment="prod"
→ Current resource inventory
→ Useful for debugging drift
Collect Platform State
Capture full platform state for documentation:
collect_state environment="prod"
→ Docker services, containers, volumes
→ Outputs to state-snapshots/
→ Commit to git for drift detection
Infrastructure Components
Global Resources (infra/terraform/global/)
- Hetzner Cloud network (
platform-net) - Subnets per environment
- Firewalls (SSH, HTTP, HTTPS, internal)
- Object storage buckets (backups, terraform state)
Per-Environment Resources (infra/terraform/envs//)
- Server instances (CPX31, CCX13, etc.)
- Volumes (data persistence)
- Floating IPs (if configured)
- Server-specific firewall attachments
Common Workflows
Add New Server
- Create Terraform config in
infra/terraform/envs/new-server/ - Define server, volume, network attachment
- Run
terraform_plan environment="new-server" - Create PR with plan
- After merge,
terraform_apply environment="new-server" confirmed=true - Bootstrap with
/dh:bootstrap
Resize Server
- Update
server_typein Terraform - Plan:
terraform_plan environment="<env>" - Warning: May require server restart
- Apply during maintenance window
Add Storage Volume
- Add
hcloud_volumeresource - Plan and review size/location
- Apply
- Mount on server via SSH
Bootstrap New Host
After Terraform provisions a server, bootstrap it:
/dh:bootstrap host=<new-host>
Bootstrap sequence:
- SSH connectivity test
- Install Docker
- Join Docker Swarm (manager or worker)
- Install Tailscale
- Configure monitoring agents
- Verify health
State Management
Terraform State
- Stored in Cloudflare R2 (S3-compatible)
- Backend configured per environment
- State locking via DynamoDB-compatible
Platform State Snapshots
- Generated by
collect_state - Stored in
state-snapshots/in git - Compare for drift detection:
diff state-snapshots/prod/latest.json state-snapshots/prod/previous.json
Integration with dh-guardrails
The dh-guardrails skill enforces:
- No
terraform destroywithout explicit confirmation - PR-first for production changes
- Backup verification before destructive operations
Error Handling
| Error | Resolution |
|---|---|
| State lock | Check for running applies, force unlock if stuck |
| Provider auth | Verify HCLOUD_TOKEN in environment |
| Resource conflict | Import existing resource or rename |
| Plan drift | Run plan, review changes, decide to apply or update config |