Terraform Enterprise Self-Hosted
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-alpine4 environment: 5 - POSTGRES_USER=terraform6 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}7 - POSTGRES_DB=terraform8 volumes: 9 - postgres_data:/var/lib/postgresql/data10 networks: 11 - tfe_net1213 redis: 14 image: redis:7-alpine15 volumes: 16 - redis_data:/data17 networks: 18 - tfe_net1920 minio: 21 image: minio/minio:latest22 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:/data31 networks: 32 - tfe_net3334 vault: 35 image: hashicorp/vault:latest36 cap_add: 37 - IPC_LOCK38 environment: 39 - VAULT_DEV_ROOT_TOKEN_ID=${VAULT_TOKEN}40 ports: 41 - "8200:8200"42 networks: 43 - tfe_net4445 # Note: TFE requires license46 # Using open-source Atlantis as alternative47 atlantis: 48 image: ghcr.io/runatlantis/atlantis:latest49 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:414156 volumes: 57 - atlantis_data:/atlantis58 networks: 59 - tfe_net6061 prometheus: 62 image: prom/prometheus:latest63 ports: 64 - "9090:9090"65 volumes: 66 - prometheus_data:/prometheus67 networks: 68 - tfe_net6970 grafana: 71 image: grafana/grafana:latest72 ports: 73 - "3000:3000"74 environment: 75 - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}76 volumes: 77 - grafana_data:/var/lib/grafana78 networks: 79 - tfe_net8081volumes: 82 postgres_data: 83 redis_data: 84 minio_data: 85 atlantis_data: 86 prometheus_data: 87 grafana_data: 8889networks: 90 tfe_net: .env Template
.env
1# Terraform Enterprise / Atlantis2POSTGRES_PASSWORD=secure_postgres_password3MINIO_USER=minioadmin4MINIO_PASSWORD=secure_minio_password5VAULT_TOKEN=dev_root_token6GITHUB_USER=your_github_username7GITHUB_TOKEN=your_github_token8GRAFANA_PASSWORD=secure_grafana_password910# Atlantis at http://localhost:414111# MinIO at http://localhost:9001Usage Notes
- 1Atlantis at http://localhost:4141
- 2MinIO for state storage at http://localhost:9001
- 3Vault for secrets at http://localhost:8200
- 4Configure GitHub webhooks for PRs
- 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 file2cat > docker-compose.yml << 'EOF'3services:4 postgres:5 image: postgres:15-alpine6 environment:7 - POSTGRES_USER=terraform8 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}9 - POSTGRES_DB=terraform10 volumes:11 - postgres_data:/var/lib/postgresql/data12 networks:13 - tfe_net1415 redis:16 image: redis:7-alpine17 volumes:18 - redis_data:/data19 networks:20 - tfe_net2122 minio:23 image: minio/minio:latest24 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:/data33 networks:34 - tfe_net3536 vault:37 image: hashicorp/vault:latest38 cap_add:39 - IPC_LOCK40 environment:41 - VAULT_DEV_ROOT_TOKEN_ID=${VAULT_TOKEN}42 ports:43 - "8200:8200"44 networks:45 - tfe_net4647 # Note: TFE requires license48 # Using open-source Atlantis as alternative49 atlantis:50 image: ghcr.io/runatlantis/atlantis:latest51 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:414158 volumes:59 - atlantis_data:/atlantis60 networks:61 - tfe_net6263 prometheus:64 image: prom/prometheus:latest65 ports:66 - "9090:9090"67 volumes:68 - prometheus_data:/prometheus69 networks:70 - tfe_net7172 grafana:73 image: grafana/grafana:latest74 ports:75 - "3000:3000"76 environment:77 - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}78 volumes:79 - grafana_data:/var/lib/grafana80 networks:81 - tfe_net8283volumes:84 postgres_data:85 redis_data:86 minio_data:87 atlantis_data:88 prometheus_data:89 grafana_data:9091networks:92 tfe_net:93EOF9495# 2. Create the .env file96cat > .env << 'EOF'97# Terraform Enterprise / Atlantis98POSTGRES_PASSWORD=secure_postgres_password99MINIO_USER=minioadmin100MINIO_PASSWORD=secure_minio_password101VAULT_TOKEN=dev_root_token102GITHUB_USER=your_github_username103GITHUB_TOKEN=your_github_token104GRAFANA_PASSWORD=secure_grafana_password105106# Atlantis at http://localhost:4141107# MinIO at http://localhost:9001108EOF109110# 3. Start the services111docker compose up -d112113# 4. View logs114docker compose logs -fOne-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 | bashTroubleshooting
- 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
Components
terraform-enterprisepostgresqlredisminiovault
Tags
#terraform#hashicorp#iac#gitops#state
Category
DevOps & CI/CDAd Space
Shortcuts: C CopyF FavoriteD Download