Как запустить Discourse в Apache vhost, а не в Nginx

Кто-нибудь успешно настроил Discourse, работающий на виртуальном хосте Apache, вместо стандартного Nginx?

Похоже, что большинство обсуждений об Apache на этих форумах касается запуска Discourse на хосте, где уже работает Apache. В каждом случае, который я видел, люди просто проксируют Apache обратно на Nginx. Чтобы было ясно: я хочу, чтобы контейнер Docker с бэкендом Discourse запускал виртуальный хост в Apache, а не в Nginx.

В частности, я надеюсь запустить бэкенд Discourse в Apache вместо Nginx, чтобы включить mod_security. Настройка Nginx с mod_security требует компиляции Nginx из исходного кода — сложности, которой я хотел бы избежать.

Мой текущий продакшн-сервер уже обслуживает несколько сайтов (WordPress, MediaWiki и т. д.). Мы используем Nginx для завершения HTTPS и базовой защиты от DoS-атак с ограничением частоты запросов → кэш Varnish → бэкенд Apache с mod_security. Если возможно, я хотел бы сохранить эту архитектуру для Discourse — с контейнером Docker бэкенда Discourse, работающим на Apache с mod_security, а не на Nginx.

Кто-нибудь успешно настроил запуск Discourse в Apache?

Извините, я новичок в Docker. У меня большие трудности с тем, чтобы понять, как файл ‘/etc/nginx/conf.d/discourse.conf’ вообще попадает в контейнер Docker. Не могли бы вы разъяснить шаги того, как этот файл генерируется и размещается в контейнере с помощью скрипта ‘./launcher’?

РЕДАКТИРОВАНИЕ: подождите, разве Nginx уже компилируется из исходного кода в Discourse?

Нет, не удавалось. Discourse довольно тесно интегрирован с nginx. Заменить его на Apache будет сложно или даже невозможно. А так как вы будете единственным, кто это делает, никто другой не будет волноваться, если что-то сломается.

Просто используйте Docker-контейнер, который использует каждый на планете, и поставьте Apache перед ним, если считаете, что это как-то повысит безопасность.

Кажется, так и есть.

Похоже, что /etc/nginx/conf.d/discourse.conf генерируется в контейнере на основе шаблона /var/docker/templates/web.template.yml — он копирует его из $home/config/nginx.sample.conf, а затем вносит изменения с помощью блоков replace в YAML (которые далее обновляются в последующих шаблонах, например, в templates/web.socketed.template.yml).

Я предполагал, что файл nginx.sample.conf просто устанавливается в контейнер nginx при компиляции из исходного кода в image/base/install-nginx, но единственный найденный мной файл nginx.sample.conf в контейнере (/var/www/discourse/config/nginx.sample.conf) уже содержал специфичные для Discourse директивы.

Откуда берётся файл nginx.sample.conf?

Я бы предпочел избежать цепочки nginx > varnish > apache > nginx :slight_smile:

Чтобы прояснить: вы считаете, что мне безопаснее обновить скрипт ‘image/base/install-nginx’ для компиляции nginx в Docker-контейнере Discourse с поддержкой mod_security, чем обновлять контейнер для запуска vhost Discourse за Apache (вместо Nginx)? Если да, каковы риски изменения скрипта install-nginx? Как это может сломать мою установку Discourse в будущем?

PSA: Всё, что вы предлагаете сделать, технически возможно, но полностью не поддерживается. Мы не можем разумно поддерживать все возможные комбинации, которые люди придумывают для развёртывания Discourse в вебе. Поэтому поддержка на этом форуме ограничена установками, следующими руководству discourse/docs/INSTALL-cloud.md at main · discourse/discourse · GitHub.

discourse/config/nginx.sample.conf at main · discourse/discourse · GitHub

В конечном счёте это всё равно сломается множеством способов. Вам придётся постоянно сливать изменения из основной ветки и поддерживать свой форк вечно.

Отлично, спасибо! Ух ты, это совершенно другой репозиторий. Как контейнер получает этот файл из другого репозитория? Вот здесь?

А что такое $home?

Вы можете просмотреть исходный код и найти всё это и многое другое по адресу discourse_docker/image/base/Dockerfile at master · discourse/discourse_docker · GitHub

Я настроил файл app.yml (Discourse) следующим образом:
expose:
- "2045:80" # http
- "8443:443" # https

.. а мой vhost — так:
<VirtualHost *myhostIP*:443>
ServerName forum.domain.org
ServerAlias forum.domain.org
...
ProxyAddHeaders Off
ProxyPass / "http://localhost:2045/"
ProxyPassReverse / "http://localhost:2045/"
</VirtualHost>

Надеюсь, я правильно понял ваш вопрос :blush:

@ledimeo Это именно то, что предложил @pfaffman, и я считаю, что в данном случае это лучший вариант, чтобы в будущем при выпуске новых версий не возникало серьезных проблем. Однако, похоже, что он уже использует другой nginx в качестве фронтенд-прокси, и не хочет:

Тем не менее, я считаю, что проксирование apache через nginx (даже если в итоге получится четыре уровня) будет как минимум более поддерживаемым решением, чем попытка изменить способ работы Discourse в официальной установке.

Для этой цели вам в основном следует считать, что nginx находится внутри «чёрного ящика» Docker-контейнера, и не беспокоиться о нём.

Итак: nginx → varnish → apache → Discourse (включающий nginx и unicorn)

(за исключением настройки доверия к IP-адресам прокси-серверов вышестоящего уровня)

Таким образом, использование Apache в качестве прокси для nginx Discourse — определённо возможный вариант.

Я согласен с тем, что преимуществом профессионального подхода является упрощение будущих обновлений, и это важный аргумент.

Однако добавление ещё одного звена в архитектуру не только усложнит отладку проблем в будущем, но и вызывает у меня опасения относительно производительности Apache в качестве прокси для веб-приложения, использующего long polling, как отмечал @sam в этом посте от 2016 года.

Я в целом предпочитаю nginx Apache, за исключением случая с mod_security. Было бы замечательно, если бы репозитории ОС включали пакеты для включения mod_security в nginx, как это сделано для Apache, но на данный момент включение mod_security в nginx требует компиляции nginx из исходного кода как в RHEL/CentOS, так и в Debian. А я избегаю зависимости от пакетов, скомпилированных из исходного кода, на производственных серверах как чумы.

Касательно: я немного изучил скрипт install-nginx и обнаружил небольшую логическую ошибку: строка очистки, которая должна удалять исходный код nginx из /tmp/, на самом деле ничего не делает.

Директории /tmp/nginx/ не существует: она называется /tmp/nginx-$VERSION/ (в данный момент это /tmp/nginx-1.17.4/, также есть архив /tmp/nginx-1.17.4.tar.gz).

Думаю, вы имели в виду следующее:

rm -fr /tmp/nginx-${VERSION}*

К сожалению, мой обновленный скрипт /var/discourse/image/base/install-nginx не выполняется при запуске команды /var/discourse/launcher destroy app && /var/discourse/launcher/rebuild app.

Есть ли какая-то причина, по которой команда rebuild не переисполняет обновленный скрипт install-nginx?

Как вы вносите изменения в скрипт после пересборки? С помощью хука?

vim /var/discourse/image/base/install-nginx

После пересборки вы всё ещё можете увидеть свои изменения? Прямое редактирование файлов внутри образа не сработает.

Вам нужно использовать хуки, чтобы изменить файл из вашего app.yml.

Вы раньше работали с Docker?

Если вы не знакомы с Docker, этот путь будет сложным…

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

Хорошо. Ну, я соврал насчёт vim для простоты. На самом деле я запускаю эти команды для идемпотентного и надёжного обновления скрипта:

cd /var/discourse/image/base
cp install-nginx install-nginx.`date "+%Y%m%d_%H%M%S"`.orig

# добавить блок для проверки модуля modsecurity nginx непосредственно перед загрузкой исходного кода nginx
grep 'ModSecurity' install-nginx || sed -i 's%\(curl.*nginx\.org/download.*\)%# mod_security --maltfield\napt-get install -y libmodsecurity-dev modsecurity-crs\ncd /tmp\ngit clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git\n\n\1%' install-nginx

# обновить строку configure, чтобы включить модуль ModSecurity, проверенный выше
sed -i '/ModSecurity/! s%^[^#]*./configure \(.*nginx.*\)%#./configure \1\n./configure \1 --add-module=/tmp/ModSecurity-nginx%' install-nginx

# добавить строку в раздел очистки
grep 'rm -fr /tmp/ModSecurity-nginx' install-nginx || sed -i 's%\(rm -fr.*/tmp/nginx.*\)%rm -fr /tmp/ModSecurity-nginx\n\1%' install-nginx

Где мне разместить эти команды, чтобы был изменён фактический скрипт install-nginx, используемый контейнером при загрузке?