Do repositório a uma URL pública#
O frontend é a parte que seus usuários veem: componentes, estilos e a lógica de interação. Fazer um bom deploy dele significa que cada commit na branch certa termine publicado na URL certa, de forma repetível e sem ninguém copiando arquivos na mão.
Toda plataforma de deploy de frontends, seja qual for, pede mais ou menos as mesmas coisas: o repositório, um nome DNS, como compilar o projeto, se o conteúdo é estático ou renderizado no servidor e uma rota que responda para confirmar que o site está no ar. Este guia mostra como resolver essas mesmas peças diretamente com serviços da AWS.
A primeira decisão é a mais importante: o seu build gera arquivos estáticos ou precisa de um servidor a cada requisição?
Estático ou SSR: escolha a arquitetura#
Se o comando de build gera uma pasta de HTML, CSS e JavaScript que o navegador carrega do jeito que está (uma SPA com Vite ou um export estático do Next.js), seu site é estático. O Amazon S3 pode armazená-lo, mas não executa código do lado do servidor. Se cada requisição precisa de um processo Node.js que renderize HTML, você precisa de computação.
| Opção | Quando se encaixa | O que você gerencia |
|---|---|---|
| S3 privado + CloudFront (OAC) | Sites estáticos e SPAs | Bucket, distribuição, política, pipeline de CI |
| AWS Amplify Hosting | Estáticos, SPAs e frameworks com SSR; fluxo baseado em Git | Configuração de build e branches; a AWS gerencia o resto |
| Container no ECS (por exemplo ECS Express Mode) | SSR com requisitos próprios de runtime ou rede | Imagem, serviço, load balancer e escalabilidade |
Este guia detalha a primeira opção, a mais comum para SPAs, e resume o Amplify. O caso de container é coberto no guia para fazer deploy de um serviço HTTP em containers na AWS.
Documentação: Amazon S3 · Hospedagem de sites estáticos ↗ · Vite · Deploy estático ↗ · Next.js · Static exports ↗ · Amazon ECS · Express Mode ↗
S3 privado com CloudFront e OAC#
O padrão recomendado é um bucket S3 sem acesso público (com o Block Public Access ativado) e uma distribuição do CloudFront na frente, que lê do bucket via origin access control (OAC). A AWS recomenda o OAC; o origin access identity (OAI) é o mecanismo anterior e aparece como legado. A política do bucket só permite leitura pela distribuição específica:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": { "Service": "cloudfront.amazonaws.com" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/EDFDVBD6EXAMPLE"
}
}
}
]
}- Configure index.html como default root object da distribuição. Atenção: isso só vale para a raiz, não para subdiretórios.
- Para uma SPA com rotas no lado do cliente, adicione respostas de erro personalizadas que devolvam /index.html com código 200 para 403 e 404. Com OAC e sem a permissão s3:ListBucket, o S3 responde 403 (não 404) quando o objeto não existe.
- Use seu domínio com um certificado do ACM e um alias no Route 53 apontando para a distribuição.
Documentação: CloudFront · Restringir acesso ao S3 (OAC) ↗ · Amazon S3 · Block Public Access ↗ · CloudFront · Default root object ↗ · CloudFront · Alterar códigos de resposta ↗ · Amazon S3 · GetObject e 403 ↗
Pipeline com GitHub Actions e OIDC#
O pipeline compila a cada push na main, obtém credenciais temporárias da AWS via OIDC (sem access keys guardadas no GitHub), sobe os arquivos e invalida o que não deve ficar em cache:
# .github/workflows/deploy-frontend.yml
name: deploy-frontend
on:
push:
branches: [main]
permissions:
id-token: write # necessário para pedir o token OIDC
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
environment: prod
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run build # gera dist/
- uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::111122223333:role/frontend-deploy
aws-region: us-east-1
# Assets com hash no nome: cache longo
- run: >
aws s3 sync dist/ s3://amzn-s3-demo-bucket/ --delete
--exclude index.html
--cache-control "public,max-age=31536000,immutable"
# index.html: sempre revalidar
- run: >
aws s3 cp dist/index.html s3://amzn-s3-demo-bucket/index.html
--cache-control "no-cache"
- run: >
aws cloudfront create-invalidation
--distribution-id EDFDVBD6EXAMPLE --paths "/index.html"A estratégia de cache evita invalidações em massa. Os bundlers geram nomes com hash, então esses arquivos podem ficar em cache por um ano; o index.html é servido com no-cache e é a única coisa invalidada. A AWS documenta essa alternativa como usar nomes de arquivo versionados em vez de invalidar.
Para se aprofundar: Conectar GitHub à AWS sem chaves de acesso (OIDC)
Documentação: GitHub · OIDC com AWS ↗ · configure-aws-credentials ↗ · AWS CLI · s3 sync ↗ · AWS CLI · create-invalidation ↗ · CloudFront · Invalidação vs nomes versionados ↗ · CloudFront · Expiração de conteúdo ↗
Alternativa gerenciada: Amplify Hosting#
O Amplify Hosting oferece um fluxo baseado em Git com deploy contínuo: você conecta o repositório, o Amplify compila a cada push e publica na CDN dele. Suporta frameworks com SSR, SPAs e geradores de sites estáticos.
Cada branch conectada vira um deploy próprio com sua URL (por exemplo main e dev), o que combina com ter um ambiente por branch. É a opção com menos peças quando você precisa de SSR e não quer operar containers; em troca, você tem menos controle sobre a infraestrutura do que com S3 e CloudFront.
Documentação: AWS Amplify Hosting ↗ · Amplify · Deploys por branch ↗
Verificar o deploy#
- Abra a URL pública, navegue direto para uma rota interna (por exemplo /perfil) e recarregue: se você vê o app e não um erro XML do S3, as respostas de erro estão bem configuradas.
- Confira que o bucket não responde se você acessar o endpoint direto dele; ele só deve servir via CloudFront.
- Revise os headers Cache-Control do index.html e de um asset com hash.
- Defina uma rota de health check simples (a raiz costuma bastar) que devolva 200 e use-a no seu monitoramento.
Checklist#
- Build reproduzível (npm ci, versão do Node fixada).
- Bucket privado, OAC e política limitada à distribuição.
- Respostas 403/404 para /index.html só se for uma SPA.
- Credenciais de CI via OIDC com permissões mínimas; nada de segredos no bundle do cliente.
- Cache longo para assets com hash; no-cache para o index.html.
Fontes e escopo
Documentação consultada em 25 de setembro de 2026. Os exemplos e critérios de decisão são propostas editoriais; adapte-os ao contrato da sua aplicação e valide-os no seu ambiente de testes autorizado.
- Amazon S3 · Hospedagem de sites estáticos ↗
- Vite · Deploy estático ↗
- Next.js · Static exports ↗
- Amazon ECS · Express Mode ↗
- CloudFront · Restringir acesso ao S3 (OAC) ↗
- Amazon S3 · Block Public Access ↗
- CloudFront · Default root object ↗
- CloudFront · Alterar códigos de resposta ↗
- Amazon S3 · GetObject e 403 ↗
- GitHub · OIDC com AWS ↗
- configure-aws-credentials ↗
- AWS CLI · s3 sync ↗
- AWS CLI · create-invalidation ↗
- CloudFront · Invalidação vs nomes versionados ↗
- CloudFront · Expiração de conteúdo ↗
- AWS Amplify Hosting ↗
- Amplify · Deploys por branch ↗
Compare opções de nuvem
Confira preços, limites, condições e fontes de cada opção.
Abrir comparador