Cómo ejecutar Discourse en vhost de Apache, no en Nginx

¿Alguien ha configurado con éxito Discourse ejecutándose en un vhost de Apache, en lugar del nginx predeterminado?

Parece que la mayoría de las conversaciones sobre Apache en estos foros se refieren a ejecutar Discourse en un host que ya ejecuta Apache. En cada caso que he visto, las personas simplemente hacen que Apache proxye hacia atrás a nginx. Para ser claro: quiero que el contenedor backend de Docker que ejecuta Discourse ejecute el host virtual en Apache, no en Nginx.

Específicamente, espero ejecutar el backend de Discourse en Apache en lugar de Nginx para habilitar mod_security. Configurar Nginx con mod_security requiere compilar Nginx desde el código fuente, una complejidad que me gustaría evitar.

Mi servidor de producción actual ya ejecuta varios sitios (WordPress, MediaWiki, etc.). Usamos Nginx para terminar HTTPS y realizar una limitación básica de tasa de DOS → caché Varnish → backend Apache con mod_security. Si es posible, me gustaría mantener esta arquitectura para Discourse, con el contenedor Docker backend de Discourse ejecutando Apache con mod_security, no Nginx.

¿Alguien ha configurado con éxito Discourse para que se ejecute en Apache?

Lo siento, soy nuevo en Docker. Me está costando mucho entender cómo se coloca el archivo ‘/etc/nginx/conf.d/discourse.conf’ en el contenedor de Docker. ¿Alguien podría explicar los pasos para generar ese archivo y colocarlo en el contenedor mediante el script ‘./launcher’?

EDITO: espera, ¿ya está compilando Nginx desde el código fuente Discourse?

No, nadie lo ha hecho. Discourse está bastante estrechamente vinculado a nginx. Sería difícil, si no imposible, reemplazarlo con Apache. Y dado que serías la única persona intentándolo, a nadie más le importará cuando falle.

Simplemente usa el contenedor Docker que usa todo el mundo y coloca Apache delante si crees que eso mejorará la seguridad de alguna manera.

Parece que sí.

Parece que /etc/nginx/conf.d/discourse.conf se genera dentro del contenedor a partir del archivo de plantilla /var/docker/templates/web.template.yml, el cual lo copia en su lugar desde $home/config/nginx.sample.conf y luego realiza modificaciones mediante los bloques replace de YAML (los cuales se actualizan aún más en plantillas posteriores, como templates/web.socketed.template.yml).

Asumía que el archivo nginx.sample.conf se instalaba directamente por nginx al compilar desde el origen en image/base/install-nginx, pero el único archivo nginx.sample.conf que encontré en el contenedor (/var/www/discourse/config/nginx.sample.conf) ya contenía directivas específicas de Discourse.

¿De dónde proviene nginx.sample.conf?

Prefiero no tener nginx → varnish → apache → nginx :slight_smile:

Para aclarar: ¿crees que sería más seguro para mí actualizar el script ‘image/base/install-nginx’ para compilar nginx en el contenedor Docker de Discourse con soporte de mod_security, en lugar de actualizar el contenedor para ejecutar el vhost de Discourse detrás de Apache (en lugar de Nginx)? De ser así, ¿cuáles son los riesgos de modificar el script install-nginx? ¿Cómo podría romper mi instalación de Discourse en el futuro?

AVISO: Todo lo que estás proponiendo hacer, aunque técnicamente es factible, no tiene soporte. No podemos razonablemente dar soporte a cada combinación posible que se les ocurra a las personas para servir Discourse en la web. Por lo tanto, el soporte en este foro se limita a instalaciones que sigan la guía discourse/docs/INSTALL-cloud.md at main · discourse/discourse · GitHub.

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

Eventualmente, se romperá de muchas maneras. Tendrás la responsabilidad de fusionar continuamente los cambios aguas arriba y mantener tu bifurcación para siempre.

Perfecto, ¡gracias! Vaya, es un repositorio totalmente diferente. ¿Cómo obtiene el contenedor ese archivo del otro repositorio? ¿Está aquí?

¿Y qué es $home?

Puedes leer el código fuente para encontrar todo eso y más en discourse_docker/image/base/Dockerfile at master · discourse/discourse_docker · GitHub

Resolví configurando app.yml (Discourse) de la siguiente manera:
expose:
- "2045:80" # http
- "8443:443" # https

… y mi vhost así:
<VirtualHost *myhostIP*:443>
ServerName forum.domain.org
ServerAlias forum.domain.org

ProxyAddHeaders Off
ProxyPass / "http://localhost:2045/"
ProxyPassReverse / "http://localhost:2045/"
</VirtualHost>

Espero no haber malinterpretado tu pregunta :blush:

@ledimeo Eso es lo que sugirió @pfaffman, y lo que creo que sería mejor en este caso, para no romper las cosas gravemente en el futuro cuando se lancen nuevas versiones. Pero parece que ya utiliza otro nginx al frente como proxy inverso y no quiere:

Dicho esto, creo que hacer proxy de apache a nginx (incluso si eso terminara con esas 4 capas) sería al menos más mantenible que intentar cambiar la forma en que funciona Discourse en la instalación oficial.

Para este propósito, deberías principalmente fingir que nginx está dentro de la “caja negra” del contenedor de Docker y no preocuparte por ello.

Así que: nginx → varnish → apache → Discourse (compuesto por nginx y unicorn)

(excepto para configurarlo para que confíe en las IPs de los proxies aguas arriba)

Así que agregar Apache como proxy al nginx de Discourse es definitivamente una opción.

Estoy de acuerdo en que un profesional facilitaría las futuras actualizaciones, y ese es un punto importante.

Sin embargo, agregar otro salto a la arquitectura no solo complicaría la depuración de problemas en el futuro; también tengo preocupaciones sobre el rendimiento de Apache como proxy para una aplicación web que utiliza polling largo, como señaló @sam en esta publicación de 2016.

Generalmente prefiero nginx a Apache, excepto cuando se trata de mod_security. Sería fantástico si los repositorios del SO incluyeran paquetes para habilitar mod_security en nginx, como lo hacen para Apache, pero actualmente habilitar mod_security en nginx requiere compilar nginx desde el origen tanto en RHEL/Cent como en Debian. Y evito depender de paquetes compilados desde el origen en producción como la peste.

relacionado: He estado revisando el script install-nginx y encontré un pequeño error de lógica: la línea de limpieza que debería eliminar el código fuente de nginx de /tmp/ en realidad no hace nada.

No existe el directorio /tmp/nginx/: es /tmp/nginx-$VERSION/ (en este momento es /tmp/nginx-1.17.4/ y también está el archivo tarball /tmp/nginx-1.17.4.tar.gz).

Creo que te refieres a esto en su lugar:

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

Desafortunadamente, mi script actualizado /var/discourse/image/base/install-nginx no parece ejecutarse cuando ejecuto /var/discourse/launcher destroy app && /var/discourse/launcher rebuild app.

¿Hay alguna razón por la que este comando rebuild no vuelva a ejecutar el script install-nginx actualizado?

¿Cómo estás modificando el script después de la reconstrucción? ¿Con un hook?

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

Después de una reconstrucción, ¿sigues viendo tus cambios? Editar archivos directamente en la imagen no funcionará.

Debes usar hooks para modificar el archivo desde tu app.yml

¿Has trabajado con Docker antes?

Si no estás familiarizado con Docker, este será un camino difícil…

discourse_docker contiene el código fuente de nuestra imagen base de Docker que reside en el registro público de Docker, y que nunca se ejecutará localmente. La razón de todo esto es tener una imagen reutilizable.

ok. Bueno, mentí sobre vim para simplificar. En realidad, estoy ejecutando estos comandos para actualizar el script de forma idempotente y robusta

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

# agregar un bloque para verificar el módulo nginx de modsecurity justo antes de descargar el código fuente de 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

# actualizar la línea de configuración para incluir el módulo ModSecurity verificado anteriormente
sed -i '/ModSecurity/! s%^[^#]*./configure \(.*nginx.*\)%#./configure \1\n./configure \1 --add-module=/tmp/ModSecurity-nginx%' install-nginx

# agregar una línea a la sección de limpieza
grep 'rm -fr /tmp/ModSecurity-nginx' install-nginx || sed -i 's%\(rm -fr.*/tmp/nginx.*\)%rm -fr /tmp/ModSecurity-nginx\n\1%' install-nginx

¿Dónde debería colocar estos comandos para que se modifique el script real install-nginx utilizado por el contenedor durante el arranque?