AWS com LocalStack e Terraform
Uma das principais dores de quem está estudando Cloud AWS é não conseguir aplicar o conteúdo na prática. É fato que nem sempre podemos ter uma conta da AWS com um cartão de crédito disponível, ou mesmo ter recursos financeiros para subir uma infraestrutura com os serviços necessários. E a gente sabe que não há nada melhor do que aplicar o conteúdo, experimentar, "quebrar" as coisas e entender como tudo funciona. Porém, fica o dilema de não ter acesso ou de praticar correndo o risco de ter infelizes surpresas na fatura do cartão no fim do mês.
Para resolver esse problema, existe uma ferramenta muito legal e que tem sido muito útil nos meus labs, permitindo emular alguns dos principais serviços da AWS e interagir através da linha de comando (CLI), SDKs e IaC: o LocalStack.
O objetivo deste artigo é apresentar o LocalStack e como ele pode ser utilizado junto com o Terraform para ambientes de estudo mais próximos dos cenários reais, mas sem pesar no bolso.
Então, bora lá conhecer essa ferramenta sensacional?
O que é e como funciona o LocalStack?
O LocalStack é uma ferramenta gratuita que emula serviços da AWS de forma local, rodando em um container Docker. Isso permite interagir e testar serviços como EC2, S3, VPC, CloudWatch, SQS, Route 53, ACM, entre outros. Com ele, podemos criar ambientes de teste com a mesma estrutura (inclusive de código!) que faríamos caso estivéssemos usando a própria AWS.
Com ele, fazemos com que a API do LocalStack responda no lugar da API da AWS, permitindo realizar testes de Infraestrutura como Código (IaC), validar pipelines CI/CD, scripts de automação, etc. Não é massa?
Agora que já temos um overview sobre o LocalStack, vamos partir para a instalação.
Instalando o LocalStack
Para utilizar o LocalStack, você precisa ter instalado:
Para não deixar este artigo muito longo, optei por não detalhar a instalação dos pré-requisitos. Um ponto importante é que vamos usar a AWS CLI, e por isso precisamos configurar com as credenciais para o LocalStack.
Para isso, após instalar a AWS CLI, rode o comando aws configure e preencha com as seguintes informações:
- AWS Access Key ID: test
- AWS Secret Access Key: test
- Default region name: us-east-1
- Default output format: json

Feito isso, vamos seguir com a instalação, porém, há um detalhe importante: a partir de março de 2026, o LocalStack vai deixar de manter uma versão Community realmente ativa e vai exigir autenticação (login/token) para usar a imagem principal (localstack/localstack:latest).
Portanto, antes de realmente instalar, é necessário:
1) Criar uma conta usando e-mail ou autenticação via Google ou GitHub;
2) Clicar no link de ativação, enviado por email
3) Preencher os dados para iniciar uma versão de testes do Pro durante 15 dias (sem necessidade de cadastrar o cartão de crédito):

Após preencher, seremos direcionados para as instruções de download, instalação e configuração do LocalStack:

Nesse tutorial, vou seguir com o padrão Linux, então, copiei o link do binário e segui com os comandos:
## Baixando o binário
curl --output localstack-cli-4.13.1-linux-amd64-onefile.tar.gz \
--location https://github.com/localstack/localstack-cli/releases/download/v4.13.1/localstack-cli-4.13.1-linux-amd64-onefile.tar.gz
## Extrair o binário para /usr/local/bin
sudo tar xvzf localstack-cli-4.13.1-linux-*-onefile.tar.gz -C /usr/local/bin
## Validar a versão
localstack --version
## Configurar o token (está no passo 2 da página Getting Started)
localstack auth set-token <use_seu_token_aqui>Com tudo ok, vamos dar um start no LocalStack com o comando:
## Rodar o LocalStack em segundo plano
localstack start -dO comando acima vai iniciar uma instância do Localstack no localhost, utilizando a porta 4566, dessa forma aqui:

Para testar se tudo deu certo mesmo, vamos simular a criação de um Bucket S3:
## Setar LocalStack Endpoint URL:
export LOCALSTACK_ENDPOINT=http://localhost:4566
## Criar o Bucket
aws --endpoint-url=$LOCALSTACK_ENDPOINT s3 mb s3://meu-primeiro-bucket
## Listar o Bucket
aws --endpoint-url=$LOCALSTACK_ENDPOINT s3 lsE veja ele aí, Bucker criado e listado:

Acessando o dashboard
Além de verificar e interagir com os recursos via CLI, também podemos usar uma interface gráfica (GUI) que nos ajuda a ter uma percepção mais "real" do que estamos construindo.
Para acessar esse dashboard, vá para a mesma página em que criamos a conta e pegamos os dados do token, clique na aba lateral esquerda, em Instances... E voilá! Os recursos disponíveis estão todos aí:

Agora que fizemos e acontecemos no LocalStack, você acha que acabou? Segura aí, que ainda tem mais mão na massa: vamos subir um website estático usando o Terraform!
Criando a infra LocalStack com Terraform
Primeiro, é necessário ter o Terraform instalado. Então, vou deixar aqui a documentação do Terraform para seguirem com a instalação, conforme o seu sistema operacional. Após instalação, use o comando terraform --version para validar a versão instalada. Feito isso, indico criar um diretório a parte para começarmos com esse projeto.
Dentro do diretório, crie os arquivos index.html e error.html, que serão as páginas dos website. Caso você não tenha arquivos para subir, pode usar o conteúdo os arquivos a seguir:
index.html
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>Site estático com Terraform + LocalStack</title>
</head>
<body style="margin:0; font-family: Arial, Helvetica, sans-serif; background-color:#0f172a; color:#f1f5f9; display:flex; align-items:center; justify-content:center; height:100vh;">
<div style="text-align:center; background-color:#1e293b; padding:40px; border-radius:12px; box-shadow:0 10px 25px rgba(0,0,0,0.3); max-width:600px;">
<h1 style="color:#38bdf8; margin-bottom:20px;">
Chegaaaa mais... Deploy realizado com sucesso!
</h1>
<p style="font-size:18px; line-height:1.6;">
Este site estático foi provisionado utilizando
<strong>Terraform</strong> para criar um bucket S3
e publicado localmente com <strong>LocalStack</strong>.
</p>
<p style="margin-top:20px; font-size:16px; color:#94a3b8;">
Infraestrutura como Código + Ambiente AWS Local =
desenvolvimento mais rápido, seguro e econômico. Show, né?
</p>
<div style="margin-top:30px; padding:10px; background-color:#0ea5e9; border-radius:8px; font-weight:bold;">
🌍 Ambiente: LocalStack (AWS Emulator)
</div>
</div>
</body>
</html>error.html
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<title>404</title>
</head>
<body style="margin:0; font-family: Arial, Helvetica, sans-serif; background: linear-gradient(135deg, #1e293b, #0f172a); color:#f1f5f9; display:flex; align-items:center; justify-content:center; height:100vh;">
<div style="text-align:center; background-color:#1e293b; padding:40px; border-radius:12px; box-shadow:0 10px 25px rgba(0,0,0,0.4); max-width:400px; width:90%;">
<h1 style="margin:0 0 20px 0; font-size:48px; color:#f86538;">
Ops... Deu ruim!
</h1>
<p style="font-size:18px; margin:0; color:#cbd5e1;">
404. Algo de errado não está certo.
</p>
</div>
</body>
</html>Em seguida, vamos criar um arquivo chamado providers.tf, com o seguinte conteúdo:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
access_key = "test"
secret_key = "test"
region = "us-east-1"
s3_use_path_style = false
skip_credentials_validation = true
skip_metadata_api_check = true
endpoints {
s3 = "http://s3.localhost.localstack.cloud:4566"
iam = "http://localhost:4566"
sts = "http://localhost:4566"
}
}Aqui, estamos informando ao Terraform qual versão do provider AWS que ele deve usar, setando a versão como 5.x.; e que ele deve se conectar com o LocalStack, e não para a AWS real. Setamos também credenciais fictícias para facilitar a conexão com o ambiente do simulador.
Em seguida, vamos criar as variáveis reutilizáveis que serão utilizadas no projeto, através do arquivo variables.tf, com o seguinte conteúdo:
variable "bucket_name" {
description = "Name of the s3 bucket"
type = string
default = "mywebsites3"
}
variable "tags" {
description = "Tags to set on the bucket"
type = map(string)
default = {}
}Basicamente, definimos que podemos alterar tanto o nome do Bucket quanto as tags, tornando esse mini projeto mais organizado e flexível. No bucket_name, foi definido um parâmetro default para o nome do Bucket, apenas para facilitar o processo. O ideal
Agora, vamos criar um outro arquivo main.tf que vai ser responsável pela criação dos recursos, ou seja, do Bucket S3, das configurações de website estático, da policy e fazer o upload dos arquivos HTML.
## Criar o bucket
resource "aws_s3_bucket" "s3_bucket_tf" {
bucket = var.bucket_name
tags = merge(
var.tags, {
Name = "${var.bucket_name}-static-website"
}
)
}
## Configurar o bucket para hospedar um site estático
resource "aws_s3_bucket_website_configuration" "s3_static_website_config" {
bucket = aws_s3_bucket.s3_bucket_tf.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
}
## Bucket policy e ACL
resource "aws_s3_bucket_acl" "s3_bucket_acl" {
bucket = aws_s3_bucket.s3_bucket_tf.id
acl = "public-read"
}
resource "aws_s3_bucket_policy" "s3_bucket" {
bucket = aws_s3_bucket.s3_bucket_tf.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "PublicReadGetObject"
Effect = "Allow"
Principal = "*"
Action = "s3:GetObject"
Resource = [
aws_s3_bucket.s3_bucket_tf.arn,
"${aws_s3_bucket.s3_bucket_tf.arn}/*",
]
},
]
})
}
## Upload dos arquivos para o bucket
resource "aws_s3_object" "object_www" {
depends_on = [aws_s3_bucket.s3_bucket_tf]
for_each = fileset("${path.root}", "*.html")
bucket = var.bucket_name
key = basename(each.value)
source = each.value
etag = filemd5("${each.value}")
content_type = "text/html"
acl = "public-read"
}Sobre os blocos de recursos, o bloco aws_s3_object usa a função fileset para mapear os arquivos HTML que estiverem na pasta raiz do projeto. Por isso, lembre-se de mantê-los no mesmo diretório que os arquivos do Terraform. Além disso, o parâmetro etag garante que o Terraform detecte mudanças no conteúdo dos arquivos.
E por fim, vamos criar um arquivo chamado outputs.tf que vai conter informações de saída, tais como o ARN do Bucket e o endpoint do website.
output "arn" {
description = "ARN of the bucket"
value = aws_s3_bucket.s3_bucket_tf.arn
}
output "bucket_name" {
description = "Name (id) of the bucket"
value = aws_s3_bucket.s3_bucket_tf.id
}
output "website_endpoint" {
value = aws_s3_bucket_website_configuration.s3_static_website_config.website_endpoint
}Agora, execute os comandos:
## Inicializar o projeto
terraform init
## Formatar os arquivos
terraform fmt
## Validar a sintaxe e configurações
terraform validate
## Mostar o plano de execução
terraform plan
## Aplicar as mudanças
terraform apply -- auto-approveApós o apply, acesse o endpoint no navegador, usando esta URL: http://mywebsites3.s3-website.localhost.localstack.cloud:4566/
E olha ele aí!

Inclusive, com a página de erro também:

Massa demais, não é? Para finalizar, vamos limpar o nosso ambiente, removendo os recursos usando o comando terraform destroy --auto-approve
Simples assim.
Extra: como usar o LocalStack for Students
Na versão free do LocalStack, há 30 serviços disponíveis para brincar à vontade. No entanto, a medida em que os estudos e projetos vão ficando cada vez mais complexos, isso pode não ser o bastante. A mão de subir um EKS chega até a arder...
Infelizmente, a questão financeira pode ser uma pequena barreira aqui, mas há uma luz no fim do túnel: o LocalStack for Students!
Caso você tenha uma conta do GitHub Student Developer Pack, você tem acesso a diversos recursos para além da licença free. Os recursos incluem: AWS Glue, EMR, Lake Formation, Amazon MQ, Cost Explorer, Elastic Beanstalk, ECS, EKS, entre outros. Tem muita coisa mesmo.!Além disso, você tem 1.000 créditos mensais em CI/CD para integrar e implantar continuamente desenvolvimentos locais.
Não é massa? Caso tenha alguma dúvida sobre como configurar o GitHub Student Developer Pack, escrevi aqui um artigo para auxiliar.
Palavras finais
Com este artigo, quis mostrar para vocês uma pequena parte do que é possível fazer com o LocalStack, aliado a outras ferramentas, tais como o Terraform.
Por motivos didáticos, resolvi não utilizar o tflocal e o awslocal, que são wrappers que automatizam apontamento dos endpoints para o ambiente local. Optei pela configuração manual para entendermos melhor como a comunicação entre as ferramentas funciona.
Espero que este pequeno guia ajude você a praticar Cloud sem medo e sem receio de custos inesperados.
Bons estudos e até a próxima!
Referências
- LocalStack
- LocalStack for Students
- GitHub Student Developer Pack
- LocalStack Doc - Licensing & Tiers
- Terraform Documentation
- Simulando AWS com LocalStack e Terraform: Guia completo - vídeo do Jeferson Fernando da LinuxTips
- Repositório terraform-101 - feito a partir da live com o Jeferson e Gomex pela LinuxTips
- Host a static website locally using Simple Storage Service (S3) and Terraform with LocalStack