docker.recipes

Terraform Enterprise Self-Hosted

advanced

Infrastructure as Code platform with workspaces, VCS integration, and state management.

Overview

Terraform Enterprise is HashiCorp's commercial platform for Infrastructure as Code at scale, providing teams with collaborative Terraform workflows, policy enforcement, and centralized state management. This self-hosted deployment combines Terraform Enterprise with PostgreSQL for workspace and run data, Redis for session and cache management, MinIO for S3-compatible object storage of state files and plan outputs, and Vault for secure secrets management across infrastructure deployments. The stack creates a complete GitOps-enabled infrastructure platform where teams can collaborate on Terraform configurations through VCS integration, enforce policies with Sentinel, and maintain audit trails of all infrastructure changes. Organizations choose this self-hosted approach to maintain complete control over their infrastructure automation platform, ensure sensitive state files never leave their network perimeter, and integrate with existing enterprise authentication systems while avoiding the recurring costs of HashiCorp's cloud offering.

Key Features

  • PostgreSQL backend stores Terraform workspaces, run histories, and configuration metadata with ACID compliance
  • Redis provides fast session management for concurrent Terraform operations and workspace locking
  • MinIO S3-compatible storage handles Terraform state files, plan outputs, and configuration archives
  • Vault integration enables dynamic credential injection for cloud providers during Terraform runs
  • Atlantis workflow automation triggers Terraform plans and applies from GitHub pull requests
  • Prometheus metrics collection tracks workspace usage, run success rates, and resource provisioning
  • Grafana dashboards visualize infrastructure deployment patterns and team productivity metrics
  • Isolated network architecture ensures secure communication between Terraform Enterprise and supporting services

Common Use Cases

  • 1Enterprise teams managing multi-cloud infrastructure with consistent Terraform workflows and approval gates
  • 2Organizations requiring on-premises Infrastructure as Code platform due to compliance or data sovereignty requirements
  • 3DevOps teams implementing GitOps workflows where infrastructure changes flow through version control and peer review
  • 4Companies consolidating Terraform state management from scattered S3 buckets into centralized workspace-based storage
  • 5Engineering organizations enforcing infrastructure policies and cost controls through Sentinel integration
  • 6Teams needing audit trails and approval workflows for infrastructure changes in regulated industries
  • 7Multi-tenant environments where different teams require isolated Terraform workspaces with shared backend services

Prerequisites

  • Minimum 8GB RAM and 4 CPU cores for production Terraform Enterprise workloads with concurrent runs
  • GitHub or GitLab repository with admin access for configuring webhooks and access tokens
  • Valid Terraform Enterprise license from HashiCorp (commercial product requiring purchase)
  • Docker and Docker Compose 3.8+ with sufficient disk space for state files and Terraform providers
  • Network access to cloud provider APIs (AWS, Azure, GCP) from Terraform Enterprise container
  • Understanding of Terraform workflows, state management, and Infrastructure as Code principles

For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms

docker-compose.yml

docker-compose.yml
1services:
2 postgres:
3 image: postgres:15-alpine
4 environment:
5 - POSTGRES_USER=terraform
6 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
7 - POSTGRES_DB=terraform
8 volumes:
9 - postgres_data:/var/lib/postgresql/data
10 networks:
11 - tfe_net
12
13 redis:
14 image: redis:7-alpine
15 volumes:
16 - redis_data:/data
17 networks:
18 - tfe_net
19
20 minio:
21 image: minio/minio:latest
22 command: server /data --console-address ":9001"
23 ports:
24 - "9000:9000"
25 - "9001:9001"
26 environment:
27 - MINIO_ROOT_USER=${MINIO_USER}
28 - MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
29 volumes:
30 - minio_data:/data
31 networks:
32 - tfe_net
33
34 vault:
35 image: hashicorp/vault:latest
36 cap_add:
37 - IPC_LOCK
38 environment:
39 - VAULT_DEV_ROOT_TOKEN_ID=${VAULT_TOKEN}
40 ports:
41 - "8200:8200"
42 networks:
43 - tfe_net
44
45 # Note: TFE requires license
46 # Using open-source Atlantis as alternative
47 atlantis:
48 image: ghcr.io/runatlantis/atlantis:latest
49 ports:
50 - "4141:4141"
51 environment:
52 - ATLANTIS_GH_USER=${GITHUB_USER}
53 - ATLANTIS_GH_TOKEN=${GITHUB_TOKEN}
54 - ATLANTIS_REPO_ALLOWLIST=github.com/your-org/*
55 - ATLANTIS_ATLANTIS_URL=http://localhost:4141
56 volumes:
57 - atlantis_data:/atlantis
58 networks:
59 - tfe_net
60
61 prometheus:
62 image: prom/prometheus:latest
63 ports:
64 - "9090:9090"
65 volumes:
66 - prometheus_data:/prometheus
67 networks:
68 - tfe_net
69
70 grafana:
71 image: grafana/grafana:latest
72 ports:
73 - "3000:3000"
74 environment:
75 - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
76 volumes:
77 - grafana_data:/var/lib/grafana
78 networks:
79 - tfe_net
80
81volumes:
82 postgres_data:
83 redis_data:
84 minio_data:
85 atlantis_data:
86 prometheus_data:
87 grafana_data:
88
89networks:
90 tfe_net:

.env Template

.env
1# Terraform Enterprise / Atlantis
2POSTGRES_PASSWORD=secure_postgres_password
3MINIO_USER=minioadmin
4MINIO_PASSWORD=secure_minio_password
5VAULT_TOKEN=dev_root_token
6GITHUB_USER=your_github_username
7GITHUB_TOKEN=your_github_token
8GRAFANA_PASSWORD=secure_grafana_password
9
10# Atlantis at http://localhost:4141
11# MinIO at http://localhost:9001

Usage Notes

  1. 1Atlantis at http://localhost:4141
  2. 2MinIO for state storage at http://localhost:9001
  3. 3Vault for secrets at http://localhost:8200
  4. 4Configure GitHub webhooks for PRs
  5. 5Use atlantis.yaml for workflow config

Individual Services(7 services)

Copy individual services to mix and match with your existing compose files.

postgres
postgres:
  image: postgres:15-alpine
  environment:
    - POSTGRES_USER=terraform
    - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    - POSTGRES_DB=terraform
  volumes:
    - postgres_data:/var/lib/postgresql/data
  networks:
    - tfe_net
redis
redis:
  image: redis:7-alpine
  volumes:
    - redis_data:/data
  networks:
    - tfe_net
minio
minio:
  image: minio/minio:latest
  command: server /data --console-address ":9001"
  ports:
    - "9000:9000"
    - "9001:9001"
  environment:
    - MINIO_ROOT_USER=${MINIO_USER}
    - MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
  volumes:
    - minio_data:/data
  networks:
    - tfe_net
vault
vault:
  image: hashicorp/vault:latest
  cap_add:
    - IPC_LOCK
  environment:
    - VAULT_DEV_ROOT_TOKEN_ID=${VAULT_TOKEN}
  ports:
    - "8200:8200"
  networks:
    - tfe_net
atlantis
atlantis:
  image: ghcr.io/runatlantis/atlantis:latest
  ports:
    - "4141:4141"
  environment:
    - ATLANTIS_GH_USER=${GITHUB_USER}
    - ATLANTIS_GH_TOKEN=${GITHUB_TOKEN}
    - ATLANTIS_REPO_ALLOWLIST=github.com/your-org/*
    - ATLANTIS_ATLANTIS_URL=http://localhost:4141
  volumes:
    - atlantis_data:/atlantis
  networks:
    - tfe_net
prometheus
prometheus:
  image: prom/prometheus:latest
  ports:
    - "9090:9090"
  volumes:
    - prometheus_data:/prometheus
  networks:
    - tfe_net
grafana
grafana:
  image: grafana/grafana:latest
  ports:
    - "3000:3000"
  environment:
    - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
  volumes:
    - grafana_data:/var/lib/grafana
  networks:
    - tfe_net

Quick Start

terminal
1# 1. Create the compose file
2cat > docker-compose.yml << 'EOF'
3services:
4 postgres:
5 image: postgres:15-alpine
6 environment:
7 - POSTGRES_USER=terraform
8 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
9 - POSTGRES_DB=terraform
10 volumes:
11 - postgres_data:/var/lib/postgresql/data
12 networks:
13 - tfe_net
14
15 redis:
16 image: redis:7-alpine
17 volumes:
18 - redis_data:/data
19 networks:
20 - tfe_net
21
22 minio:
23 image: minio/minio:latest
24 command: server /data --console-address ":9001"
25 ports:
26 - "9000:9000"
27 - "9001:9001"
28 environment:
29 - MINIO_ROOT_USER=${MINIO_USER}
30 - MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
31 volumes:
32 - minio_data:/data
33 networks:
34 - tfe_net
35
36 vault:
37 image: hashicorp/vault:latest
38 cap_add:
39 - IPC_LOCK
40 environment:
41 - VAULT_DEV_ROOT_TOKEN_ID=${VAULT_TOKEN}
42 ports:
43 - "8200:8200"
44 networks:
45 - tfe_net
46
47 # Note: TFE requires license
48 # Using open-source Atlantis as alternative
49 atlantis:
50 image: ghcr.io/runatlantis/atlantis:latest
51 ports:
52 - "4141:4141"
53 environment:
54 - ATLANTIS_GH_USER=${GITHUB_USER}
55 - ATLANTIS_GH_TOKEN=${GITHUB_TOKEN}
56 - ATLANTIS_REPO_ALLOWLIST=github.com/your-org/*
57 - ATLANTIS_ATLANTIS_URL=http://localhost:4141
58 volumes:
59 - atlantis_data:/atlantis
60 networks:
61 - tfe_net
62
63 prometheus:
64 image: prom/prometheus:latest
65 ports:
66 - "9090:9090"
67 volumes:
68 - prometheus_data:/prometheus
69 networks:
70 - tfe_net
71
72 grafana:
73 image: grafana/grafana:latest
74 ports:
75 - "3000:3000"
76 environment:
77 - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
78 volumes:
79 - grafana_data:/var/lib/grafana
80 networks:
81 - tfe_net
82
83volumes:
84 postgres_data:
85 redis_data:
86 minio_data:
87 atlantis_data:
88 prometheus_data:
89 grafana_data:
90
91networks:
92 tfe_net:
93EOF
94
95# 2. Create the .env file
96cat > .env << 'EOF'
97# Terraform Enterprise / Atlantis
98POSTGRES_PASSWORD=secure_postgres_password
99MINIO_USER=minioadmin
100MINIO_PASSWORD=secure_minio_password
101VAULT_TOKEN=dev_root_token
102GITHUB_USER=your_github_username
103GITHUB_TOKEN=your_github_token
104GRAFANA_PASSWORD=secure_grafana_password
105
106# Atlantis at http://localhost:4141
107# MinIO at http://localhost:9001
108EOF
109
110# 3. Start the services
111docker compose up -d
112
113# 4. View logs
114docker compose logs -f

One-Liner

Run this command to download and set up the recipe in one step:

terminal
1curl -fsSL https://docker.recipes/api/recipes/terraform-enterprise/run | bash

Troubleshooting

  • Terraform runs failing with 'unable to lock state': Check Redis connectivity and ensure workspace isn't locked by another operation in the UI
  • MinIO bucket access errors during state operations: Verify MINIO_ROOT_USER and MINIO_ROOT_PASSWORD environment variables match Terraform Enterprise S3 configuration
  • Atlantis webhook not triggering on pull requests: Confirm GitHub webhook URL points to correct port 4141 and webhook secret matches ATLANTIS_GH_TOKEN
  • PostgreSQL connection timeouts during workspace operations: Increase PostgreSQL max_connections and shared_buffers for concurrent Terraform runs
  • Vault secrets not available in Terraform runs: Ensure Vault token has appropriate policies and Terraform Enterprise can reach Vault on port 8200
  • Large Terraform state files causing MinIO upload failures: Increase MinIO memory limits and configure multipart upload thresholds in Terraform Enterprise

Community Notes

Loading...
Loading notes...

Download Recipe Kit

Get all files in a ready-to-deploy package

Includes docker-compose.yml, .env template, README, and license

Ad Space