Solução alternativa para página de manutenção - isso é possível?

Eu uso a construção de contêiner duplo atrás do CDN da Cloudflare. O contêiner duplo minimiza o tempo de inatividade e meus dois fóruns principais de produção têm no máximo 30 segundos offline durante as reconstruções. Gosto de ter uma página de manutenção porque a página padrão de servidor fora do ar é feia e não dá nenhuma dica sobre quanto tempo ela ficará offline.

por exemplo, para um site em your-domain.com eu simplesmente uso uma rota do Cloudflare Workers definida como *yourdomain.com/* (inclua os asteriscos).

Passo 1: Criar a página do worker

você pode configurar a página de manutenção na página de configurações workers & pages na Cloudflare - clique no botão create application:

então use o modelo hello world:

então dê um nome a ele e clique em deploy:

então vá para a página de visão geral dessa página de manutenção e clique em edit code:

e cole este código na janela de código worker.js (substitua seu domínio e qualquer mensagem que você quiser, edite o texto, a cor do texto, o fundo, etc):

export default {
  async fetch(request, env, ctx) {
    try {
      // Busca a solicitação original do seu servidor
      const response = await fetch(request);

      // Se SEU SITE estiver alternando contêineres, ele gera um 502, 521 ou 530
      if (response.status === 502 || response.status === 521 || response.status === 530) {
        return returnCustomErrorPage();
      }

      // Se tudo estiver bem, retorna o tráfego normal do fórum
      return response;
    } catch (e) {
      // Se o servidor estiver completamente inacessível
      return returnCustomErrorPage();
    }
  }
};

function returnCustomErrorPage() {
  const html = `
    <!DOCTYPE html>
    <html lang="pt-BR">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Atualização do Sistema - YOUR-SITE.com</title>
      <style>
        body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; text-align: center; padding: 50px; color: #333; background-color: #f9f9f9; }
        h1 { font-size: 2.5em; margin-bottom: 0.5em; color: #9400D3; }
        p { font-size: 1.2em; line-height: 1.5; }
        .container { max-width: 600px; margin: 0 auto; background: white; padding: 40px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
      </style>
    </head>
    <body>
      <div class="container">
        <h1>Apenas uma breve janela de atualização</h1>
        <p><strong>YOUR-SITE</strong> está passando por uma breve atualização de sistema de 30 segundos.</p>
        <p>Tomem um gole rápido da sua bebida — esta página será atualizada automaticamente assim que estivermos de volta online.</p>
      </div>
      <script>
        // Verifica automaticamente se o site está de volta a cada 10 segundos
        setInterval(function() {
          window.location.reload();
        }, 10000);
      </script>
    </body>
    </html>
  `;

  return new Response(html, {
    status: 503, // 503 é o melhor para SEO para que o Google não penalize você pelo tempo de inatividade
    headers: {
      "Content-Type": "text/html;charset=UTF-8",
      "Retry-After": "30"
    }
  });
}

deve ficar mais ou menos assim. clique em deploy para salvá-lo:

Passo 2: Adicionar a rota

agora vá para a página de rotas do Cloudflare worker e clique no botão add route para abrir o novo modal de rota, preencha a rota do domínio e selecione a página do worker que você acabou de criar, depois clique em salvar:

Passo 3: Executando atualizações ou reconstruções

agora, quando você fizer ssh no seu servidor e executar suas atualizações do sistema ou fizer uma reconstrução, em vez de uma página de site fora do ar ou erro, esta página será exibida quando o tempo de inatividade realmente ocorrer (eu uso 30 segundos no meu porque esse é o máximo para meus sites)

eu costumo adicionar e excluir minha página de rota de workers sempre que estou fazendo manutenção, mas alguns gostam de simplesmente deixá-la lá o tempo todo (eu deixo o código real da página, apenas adiciono e removo a rota).

acho que é isso.

Opcional: Executar atualizações com um script e agendar

eu também uso um script de shell unix no meu servidor para executar a atualização específica do contêiner duplo, que eu criei assim:

cat << 'EOF' > /root/update-web.sh
#!/bin/bash
cd /var/discourse
echo "➡️ Baixando os scripts mais recentes do Discourse docker..."
git pull

echo "➡️ Preparando novo contêiner web em segundo plano (leva ~8 mins)..."
./launcher bootstrap web_only

if [ $? -eq 0 ]; then
    echo "✅ Bootstrap bem-sucedido! Alternando contêineres..."
    ./launcher destroy web_only && ./launcher start web_only
    echo "🚀 Pronto! Site atualizado com quase zero tempo de inatividade."
else
    echo "❌ Bootstrap falhou! Abortando a alternância para manter o site atual online."
fi
EOF

chmod +x /root/update-web.sh

então eu o executo no prompt de root no meu servidor com o comando ./update-web.sh.


:warning: edição: não execute as etapas abaixo a menos que você tenha uma conta paga da Cloudflare.

você pode automatizá-lo para um horário específico, como 1 da manhã de domingo no seu horário local com um trabalho cron. para mim 1:00am local é 8:00 AM UTC, (você pode descobrir a data UTC do seu servidor digitando date no prompt de comando quando conectado via ssh).

então:

execute este comando para abrir o agendador de tarefas do seu servidor:

crontab -e

(se ele pedir para você escolher um editor, selecione seu editor preferido, 1 para nano é provavelmente o mais fácil)

eu rolo até o final dos comentários e colo isso:

0 8 * * 0 /root/update-web.sh >> /var/log/discourse-update.log 2>&1

(o que significa executar o arquivo /root/update-web.sh no minuto 0, hora 8 (UTC), toda manhã de domingo)

então salve e saia (se você estiver usando nano):

  1. Ctrl + O para salvar.
  2. Enter para confirmar.
  3. Ctrl + X para sair.

então eu posso executar cat /var/log/discourse-update.log quando acordo nas manhãs de domingo para verificar se ele foi executado corretamente. se você usar um agendador de tarefas cron, então você quererá deixar a rota da página de workers.

acho que é tudo. me avise se você tiver dúvidas rs. é muito mais simples do que eu fiz parecer rs. :grin: