Обходной путь для страницы технического обслуживания — можно ли это сделать?

Я использую двухконтейнерную сборку за CDN Cloudflare. Двухконтейнерная схема минимизирует время простоя, и оба моих основных рабочих форума имеют максимум 30 секунд недоступности во время пересборки. Мне нравится иметь страницу технического обслуживания, потому что стандартная страница «веб-сервер недоступен» выглядит некрасиво и не дает никаких подсказок о том, как долго сайт будет недоступен.

Например, для сайта your-domain.com я просто использую маршрут Cloudflare Workers, настроенный на *yourdomain.com/* (включая звездочки).

Шаг 1: Создание страницы Workers

Вы можете настроить страницу технического обслуживания на странице настроек Workers & Pages в Cloudflare — нажмите кнопку Create application:

Затем используйте шаблон Hello World:

Затем дайте ему имя и нажмите Deploy:

Затем перейдите на страницу обзора для этой страницы технического обслуживания и нажмите Edit code:

И вставьте этот код в окно кода worker.js (замените ваш домен и любое сообщение, которое вы хотите, отредактируйте текст, цвет текста, фон и т.д.):

export default {
  async fetch(request, env, ctx) {
    try {
      // Получаем исходный запрос с вашего сервера
      const response = await fetch(request);

      // Если ВАШ САЙТ переключает контейнеры, он выдает ошибку 502, 521 или 530
      if (response.status === 502 || response.status === 521 || response.status === 530) {
        return returnCustomErrorPage();
      }

      // Если все в порядке, возвращаем обычный трафик форума
      return response;
    } catch (e) {
      // Если сервер полностью недоступен
      return returnCustomErrorPage();
    }
  }
};

function returnCustomErrorPage() {
  const html = `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Обновление системы - 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>Короткое окно обновлений</h1>
        <p><strong>YOUR-SITE</strong> проходит быстрое обновление системы, которое займет около 30 секунд.</p>
        <p>Сделайте глоток напитка — эта страница автоматически обновится, как только мы вернемся в онлайн.</p>
      </div>
      <script>
        // Автоматически проверяет, вернулся ли сайт в онлайн, каждые 10 секунд
        setInterval(function() {
          window.location.reload();
        }, 10000);
      </script>
    </body>
    </html>
  `;

  return new Response(html, {
    status: 503, // 503 лучше для SEO, чтобы Google не наказывал вас за простой
    headers: {
      "Content-Type": "text/html;charset=UTF-8",
      "Retry-After": "30"
    }
  });
}

Это должно выглядеть примерно так. Нажмите Deploy, чтобы сохранить:

Шаг 2: Добавление маршрута

Теперь перейдите на страницу маршрутов Cloudflare Workers и нажмите кнопку Add route, чтобы открыть модальное окно нового маршрута, введите маршрут домена и выберите страницу Workers, которую вы только что создали, затем нажмите Save:

Шаг 3: Запуск обновлений или пересборок

Теперь, когда вы подключаетесь к серверу через SSH и запускаете системные обновления или пересборку, вместо страницы «сайт недоступен» или ошибки, эта страница будет показываться, когда на самом деле происходит простой (я использую 30 секунд в своем, потому что это максимум для моих сайтов)

Я склонен добавлять и удалять маршрут Workers, когда выполняю техническое обслуживание, но некоторые предпочитают просто оставить его там все время (я оставляю фактический код для страницы, я просто добавляю и удаляю маршрут).

Думаю, это все.

Дополнительно: Запуск обновлений с помощью скрипта и расписания

Я также использую shell-скрипт Unix на своем сервере для запуска обновления, специфичного для двух контейнеров, который я создал следующим образом:

cat << 'EOF' > /root/update-web.sh
#!/bin/bash
cd /var/discourse
echo "➡️ Загрузка последних скриптов Docker Discourse..."
git pull

echo "➡️ Инициализация нового веб-контейнера в фоновом режиме (занимает ~8 мин)..."
./launcher bootstrap web_only

if [ $? -eq 0 ]; then
    echo "✅ Инициализация успешна! Переключение контейнеров..."
    ./launcher destroy web_only && ./launcher start web_only
    echo "🚀 Готово! Сайт обновлен с почти нулевым простоем."
else
    echo "❌ Инициализация не удалась! Отмена переключения, чтобы текущий сайт остался в сети."
fi
EOF

chmod +x /root/update-web.sh

Затем я запускаю его в командной строке root на моем сервере командой ./update-web.sh.


:warning: примечание: не выполняйте шаги ниже, если у вас нет платной учетной записи Cloudflare.

Вы можете автоматизировать это на определенное время, например, на 1 час ночи по вашему местному времени с помощью cron-задачи. Для меня 1:00 ночи по местному времени — это 8:00 утра по UTC, (вы можете узнать UTC-дату вашего сервера, введя date в командной строке при подключении через SSH).

Итак:

Выполните эту команду, чтобы открыть планировщик задач вашего сервера:

crontab -e

(если он попросит вас выбрать редактор, выберите предпочитаемый редактор, 1 для nano, вероятно, самый простой)

Я прокручиваю до конца комментариев и вставляю это:

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

(что означает запуск файла /root/update-web.sh в 0 минут, 8 часов (UTC), каждое воскресенье утром)

Затем сохраните и выйдите (если вы используете nano):

  1. Ctrl + O для сохранения.
  2. Enter для подтверждения.
  3. Ctrl + X для выхода.

Тогда я могу запустить cat /var/log/discourse-update.log, когда просыпаюсь по воскресным утрам, чтобы проверить, выполнилась ли задача правильно. Если вы используете планировщик задач cron, то вам нужно оставить маршрут страницы Workers.

Думаю, это все. Дайте знать, если у вас есть вопросы, ха-ха. Это намного проще, чем я сделал это кажущимся, ха-ха. :grin: