Distribution Strategies
Distribution Overview
While the Terraform Registry is ideal for public providers, organizations often need alternative distribution methods for private, internal, or air-gapped environments.
Distribution Methods
1. Terraform Registry (Public)
Best for: Open source providers
Advantages:
- ✅ Global distribution
- ✅ Automatic updates
- ✅ Version management
- ✅ Documentation hosting
- ✅ Discovery
Usage:
terraform {
required_providers {
cachecloud = {
source = "example/cachecloud"
version = "~> 1.0"
}
}
}
2. Private Registry
Best for: Enterprise organizations
Advantages:
- ✅ Internal providers
- ✅ Access control
- ✅ Custom hosting
- ✅ Compliance
- ✅ Audit trails
3. Direct Downloads
Best for: Small teams, custom deployments
Advantages:
- ✅ Simple setup
- ✅ Full control
- ✅ No external dependencies
- ✅ Air-gap friendly
4. Provider Mirrors
Best for: Multi-region, air-gapped environments
Advantages:
- ✅ Local caching
- ✅ Bandwidth savings
- ✅ Offline support
- ✅ Compliance
Private Registry Implementation
Terraform Cloud/Enterprise
Setup:
- Create Organization
# Navigate to Terraform Cloud open https://app.terraform.io/ # Create organization: "my-company" - Configure Private Registry
# Settings → Registry → Add Provider # Link GitHub repository # Configure webhook - Publish Provider
# Create release as usual git tag -s v1.0.0 -m "Release v1.0.0" git push origin v1.0.0 # Terraform Cloud automatically picks up release - Use Private Provider
terraform { required_providers { cachecloud = { source = "app.terraform.io/my-company/cachecloud" version = "~> 1.0" } } }
Self-Hosted Registry
Using Terraform Enterprise:
# terraform.rc or .terraformrc
provider_installation {
direct {
# Use self-hosted registry
registry = "terraform.example.com"
}
}
Using Artifactory:
- Setup Terraform Repository
# Create Terraform repository in Artifactory # Type: Generic # Package Type: Terraform - Upload Provider
# Upload to Artifactory curl -u user:password \ -T terraform-provider-cachecloud_1.0.0_linux_amd64.zip \ "https://artifactory.example.com/terraform/example/cachecloud/1.0.0/linux_amd64/terraform-provider-cachecloud_1.0.0_linux_amd64.zip" - Configure Terraform
# .terraformrc provider_installation { network_mirror { url = "https://artifactory.example.com/terraform/" } }
Direct Download Method
Manual Installation
1. Download Provider
# Download release
PROVIDER_VERSION="1.0.0"
OS="darwin" # or linux, windows
ARCH="amd64" # or arm64
curl -LO "https://github.com/example/terraform-provider-cachecloud/releases/download/v${PROVIDER_VERSION}/terraform-provider-cachecloud_${PROVIDER_VERSION}_${OS}_${ARCH}.zip"
# Extract
unzip terraform-provider-cachecloud_${PROVIDER_VERSION}_${OS}_${ARCH}.zip
2. Install to Plugin Directory
# Create plugin directory
mkdir -p ~/.terraform.d/plugins/registry.terraform.io/example/cachecloud/${PROVIDER_VERSION}/${OS}_${ARCH}
# Move binary
mv terraform-provider-cachecloud_v${PROVIDER_VERSION} \
~/.terraform.d/plugins/registry.terraform.io/example/cachecloud/${PROVIDER_VERSION}/${OS}_${ARCH}/
# Make executable
chmod +x ~/.terraform.d/plugins/registry.terraform.io/example/cachecloud/${PROVIDER_VERSION}/${OS}_${ARCH}/terraform-provider-cachecloud_v${PROVIDER_VERSION}
3. Configure Terraform
terraform {
required_providers {
cachecloud = {
source = "example/cachecloud"
version = "1.0.0"
}
}
}
Automated Installation Script
#!/bin/bash
# install-provider.sh
set -e
PROVIDER_NAME="cachecloud"
PROVIDER_NAMESPACE="example"
PROVIDER_VERSION="${1:-1.0.0}"
GITHUB_REPO="example/terraform-provider-cachecloud"
# Detect OS and architecture
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m)"
case "${OS}" in
darwin) OS="darwin" ;;
linux) OS="linux" ;;
mingw*) OS="windows" ;;
esac
case "${ARCH}" in
x86_64) ARCH="amd64" ;;
aarch64) ARCH="arm64" ;;
arm64) ARCH="arm64" ;;
esac
echo "Installing ${PROVIDER_NAMESPACE}/${PROVIDER_NAME} v${PROVIDER_VERSION} for ${OS}_${ARCH}"
# Download
DOWNLOAD_URL="https://github.com/${GITHUB_REPO}/releases/download/v${PROVIDER_VERSION}/terraform-provider-${PROVIDER_NAME}_${PROVIDER_VERSION}_${OS}_${ARCH}.zip"
echo "Downloading from: ${DOWNLOAD_URL}"
curl -LO "${DOWNLOAD_URL}"
# Extract
unzip -o "terraform-provider-${PROVIDER_NAME}_${PROVIDER_VERSION}_${OS}_${ARCH}.zip"
# Create plugin directory
PLUGIN_DIR="${HOME}/.terraform.d/plugins/registry.terraform.io/${PROVIDER_NAMESPACE}/${PROVIDER_NAME}/${PROVIDER_VERSION}/${OS}_${ARCH}"
mkdir -p "${PLUGIN_DIR}"
# Move binary
mv "terraform-provider-${PROVIDER_NAME}_v${PROVIDER_VERSION}" "${PLUGIN_DIR}/"
# Make executable
chmod +x "${PLUGIN_DIR}/terraform-provider-${PROVIDER_NAME}_v${PROVIDER_VERSION}"
# Cleanup
rm "terraform-provider-${PROVIDER_NAME}_${PROVIDER_VERSION}_${OS}_${ARCH}.zip"
echo "✅ Installation complete!"
echo "Provider installed to: ${PLUGIN_DIR}"
Usage:
# Install specific version
./install-provider.sh 1.0.0
# Install latest
./install-provider.sh
Provider Network Mirror
Setting Up Mirror
Directory Structure:
mirror/
└── registry.terraform.io/
└── example/
└── cachecloud/
├── index.json
└── 1.0.0.json
index.json:
{
"versions": {
"1.0.0": {},
"1.1.0": {}
}
}
1.0.0.json:
{
"archives": {
"darwin_amd64": {
"url": "terraform-provider-cachecloud_1.0.0_darwin_amd64.zip",
"hashes": [
"zh:a1b2c3d4e5f6...",
"h1:e5f6g7h8i9j0..."
]
},
"linux_amd64": {
"url": "terraform-provider-cachecloud_1.0.0_linux_amd64.zip",
"hashes": [
"zh:b2c3d4e5f6g7...",
"h1:f6g7h8i9j0k1..."
]
}
}
}
HTTP Server Setup
Using Nginx:
# /etc/nginx/sites-available/terraform-mirror
server {
listen 80;
server_name terraform-mirror.internal.example.com;
root /var/www/terraform-mirror;
location / {
autoindex on;
add_header 'Access-Control-Allow-Origin' '*';
}
location ~ \.json$ {
add_header Content-Type application/json;
}
}
Using Python:
cd mirror/
python3 -m http.server 8080
Configure Mirror
# .terraformrc
provider_installation {
network_mirror {
url = "https://terraform-mirror.internal.example.com/"
}
}
Air-Gapped Environments
Complete Offline Bundle
1. Download All Artifacts
#!/bin/bash
# download-provider-bundle.sh
PROVIDER="cachecloud"
VERSION="1.0.0"
PLATFORMS="darwin_amd64 darwin_arm64 linux_amd64 linux_arm64 windows_amd64"
mkdir -p bundle/${PROVIDER}/${VERSION}
for PLATFORM in ${PLATFORMS}; do
echo "Downloading ${PLATFORM}..."
curl -LO "https://github.com/example/terraform-provider-${PROVIDER}/releases/download/v${VERSION}/terraform-provider-${PROVIDER}_${VERSION}_${PLATFORM}.zip"
mv "terraform-provider-${PROVIDER}_${VERSION}_${PLATFORM}.zip" bundle/${PROVIDER}/${VERSION}/
done
# Download checksums
curl -LO "https://github.com/example/terraform-provider-${PROVIDER}/releases/download/v${VERSION}/terraform-provider-${PROVIDER}_${VERSION}_SHA256SUMS"
curl -LO "https://github.com/example/terraform-provider-${PROVIDER}/releases/download/v${VERSION}/terraform-provider-${PROVIDER}_${VERSION}_SHA256SUMS.sig"
mv terraform-provider-${PROVIDER}_${VERSION}_SHA256SUMS* bundle/${PROVIDER}/${VERSION}/
# Create bundle
tar -czf terraform-provider-${PROVIDER}-${VERSION}-bundle.tar.gz bundle/
echo "✅ Bundle created: terraform-provider-${PROVIDER}-${VERSION}-bundle.tar.gz"
2. Transfer to Air-Gapped Environment
# Via USB, secure file transfer, etc.
scp terraform-provider-cachecloud-1.0.0-bundle.tar.gz airgap-host:/tmp/
3. Install in Air-Gapped Environment
#!/bin/bash
# install-offline-provider.sh
BUNDLE="terraform-provider-cachecloud-1.0.0-bundle.tar.gz"
# Extract bundle
tar -xzf "${BUNDLE}"
# Detect platform
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m)"
case "${ARCH}" in
x86_64) ARCH="amd64" ;;
aarch64|arm64) ARCH="arm64" ;;
esac
PLATFORM="${OS}_${ARCH}"
# Find provider binary
cd bundle/cachecloud/1.0.0
unzip "terraform-provider-cachecloud_1.0.0_${PLATFORM}.zip"
# Install
PLUGIN_DIR="${HOME}/.terraform.d/plugins/registry.terraform.io/example/cachecloud/1.0.0/${PLATFORM}"
mkdir -p "${PLUGIN_DIR}"
mv terraform-provider-cachecloud_v1.0.0 "${PLUGIN_DIR}/"
chmod +x "${PLUGIN_DIR}/terraform-provider-cachecloud_v1.0.0"
echo "✅ Provider installed offline"
Development Overrides
Local Development
# ~/.terraformrc
provider_installation {
dev_overrides {
"example/cachecloud" = "/Users/developer/go/bin"
}
# For all other providers
direct {}
}
Usage:
# Build provider
cd terraform-provider-cachecloud
go build -o ~/go/bin/terraform-provider-cachecloud
# Terraform uses local binary
cd examples/
terraform init # Skips provider download
terraform plan # Uses local binary
Container-Based Distribution
Docker Image
Dockerfile:
FROM hashicorp/terraform:1.6
# Copy provider binary
COPY terraform-provider-cachecloud /usr/local/bin/
# Set plugin directory
ENV TF_PLUGIN_CACHE_DIR=/terraform/plugins
RUN mkdir -p /terraform/plugins
WORKDIR /terraform
ENTRYPOINT ["terraform"]
Build and Use:
# Build image
docker build -t terraform-with-cachecloud:1.0.0 .
# Run
docker run -it \
-v $(pwd):/terraform \
-w /terraform \
terraform-with-cachecloud:1.0.0 \
init
Distribution Best Practices
1. Version Management
# ✅ Good: Clear version strategy
Public Registry: Latest stable versions
Private Registry: All versions including pre-release
Air-Gap Bundle: Specific tested versions
# ❌ Bad: Inconsistent versions
Different versions in different locations
No version tracking
2. Access Control
# ✅ Good: Role-based access
Public: Everyone
Private: Authenticated organization members
Internal: VPN + authentication
Air-Gap: Physical security
# ❌ Bad: No access control
All providers publicly accessible
No authentication required
3. Update Strategy
# ✅ Good: Planned updates
Weekly: Check for updates
Monthly: Test and deploy
Quarterly: Major version upgrades
# ❌ Bad: No update plan
Manual updates only
No testing
Unpredictable timing
Complete Example
Multi-Environment Setup
# .terraformrc
provider_installation {
# Production: Use company registry
direct {
registry = "terraform.company.com"
}
# Development: Use local override
dev_overrides {
"example/cachecloud" = "/Users/developer/providers"
}
# Fallback: Public registry
network_mirror {
url = "https://registry.terraform.io/"
}
}
Key Takeaways
- ✅ Choose distribution method based on requirements
- ✅ Public registry for open source providers
- ✅ Private registry for enterprise
- ✅ Direct downloads for simple setups
- ✅ Network mirrors for air-gapped environments
- ✅ Use development overrides for local testing
- ✅ Plan update strategies
- ✅ Implement access controls
- ✅ Maintain version consistency
- ✅ Document distribution process
What’s Next?
Practice the complete publishing workflow in a hands-on lab.
Previous: ← Registry Publication
Next: Publishing Lab →
Last updated: June 30, 2026