Executando verificação de segurança...
13

[Tutorial] Crie e hospede sites estáticos de graça na AWS usando Next.js (Alerta para ideia de negócio!)

Neste tutorial vamos hospedar um site estático criado com o Next.js na AWS com custo zero ou quase zero, mas com desempenho excelente!

O que você vai ter no final:

  • Um site estático com custo mínimo
  • O site será acessível através do endereço www.exemplo.com.br ou exemplo.com.br
  • O site aceita conexões HTTPS para maior segurança
  • O site terá um ótimo desempenho e terá uma ótima base para ter bom posicionamento nos mecanismos de busca
  • O site usará um CDN (Content Delivery Network, saiba mais o que é isso) para melhor desempenho, possibilitar aceitar conexões HTTPS e estar bem posicionado nos resultados dos buscadores

O que é um site estático?

À primeira vista, o nome “estático” dá a entender que o site é uma página “parada”, um site antiquado dos anos 90, com HTML e CSS puros, que não tem interatividade, não mostra informações atualizadas e tem poucas possibilidades de uso. Na verdade, um site estático pode ser interativo, pode pegar dados de uma API, pode ter um CMS (Content Management System, do tipo Wordpress). Veja aqui alguns exemplos de sites estáticos e outros exemplos aqui.

Por quê o custo é zero ou quase zero?

Para esse projeto, vamos usar os seguintes serviços AWS:

  • S3, que armazenará os arquivos HTML, CSS e JavaScript
  • Cloudfront, que será o nosso CDN e retornará os nossos arquivos de um local mais próximo possível do usuário que está acessando o site

O S3 tem limites bem generosos para novas contas (saiba mais sobre os limites grátis) e o preço do armazenamento e transferência são na casa dos centavos (saiba mais sobre os custos). O Cloudfront têm um limite grátis vitalício muito generoso e suporta uma grande quantidade de transferências de dados também com custo na casa de centavos (saiba mais sobre os custos)

Vantagens

  • Páginas muito rápidas
  • Sem necessidade de criar, configurar e administrar servidores
  • Custo zero ou quase zero
  • Ótimo para mecanismos de busca: amigável para web crawlers, ótimo desempenho da página
  • Seguro contra ataques: um site estático diminui em muito as rotas de ataques

Casos de uso

  • Páginas de projetos pessoais
  • Páginas comerciais, de negócios de bairro à páginas institucionais de empresas
  • Criar diversas páginas ou projetos, mesmo com orçamento apertado
  • Landing pages comerciais que recebem poucas ou muitas solicitações
  • Blogs com poucas ou centenas de páginas
  • E-commerces

Note que é possível criar diversos sites para clientes e ter um custo fixo muito baixo, sem precisar subir servidor, atualizar servidor, balancear a carga do servidor, que são tarefas técnicas, porém que não são valorizadas pelos clientes, o que é um diferencial competitivo enorme.
Pense quantos negócios poderiam substituir páginas feitas em Wordpress, que exigem uma atenção constante, por essa solução.
Você pode criar e manter diversos sites para pequenos negócios, por exemplo, tendo um custo fixo muito baixo e cobrando uma mensalidade mais em conta que os seus concorrentes. Pense naquela pizzaria do bairro que não tem site ou paga uma mensalidade alta para ter um site no Wix. Ou páginas de apresentação profissionais de médicos, dentistas, personal trainers, etc.
Pense também em páginas corporativas, páginas de eventos, landing page de produtos, as possibilidades são inúmeras.

Pré requisitos:

  • Conta AWS
  • Projeto Next.js (Pode ser o o projeto padrão gerado pelo create-next-app ou usar o meu que criei com o v0.dev)
  • (Opcional) Um domínio próprio. Neste tutorial usaremos um domínio criado no Registro.br

Passo a passo

Você poderá acompanhar todos os passos detalhados no tutorial em Português da AWS sobre hospedar páginas estáticas com o AWS Cloudfront.

Nesse tutorial irei focar nos detalhes necesários para permitir o uso do Next.js e usando o Registo.br para obter o domínio, que o tutorial da AWS não cobre.

É necessário usar Next.js para criar sites estáticos?

Não, você pode criar um site estático com um único arquivo HTML, mas usando o Next.js é possível criar sites estáticos complexos sem precisar criar um processo completamente diferente do tradicional.

Passo 0: Crie um projeto Next.js

Você pode usar o meu projeto, que é uma landing page para uma personal trainer imaginária chamada Diana, que fiz com a ajuda do v0 (saiba mais no meu post sobre o v0.dev) ou criar o seu próprio projeto da maneira que preferir.

Caso você crie seu próprio projeto, é necessário ficar atendo a algumas limitações ao usar o Next.js para gerar páginas estáticas.
A grande maioria dos recursos do Next.js continua funcionando ao criar páginas estáticas. No entanto, como hospedaremos o site em um servidor que apenas retorna arquivos, não podemos usar funcionalidades que dependem de um servidor que processe dados, como por exemplo:

  • usar a tag <Image> (possível usar com uma configuração extra)
  • usar server components
  • Criar rotas de API
  • Usar middleware
  • Usar ISR (Incremental Static Regeneration)

Veja toda a lista de limitações na documentação oficial.

Passo 1: Crie o primeiro bucket S3 para www.exemplo.com.br, vamos definir como “principal”

Um bucket, ou balde em Português, é literalmente um lugar para guardar seus arquivos. Pense em uma pasta que você guarda todos os arquivos sobre um assunto. Logo, se você tem diferentes projetos, é melhor criar um bucket para cada projeto.

Como escolher uma região da AWS?

Ao criar o bucket, você pode criar em qualquer região, mas como iremos usar um CDN, podemos usar uma região que tenha custos mais baixos como a Virgínia do Norte (us-east-1), ao invés de usar a região de São Paulo (sa-east-1). A distância maior em relação aos usuários brasileiros é compensada pelo CDN, que irá retornar os arquivos do Brasil para os usuários brasileiros.

Defina o nome do bucket como quiser, mas o nome precisa ser único no mundo (então chamá-lo de www.exemplo.com.br não vai funcionar, pois já deve ter um outro bucket com esse nome.
Nas configurações de criação do bucket mantenha todas as opções recomendadas e que já estão selecionadas.

Note que o S3 permite criar sites estáticos, mas esses sites criados pelo S3 aceitam somente conexões HTTP, que transfere dados sem criptografia, tornando as conexões inseguras. Você pode ter um site que aceita somente HTTP, mas será duramente penalizado pelos mecanismos de busca, pois o padrão atual de segurança é usar HTTPS e seus usuários notarão o cadeado aberto no browser, criando desconfiança.
Para aceitar conexões HTTPS no site estático, será necessário usar:

  • Uma CDN, usaremos o AWS Cloudfront
  • Um certificado SSL, criado gratuitamente pela AWS Certificate Manager

Vamos providenciar esses itens nos passos seguintes.

Passo 2: Crie um certificado SSL no AWS Certificate Manager

Ao criar um certificado na AWS Certificate Manger, você deverá selecionar as seguintes opções:

  • Selecionar Request a public certificate, pois vamos usar um certificado fornecido pela Amazon
  • No campo Fully qualified domain name, colocar www.exemplo.com.br e *.exemplo.com.br (o * significa qualquer valor), assim o certificado valerá para seu domínio principal e também para todos os subdomínios, como api.exemplo.com.br
  • Selecionar DNS validation em Validation Method, pois vamos validar esse certificado criando um registro CNAME no Registro.br
  • Selecionar RSA 2048 em key algorithm para maior compatibilidade

Clique no certificado criado e veja que existem duas chaves e valores CNAME. Adicione dois registros CNAME no Registro.br com essas chaves e valores para mostrar que você realmente tem o controle do domínio.
Depois de algum tempo, o painel do Certificate Manager irá mostrar que o certificado está ativo e funcionando.

Passo 3: Crie o segundo bucket S3 para exemplo.com, vamos definir como “secundário”

Esse passo é opcional. Explico por quê.
Você pode lidar com acessos para o endereço do site sem www. de duas maneiras:

  1. Usar um redirecionador grátis para redirecionar acessos do exemplo.com.br para o domínio www.exemplo.com.br. No entanto, haverá um aumento no tempo de resposta ao acessar exemplo.com.br, pois a solicitação será redirecionada de um servidor para outro. Veja meu post sobre quais redirecionadores usar.
  2. Usar o AWS Route53 para criar uma hosted zone e nela criar um registro A, que aponta para o CDN ligado a este bucket. Esse é a melhor solução, pois não há redirecionamentos, mas é necessário ter um pequeno gasto mensal de $0,50 para manter esse serviço

O Registro.br não permite apontar o domínio raíz exemplo.com.br para uma URL, apenas para um IP. Já o Cloudfront fornece apenas uma URL como destino das requisições. Para continuar usando o DNS do Registro.br, é necessário usar a solução 1 acima e nessa caso, não será necessário criar o bucket deste passo.

Já para usar a solução 2, é necessário criar um segundo bucket que irá redirecionar a requisição internamente para o primeiro bucket.
Este bucket criado para o domínio raíz exemplo.com.br irá redirecionar os acessos para o primeiro bucket www.exemplo.com.br, que contém os arquivos do site estático.
Crie o bucket da mesma forma que o primeiro, só defina o nome deixando claro que é um bucket que é para o domínio sem www.

Passo 4: Faça o upload do seu site estático para o primeiro bucket

Agora é hora de enviar os arquivos do site estático para o primeiro bucket. Vamos fazer algumas mudanças no nosso projeto Next.js.

Modifique o arquivo next.config.ts, localizado na pasta raiz do projeto Next.js para habilitar a função de exportar em arquivos estáticos. Adicione a configuração output: ‘export’. Veja mais detalhes na documentação oficial

O arquivo next.config.ts ficará assim:

const nextConfig = {
  output: 'export',
 
  // Optional: Change links `/me` -> `/me/` and emit `/me.html` -> `/me/index.html`
  // trailingSlash: true,
 
  // Optional: Prevent automatic `/me` -> `/me/`, instead preserve `href`
  // skipTrailingSlashRedirect: true,
 
  // Optional: Change the output directory `out` -> `dist`
  // distDir: 'dist',
}

Observe que sem essa configuração, o comando npm run build não produzirá os arquivos necessários para o site estático.

Agora digite no seu terminal, na pasta raíz do projeto: npm run build. Esse comando produzirá uma pasta chamada ‘out’ na pasta raiz do projeto. Dentro dessa pasta estão todos os arquivos necessários para um site estático funcionar.
Agora vá para o bucket principal, que servirá arquivos para o domínio www.exemplo.com.br e faça o upload de todos os arquivos que estão dentro da pasta out.

Opcional

Os testes de velocidade como o pagespeed.web.dev verificam se você tem uma política de cache e vão diminuir seus pontos de desempenho caso você não tenha especificado uma. Caso queira definir quanto tempo arquivos css, js, imagens podem ficar guardados no cache para evitar solicitações desnecessárias ao servidor, é bom configurar o TTL (Time to Live).
Na tela de upload em que você seleciona os arquivos para upload, clique em Properties para abrir mais opções, vá em Metadata, clique em Add metadata e escolha a opção System Defined no campo Type. Para o campo Key, defina Cache-Control e como value defina public, max-age=31536000.

Essa configuração diz que public permite que caches públicos como CDNs possam armazenar os arquivos (configurando como private apenas caches privados, como o do navegador do usuário podem guardar os arquivos) e 31536000 se refere ao tempo de 1 ano em segundos que esses caches podem armazenar o arquivo antes de solicitar o arquivo novamente do servidor

Clique em ‘Upload’ para enviar esses arquivos para o bucket principal e espere o upload terminar.

Passo 5: Configure o bucket secundário para redirecionar para o bucket primário

Aqui não muda nada do tutorial. Veja instruções no tutorial da AWS.

Passo 6: Crie uma CDN na AWS Cloudfront para o bucket principal

  • Como origem preencha como: <nome do bucket>.s3.us-east1-amazonaws.com

  • Nome: Bucket Principal

Em Origin access, você irá configurar para permitir acesso ao bucket, apesar dos acessos a ele estarem bloqueados no momento. O Cloudfront irá liberar o acesso automaticamente.

  • Selecione Legacy access identities
    Em Origin access identity, selecione Allows Cloudfront to reach the bucket “Permita que o Cloudfront acesse o bucket”
    Em Bucket policy, selecione Yes, update the bucket policy (Sim, atualize a política do bucket). Você está permitindo que o bucket seja acessado pelo Cloudfront, apesar do bucket estar configurado por padrão para não permitir acessos

  • Em Viewer, selecione Redirect HTTP to HTTPS (Redirecione acessos HTTP para HTTPS)

  • Em Web Application Firewall, selecione Do not enable security protections

Em Settings:

  • Em Alternate domain name, escolha Add item e preencha com seu subdomínio www.exemplo.com.br
  • Em Custom SSL certificate, escolha o certificado que você criou anteriormente.
  • Na caixa de texto Default root object (Objeto raiz padrão), digite index.html.

Aceite os valores padrão dos demais campos e escolha Criar distribuição.

Crie a distribuição

Espere alguns minutos até que a criação da CDN esteja concluída. Neste momento você já tem um endereço para acessar o seu novo site!

Clique na distribuição que você criou, em General você irá ver Distribution domain name, copie o endereço e cole no seu navegador para visualizar o site.

Passo 7: Crie uma CDN na AWS Cloudfront para o bucket secundário

Esse passo não é necessário se você vai usar um redirecionador de exemplo.com.br para www.exemplo.com.br.
Caso você tenha optado por usar o Route53 para administrar o DNS do domínio, você precisará executar as instruções abaixo.

Agora vamos criar uma CDN para que possamos acessar o site sem o www.

Ao criar uma nova distribuição e selecionamos como Origin domain o valor <nome do domínio sem www>.s3.us-east-1.amazonaws.com, vamos receber um alerta:

This S3 bucket has static web hosting enabled. If you plan to use this distribution as a website, we recommend using the S3 website endpoint rather than the bucket endpoint.

Como criamos o bucket com a funcionalidade de hospedagem de sites habilitada, ele nos avisa que é melhor usar o endpoint de site do que o endpoint de bucket. Vamos aceitar a sugestão clicando em Use website endpoint. Observe que o Origin Domain irá mudar para exemplo.com.br.s3-website-us-east-1.amazonaws.com.

Use as configurações padrão que já estão selecionadas, exceto nas seguintes:

  • Viewer protocol policy: selecione Redirect HTTP to HTTPS
  • Cache policy and origin request policy (recommended): selecione CachingDisabled
  • Web Application Firewall (WAF), selecione Do not enable security protections
  • Alternate domain name (CNAME) - optional, selecione o domínio raíz da sua URL (exemplo.com.br)
  • Custom SSL certificate - optional, selecione o certificado que você criou anteriormente

Passo 8: Configure o Registro.br para que ele redirecione para o Cloudfront

Caso você tenha optador por usar um redirecionador para redirecionar de exemplo.com.br para www.exemplo.com.br, a configuração DNS do Registro.br ficará assim:

  • Registro A com o valor de exemplo.com.br para o IP indicado pelo redirecionador de sites
  • Registro CNAME que valida o uso do certificado SSL criado pelo AWS Certificate Manager
  • Registro CNAME para www.exemplo.com.br que aponta para o endereço do Cloudfront ligado ao bucket principal

Caso você tenha optado por usar o AWS Route53 para evitar redirecionamentos, ao criar a hosted zone no Route53, você irá receber 4 endereços dos servidores da AWS. Clique em Alterar servidores DNS no Registro.br e coloque os endereços nos campos indicados.

A partir deste momento, a administração de DNS do domínio passará do Registro.br para o painel do Route53. Veja as instruções de como configurar o DNS no tutorial da AWS.

Conclusão

Parabéns! Você criou um site estático na AWS! Ele tem um desempenho excelente, mas com um custo mensal bem pequeno.
Você pode incrementar seu site, fazendo com que ele converse com uma API, adicionando formulários ou integrando um CMS para que outras pessoas possam adicionar conteúdo sem precisar escrever código.

Próximos passos:

  • Veja os números de desempenho do site no PageSpeed e no GTmetrix
  • Veja custos do AWS Cloudfront e AWS S3 para verificar como qual será seus custos
  • Use tag do Next.js, com alguns passos adicionais
  • Crie um formlário e receba as respostas em um e-mail usando o W3Forms
Carregando publicação patrocinada...
3

Parabéns pela publicação, bem detalhada e mostrando todos os pontos.

Eu só fico com o pé atrás de usar um serviço assim pois a AWS é "Pay as you go", então você só paga pelo que usar, mas isso pode ser uma armadilha tb.

Digamos que alguém faça um ataque de DDoS, eles não vão derrubar nenhum servidor, pois estão batendo diretamente na AWS, mas isso pode fazer seu numero de solicitações de leitura pro S3 aumentar, seu custo de transferência de arquivos, etc, e tudo isso vai gerar um custo em sua infra grátis.

O que quero chamar a atenção é que temos que pensar que podem acontecer coisas assim, e temos que por travas de limite, para não termos sustos na fatura do cartão.

As vezes é bom que uma aplicação caia, e não saia escalando infinitamente gerando custos absurdos, só temos que estar preparados.

Comento isso baseado nesse topico:

2

Você tocou em um ponto importante e antes de começar a usar a AWS fiquei um bom tempo pesquisando a respeito, pois sou noiado com contas. Esse tipo de ataque que você descreveu é classificado como "denial of wallet", pois é um ataque financeiro.

Na AWS existe o AWS Shield Standard, que já vem habilitado por padrão quando se usa CloudFront e ele já identifica e protege contra ataques DoS. Então não é tão simples fazer um ataque:

https://docs.aws.amazon.com/pt_br/waf/latest/developerguide/ddos-event-mitigation.html

Um passo simples, mas importante quando se usa AWS, é criar alertas para diferentes custos no AWS Budgets. Um alerta para um valor um pouco acima da média da mensalidade da AWS, outra para $5 a mais, uma outra maior e assim por diante. Esses alertas podem ser na forma de um e-mail ou até SMS. Inclusive é posssível configurar limites para verificar se o free tier não será ultrapassado. A AWS é falha nesse sentido, pois por padrão não vem configurado nenhum tipo de alerta para custos.

Se você quer dormir tranquilo mesmo, existe a possibilidade de configurar uma ação no AWS Budgets para impedir que a mensalidade chegue a um custo que seria inaceitável, digamos 20 dólares. Essa ação vai desabilitar a distribuição do Cloudfront, impossibilitando continuar um ataque. Mas o site ficará indisponível também.

Esse tipo de ataque de Denial of Service também implica em um custo para o atacante, tanto de tempo como de oportunidade, então um blog pessoal ou o site da pizzaria de bairro provavelmente não vão ter alguém tão dedicado a ponto de gastar recursos para um ataque, mas quando falamos de um site corporativo ou se você tem inimigos pessoais, realmente é necessário montar um plano para lidar com essas situações.

1
1
1

Eu tentei usar o Amplify, mas tive uma experiência péssima com ele. Depois de ter gastado um bom tempo entendendo sobre ele, de criar toda a aplicação e dar deploy, descobri que ele tem um problema de cold start (quando o Lambda fica dormente após ficar sem atividade e precisa ser "acordado" quando entra uma requisição). Basicamente o site demorava 15 segundos para carregar, completamente inaceitável.

https://github.com/aws-amplify/amplify-hosting/issues/3855

Outra coisa é que o site ficou muito pesado, carregando arquivos js muito grandes, apesar de ser bem enxuto e praticamente sem nenhum recurso avançado. Isso foi parcialmente resolvido com as atualizações do Amplify.

Apesar de terem criado algumas gambiarras para o cold start, como ficar enviando solicitações a cada X tempo, ou algumas atualizações por parte do Amplify, nenhum deles resolveu o problema. Os desenvolvedores que estavam usando o Amplify estavam arrancando os cabelos, mas não teve nenhuma solução.

1

Eu tenho aplicação rodando nele em produção e não tenho problemas. quanto ao cold start do lambda, é configurável. Mas para o que você propôs não precisa de lambda.

1

Eu havia criado o projeto pela promessa do Amplify de facilitar o desenvolvimento, integrando diversos serviços da AWS de forma simples, mas a falta de suporte e de uma resolução da AWS mesmo depois de meses e de diversos issues abertos me fizeram desistir de continuar usando ele. Eu entendo que o Amplify não é um projeto prioritário para a AWS, que é focado em infra. Daí a falta de prioridade.

Para criar uma página estática eu entendo que o Amplify seria subutilizado, só iria aumentar complexidade e o tamanho do payload JS, sem facilitar muito o processo de desenvolvimento. Lembrei também dos problemas que surgiam quando se tentava usar o Next.js e o App router e falta de atualizações para resolver isso por parte da Amplify.

O cold start infelizmente era um problema ligado às bibliotecas do Amplify, não era um problema simples.

1
0
2

O problema da Vercel é que eles não permitem usos comerciais no plano free:

https://vercel.com/docs/limits/fair-use-guidelines#commercial-usage

Claro que dá para ficar usando até eles descobrirem, te darem um ultimato ou derrubarem as páginas, mas não quero ter esse tipo de risco, ainda mais se estou hospedando páginas de clientes.

O plano Pro deles, que começa nos $20/mês é bem salgado. Eu conseguiria fazer MUITO mais na AWS com esse valor. E no final das contas a Vercel usa a infraestrutura da AWS, então por quê não comprar direto no fornecedor?

1
1
1

Tenho uma dúvida:
Quando tentei utilizar o cloudfront com um dominio personalizado, precisei personalizar o certificado ssl para permitir o https. Isso impactou em uma cobrança que é bem expressiva, que cobra até mesmo independente do tráfego.

Eu que fiz algo de errado, o serviço mudou ou o que?

obrigado, desde já.

2

Acredito que você fez alguma coisa diferente. Os certificados públicos emitidos pela AWS Certificate Manager são gratuitos. Mas se você optou por um certificado privado, eles são pagos (e caros). Veja no site da AWS se foi isso que você fez.

A não ser que você tenha que faça parte de uma grande empresa, não existe necessidade de usar um certificado privado.

1

Já parou para pensar que daria para fazer usando NextJS e Github Pages? e sim totalmente de graça até com dominio proprio? Eu pensei e pratiquei isso esses dias foi tranquilo de fazer, só que só vale para sites estáticos obviamente.

2
1