Discourse + Let's Encrypt с несколькими именами хостов

При миграции (через резервную копию) Discourse с одного имени хоста на другое администратор может захотеть сохранить старое имя хоста, но настроить веб-сервер на переадресацию запросов к новому каноническому имени, например:

https://old.example.org/t/my-great-topic/12345 :arrow_heading_down:
https://new.example.org/t/my-great-topic/12345

К сожалению, это не так просто, как изменить запись CNAME или A в DNS: клиентский браузер выдаст ошибку или предупреждение, поскольку имя хоста не совпадает с именем в сертификате, сгенерированном установкой Discourse через Let’s Encrypt.

При ручной установке веб-сервера я бы использовал утилиту certbot для генерации сертификата с несколькими именами, назначенными ему. Однако конфигурация Discourse передаёт в Let’s Encrypt только имя хоста Discourse, и в конфигурации Discourse, насколько я вижу, нет понятия алиасов.

Кто-нибудь настраивал подобную схему или есть предположение, как лучше этого добиться? Думаю, это потребует некоторой доработки шаблонов SSL и Let’s Encrypt.

Не специфично для Discourse, но когда мне нужно перенаправление через HTTPS, я просто перенаправляю всё. То есть настраиваю сервер, который делает перенаправление со старого адреса на новый. Некоторые варианты хостинга берут это на себя в фоновом режиме, иногда это называют услугой «перенаправления домена» или «форвардинга».

Я даже больше не думаю об этом, потому что каждый раз, когда пробовал что-то другое, это было сплошное мучение. :thinking:

Discourse отвечает только на одно имя хоста. Если вам нужно несколько имён хостов — а ваш случай, поддержка предыдущего имени хоста, является наиболее распространённым, — тогда вам нужно перенаправлять одно имя на другое.

Я рекомендую делать это вне Discourse. Просто создайте конфигурацию nginx, которая будет иметь собственный сертификат, указывать server_name для старого имени хоста и перенаправлять все запросы на новое имя хоста.

На самом деле, если вы используете установку на базе Docker с одним экземпляром на сервер, она корректно обрабатывает любое количество записей DNS (nginx слушает порты 80 и 443 для всех имён хостов) и без проблем переписывает URL на каноническое «новое» имя хоста. Эта часть работает исправно и без проблем. (Те, кто склонен проверить это, могут добавить вымышленное доменное имя в файл localhost вашей машины и указать его на IP-адрес любого сайта Discourse.)

Единственная проблема, с которой я сталкиваюсь, — это предупреждение SSL, поскольку ответ переписывания от nginx приходит с https://old.example.org/foo и отправляет HTTP-перенаправление 302 на новый URL.

Я бы предпочел не поддерживать отдельный веб-сервер только для правила переписывания, если это возможно. :slight_smile:

Вам это не нужно, вам просто требуется дополнительный раздел server в вашей конфигурации.

Возможно, стоит заглянуть на Set up Let’s Encrypt with multiple domains / redirects

Обновление: Успешно настроено второе доменное имя на автономной установке и получен сертификат Let’s Encrypt для обработки как старого, так и нового имен.

Предварительное условие: я ещё не изменил DNS-записи, чтобы перенаправить пользователей на новый сайт; я хотел убедиться, что всё работает заранее. Поэтому я использовал запись localhost на своей тестовой машине. Это означало, что я не мог выполнить обычную проверку Let’s Encrypt и вместо этого должен был использовать метод «DNS» утилиты acme.sh, который обычно не рекомендуется, так как он не поддерживает автоматическое продление. Для меня это приемлемо, поскольку я переключусь в течение 30-дневного срока действия «первичного» (недавно выданного на два имени) сертификата.

  1. В моём файле web_only.yml (возможно, у вас app.yml) в секции hooks: и перед плагинами добавил следующее:
  after_ssl:
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d second-domain.com --keylength"
  1. В DNS создайте временную/фейковую TXT-запись для _acme-challenge.old.example.org с TTL 5 минут (можно установить и меньше) и дождитесь её распространения, чтобы быстро выполнить проверку с помощью acme.sh (Let’s Encrypt) с использованием ключа подтверждения.

  2. Остановите сайт и выполните отладочную (тестовую) проверку, чтобы система узнала о коротком TTL новой записи:

./launcher enter app
sv stop nginx
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf
LE_WORKING_DIR=/shared/letsencrypt DEBUG=1 /shared/letsencrypt/acme.sh --issue -d new.example.org -d old.example.org -k 4096 -w /var/www/discourse/public --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please --force
  1. Выполните запрос в реальном режиме без флага отладки. Вы получите предупреждение со значением, которое нужно использовать в DNS для записи, созданной на шаге 2:
LE_WORKING_DIR=/shared/letsencrypt /shared/letsencrypt/acme.sh --issue -d new.example.org -d old.example.org -k 4096 -w /var/www/discourse/public --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please --force
  1. Обновите DNS и подождите 5 минут. Да, стоит подождать всё это время, чтобы не столкнуться с ограничениями Let’s Encrypt.

  2. Выполните аналогичную команду, но в режиме renew:

LE_WORKING_DIR=/shared/letsencrypt /shared/letsencrypt/acme.sh --issue -d new.example.org -d old.example.org -k 4096 -w /var/www/discourse/public --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please --force --renew
  1. Вы должны получить подтверждение. Выполните следующие команды для очистки и установки нового сертификата:
LE_WORKING_DIR=/shared/letsencrypt /shared/letsencrypt/acme.sh --installcert -d new.example.org -d old.example.org --fullchainpath /shared/ssl/new.example.org.cer --keypath /shared/ssl/new.example.org.key --reloadcmd "sv reload nginx"
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop
exit
  1. Последний шаг, теперь когда вы вышли из лаунчера:
rm -rf /var/discourse/shared/standalone/ssl
rm -rf /var/discourse/shared/standalone/letsencrypt
./launcher rebuild app

После того как сайт снова заработает, он должен работать с новым сертификатом. Возможно, вам придётся очистить кэш сертификатов в браузере — это оставляем на ваше усмотрение и в помощь вашему любимому поисковику.

Спасибо тем, кто указал мне правильное направление!

Это идеальный вариант для правила Cloudflare — нулевая настройка сервера. Просто передайте те же параметры URL новому домену.

Для старого доменного имени необходимо включить оранжевое облако.

Да, ситуация с обратным прокси, подобная Cloudflare (или, предположим, вашему собственному выбранному обратному прокси перед сайтом Discourse), могла бы обойти это, реализовав правила переписывания «уровнем выше». В данном случае Cloudflare не был вариантом по соображениям безопасности и моральным причинам. :slight_smile:

(См. выше для автономного решения.)