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

Да, я бы сделал это поэтапно:

  1. взять немного более мощный сервер
  2. настроить установку двух контейнеров

если на этом этапе вы довольны результатом, остановитесь здесь, или:

  1. реализуйте страницу технического обслуживания, используя отличное руководство @Lilly, приведённое выше. :+1:

Ха-ха, я рад, что вы спросили, потому что я не удосужился объяснить эту часть (мне следовало это сделать — здесь есть что рассказать, и Cloudflare довольно сложен!).

Когда настроен маршрут для Workers, каждая загрузка изображения и просмотр страницы на форуме проходят через этого Worker.

Бесплатный тарифный план CDN от Cloudflare включает лимит в 100 000 запросов в день на маршрут Worker.

Таким образом, если у вас относительно загруженный форум, чтобы не исчерпать лимит бесплатного тарифа за один день, имеет смысл не держать этот маршрут включенным постоянно. Речь идет именно о маршруте Worker, а не о странице обслуживания — страницу обслуживания можно оставить включенной всё время; она не будет вызываться, пока не активирован маршрут Worker. Речь идет только о Шаге 2, где вы назначили маршрут (который легко настроить и удалить). Если вы не используете платный план Cloudflare, то хорошим тоном считается держать его включенным только во время проведения собственного обслуживания.

  1. Перейдите на страницу маршрутов Workers для вашего домена в Cloudflare и нажмите кнопку справа от маршрута.

  1. В нижней части экрана редактирования нажмите кнопку remove (удалить), чтобы отвязать страницу Worker от маршрута.

  1. Не волнуйтесь, сам код Worker не будет удален, только правило маршрутизации. В следующий раз, когда вы будете выполнять пересборку или обновление, вы сможете просто добавить его снова, как в Шаге 2 выше.

Если вы используете платный план Cloudflare, то вам не о чем беспокоиться. Однако в этом случае вы можете использовать страницы ошибок Cloudflare вместо страницы Workers… (Я уже упоминал, что Cloudflare довольно сложен? ЛОЛ).

:warning: ниже приведена расширенная конфигурация для администраторов

Если вы хотите полностью автоматизировать обновления на бесплатном плане, вам следует использовать токен API Cloudflare, ваш zone-id и команду curl, чтобы получить route id (идентификатор маршрута) для Workers. Затем отредактируйте скрипт /root/update-web.sh, добавив туда немного «веселой» логики для автоматического включения и выключения маршрута Worker:

#!/bin/bash
cd /var/discourse

CF_TOKEN="your_actual_token_here" #<---Токен API Cloudflare
ZONE_ID="xxxx" #<---Взят со страницы профиля Cloudflare
ROUTE_ID="xxxx"
WORKER_NAME="my-site-maintenance-page"

echo "➡️ Загрузка последних скриптов Docker Discourse..."
git pull

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

if [ $? -eq 0 ]; then
    echo "✅ Инициализация успешна!"
    
    # ВКЛЮЧАЕМ Worker для страницы обслуживания Cloudflare
    echo "🚧 Включение страницы обслуживания..."
    curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes/$ROUTE_ID" \
         -H "Authorization: Bearer $CF_TOKEN" \
         -H "Content-Type: application/json" \
         --data '{"pattern":"*your-site.com/*","script":"'$WORKER_NAME'"}' > /dev/null

    # Замена контейнеров (окно простоя 30 секунд)
    echo "🔄 Замена контейнеров..."
    ./launcher destroy web_only && ./launcher start web_only
    
    # ВЫКЛЮЧАЕМ Worker для страницы обслуживания Cloudflare
    echo "🌍 Отключение страницы обслуживания..."
    curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes/$ROUTE_ID" \
         -H "Authorization: Bearer $CF_TOKEN" \
         -H "Content-Type: application/json" \
         --data '{"pattern":"*your-site.com/*","script":null}' > /dev/null

    echo "🚀 Готово! Сайт обновлен без видимого простоя."
else
    echo "❌ Инициализация не удалась! Прерываем замену, чтобы текущий сайт оставался в сети."
fi 

Я использую предыдущую версию скрипта, потому что мне не хочется автоматизировать всё подряд, и мне нравится присутствовать при выполнении обновлений/пересборок. Я просто добавляю маршрут Workers прямо перед обновлением, а затем удаляю его после. Это занимает всего несколько секунд.

Мои общие шаги:

  1. Добавить маршрут Workers в Cloudflare
  2. Подключиться к Hetzner по SSH
  3. Выполнить системные обновления (например: sudo apt update && sudo apt upgrade -y, затем перезагрузить сервер, если необходимо)
  4. Подключиться по SSH снова, если была перезагрузка
  5. Запустить ./update-web.sh
  6. Удалить маршрут Workers в Cloudflare

Я совершенно не разбираюсь в программировании и мире разработки, если не считать одного единственного эксперимента с «Hello World» на Visual Basic, который я когда-то давно проводил. Однако я могу кое-что сделать, потому что лучше разбираюсь в администрировании своих серверов WordPress и Mastodon/Pixelfed, а также, как-никак, своего Discourse. Плюс есть такая штука, как ИИ (которая, кстати, для новичка оказывается не такой простой, как это рекламируется).

Я не знаю, возможно ли это в принципе в Discourse из-за Docker, но в обычном мире Nginx-Varnish-WordPress я создал систему, при которой сервер Plesk получает информацию об ошибках 50x и показывает страницу ошибки. На самом деле у меня есть три варианта настройки: фронтенд-сервер Nginx показывает сгенерированный снимок контента, если Varnish недоступен; Varnish начинает использовать снимок для некэшированного контента, если бэкенд, связанный с WordPress, недоступен; и третий вариант — страница ошибки, если фронтенд-сервер Nginx не отвечает.

Решения с Varnish не подходят для Discourse, но я не вижу причин, по которым нельзя было бы построить подобную «паутину» и в мире Docker, где любая ошибка 50x приводила бы к отображению страницы ошибки.

Хотя такая система могла бы быть очень подвержена ошибкам. И я совершенно не представляю, что произойдет, если пользователей будет больше, чем горсть.

К тому же есть самый очевидный ответ, конечно: использовать, например, Nginx перед Discourse. Я использовал такой подход, прежде чем перешел на двухконтейнерную конфигурацию.