When Localhost Isn't Local: Fixing Terraform Apply Failures in LocalStack Docker Setups


When Localhost Isn't Local: Fixing Terraform Apply Failures in LocalStack Docker Setups


Software Engineer & Technology Writer


Problem

You're running Terraform against LocalStack using tflocal inside a Docker container. terraform init works perfectly, but terraform apply fails with connection errors like: 

bash
Error: creating Amazon S3 (Simple Storage) Bucket: RequestError: send request failed
caused by: Put "http://s3.localhost.localstack.cloud:4566/": dial tcp: lookup s3.localhost.localstack.cloud: no such host

or 

bash
dial tcp 127.0.0.1:4566: connect: connection refused


Clarifying the Issue

The tflocal script uses the Terraform Override mechanism and creates a temporary file localstack_providers_override.tf to configure the endpoints for the AWS provider section. The endpoints for all services are configured to point to the LocalStack API (http://localhost:4566 by default).

By default, tflocal configures S3 to use S3_HOSTNAME: special hostname to be used to connect to LocalStack S3 (default: s3.localhost.localstack.cloud).

The core issue: inside the Terraform container, localhost refers to that container itself, not the localstack service running in a separate container. When tflocal generates endpoints like http://s3.localhost.localstack.cloud:4566, Terraform tries to connect to 127.0.0.1:4566 within its own container, which leads nowhere.


Why It Matters

This is a classic container networking problem that affects any multi-container setup using tflocal. The issue is particularly confusing because:
  • terraform init often succeeds (it downloads providers and modules)
  • terraform apply fails during actual AWS API calls (like S3 bucket creation)
  • The error messages point to localhost URLs that work fine when running Terraform on the host machine
Getting this wrong means your Infrastructure as Code can't deploy locally, defeating the purpose of using LocalStack for development and testing.


Key Terms
  • LocalStack – A fully functional local AWS cloud stack for development and testing
  • tflocal – A small wrapper script to run Terraform against LocalStack that automatically configures service endpoints
  • Docker Compose network – A virtual network where containers can reach each other via service names
  • localhost in containers – Always refers only to the container itself, not the host or other containers
  • Provider Override – Terraform mechanism that tflocal uses to create a temporary localstack_providers_override.tf file

Steps at a Glance
  1. Choose Your Fix Strategy
  2. Verify Network Configuration
  3. Test Container Connectivity
  4. Clean and Apply
  5. Verify Success

Detailed Steps

Step 1: Choose Your Fix Strategy

You have two main options to resolve the container networking issue:

Option A: Override S3 Endpoint (Recommended)

Add an explicit S3 endpoint override in your Terraform configuration: 

hcl
# Create a file called terraform_override.tf
provider "aws" {
  endpoints {
    s3 = "http://localstack:4566"
  }
}

This overrides tflocal's automatic localhost-based endpoint configuration.

Option B: Configure S3_HOSTNAME Environment Variable

Set the S3_HOSTNAME environment variable in your Terraform container to use the LocalStack service name: 

yaml
# In your docker-compose.yml
local_terraform_setup:
  build:
    context: .
    dockerfile: Dockerfile.local-terraform-setup
  environment:
    - S3_HOSTNAME=localstack:4566
  volumes:
    - './terraform:/workspace'
  working_dir: /workspace/development
  networks:
    - my_network

Step 2: Verify Network Configuration

Ensure both containers are on the same Docker network. Your setup should look like: 

yaml
networks:
  my_network:
    name: my_network

services:
  localstack:
    image: localstack/localstack
    environment:
      - AWS_ENDPOINT_URL=http://localstack:4566
    networks:
      - my_network

  local_terraform_setup:
    # your terraform container config
    networks:
      - my_network

Step 3: Test Container Connectivity

Verify that your Terraform container can reach LocalStack: 

bash
docker compose -f docker-compose.dev.yaml run --rm --entrypoint curl local_terraform_setup http://localstack:4566/_localstack/health

You should see a JSON response confirming LocalStack services are ready.

Step 4: Clean and Apply

Remove any existing override files and apply your infrastructure: 

bash
# Remove any existing override files
docker compose -f docker-compose.dev.yaml run --rm --entrypoint rm local_terraform_setup -f localstack_providers_override.tf

# Run terraform apply
docker compose -f docker-compose.dev.yaml run --rm --entrypoint tflocal local_terraform_setup apply -auto-approve

Step 5: Verify Success

You can verify your S3 bucket was created by checking the LocalStack endpoint or using awslocal commands.


Conclusion

When containerizing Terraform with tflocal, the key insight is that Docker container networking requires service names, not localhost. While tflocal automatically configures endpoints to point to http://localhost:4566 by default, this only works when running on the host machine.

For container-to-container communication, you must either override the S3 endpoint to use your LocalStack service name or configure the S3_HOSTNAME environment variable. Both approaches ensure that Terraform connects to the correct LocalStack instance instead of trying to reach a non-existent localhost service.

Remember: in Docker networks, service names are your DNS, not localhost addresses. Once you fix the networking, tflocal works exactly as expected, giving you the full power of LocalStack for local AWS development without the networking headaches.




Aaron Rose is a software engineer and technology writer at tech-reader.blog.

Comments

Popular posts from this blog

The New ChatGPT Reason Feature: What It Is and Why You Should Use It

Raspberry Pi Connect vs. RealVNC: A Comprehensive Comparison

Running AI Models on Raspberry Pi 5 (8GB RAM): What Works and What Doesn't