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çãoQuando se encaixaO que você gerencia
S3 privado + CloudFront (OAC)Sites estáticos e SPAsBucket, distribuição, política, pipeline de CI
AWS Amplify HostingEstáticos, SPAs e frameworks com SSR; fluxo baseado em GitConfiguraçã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 redeImagem, 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:

json
{
  "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"
        }
      }
    }
  ]
}
Política de bucket baseada no exemplo da documentação do CloudFront. Substitua o nome do bucket, o ID da conta e o ID da distribuição.
  • 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:

yaml
# .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 role frontend-deploy deve confiar no provedor OIDC do GitHub e limitar o sub ao repositório e ao environment; as permissões dela, só s3 sync no bucket e create-invalidation na distribuição.

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.

Do design à decisão

Compare opções de nuvem

Confira preços, limites, condições e fontes de cada opção.

Abrir comparador