Error de Bootstrap durante la instalación de Discourse: ENOENT - /etc/runit/1.d/letsencrypt

Hola, estoy intentando instalar Discourse usando el proceso estándar ./discourse-setup, pero me encuentro con un error durante el bootstrap:

FAILED
--------------------
Errno::ENOENT: No such file or directory @ rb_sysopen - /etc/runit/1.d/letsencrypt
Location of failure: /usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups/replace_command.rb:11:in `read'
replace failed with the params {"filename"=>"/etc/runit/1.d/letsencrypt", "from"=>"/--keylength/", "to"=>"-d forum.mysite.org --keylength"}
bootstrap failed with exit code 1
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.

Parece que el error es provocado por un plugin que intenta ejecutar un comando replace en el archivo /etc/runit/1.d/letsencrypt, que no existe dentro del contenedor durante el bootstrap. La línea relevante en el plugin se ve así:

- replace:
    filename: "/etc/runit/1.d/letsencrypt"
    from: "/--keylength/"
    to: "-d forum.mysite.org --keylength"

¿Algún consejo sobre cómo solucionar esto o regenerar adecuadamente el archivo faltante?

Gracias de antemano.

¿Un plugin? Ese es código de cups de tu app.yml, ¿verdad? ¿Estás intentando añadir otro certificado? Como en Set up Let’s Encrypt with multiple domains / redirects ¿Puedes incluir el código real y ambos certificados?

Como bien señalas, ese runit ya no existe, y ahora esa magia está en /usr/local/bin/letsencrypt (dentro del contenedor)

Creo que quizás quieras algo como esto si tu sitio es www.misitio.org y también quieres que tenga un certificado para foro.misitio.org:

- replace:
    filename: "/usr/local/bin/letsencrypt"
    from: "/-d www.misitio.org/"
    to: "-d www.misitio.org -d foro.misitio.org "
    global: true

Lo que yo haría (lo cual puede que no te sirva de ayuda) es entrar en el contenedor, apt update;apt install -y vim y luego editar /usr/local/bin/letsencrypt de tal manera que solicite los certificados que deseas.

Añadí código al tema de let’s encrypt enlazado arriba que debería permitirte introducir tu dominio y obtener código que puedes copiar/pegar en tu app.yml.

1 me gusta

He encontrado lo que parece ser el mismo mensaje de error durante un intento de actualización.

No estoy intentando cambiar nada relacionado con los certificados.

Mi archivo app.yml muestra esto actualmente:

 after_ssl:
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d www.nzarchitecture.net.nz --keylength"

Seguí tu sugerencia:

 apt update;apt install -y vim

pero el resultado fue: ‘vim ya es la versión más reciente (2:9.1.0016-1ubuntu7.8).’

En cuanto al segundo paso sugerido, no tengo idea de qué certificados quiero, ya que no tenía intención de cambiar nada.

OK, después de unas horas de esfuerzo, logré volver a ponerlo en marcha.

Encontré un archivo app.yml antiguo y lo sustituí, simplemente eliminando las referencias antiguas a plugins que desde entonces se han incorporado a Discourse.

Este archivo app.yml más antiguo no contenía el código que encontré en uno posterior.

 after_ssl:
    - replace:
        filename: "/etc/runit/1.d/letsencrypt"
        from: /--keylength/
        to: "-d www.nzarchitecture.net.nz --keylength"

No recuerdo haber puesto ese código yo mismo, aunque había configurado mi sitio para usar letsencrypt para los certificados de seguridad gratuitos, pero las instrucciones de Set up HTTPS support with Let's Encrypt no parecen requerir esas líneas en absoluto, así que no tengo idea de para qué habrían sido.

¿Podría algo más haber escrito esas líneas en app.yml? Por ejemplo, ¿podrían haberse agregado durante una actualización beta?

Al menos por ahora, con esas líneas eliminadas, mi sitio está funcionando de nuevo y actualizado.

Cuando mi certificado SSL actual expire, supongo que descubriré para qué eran esas líneas adicionales.

Bueno, sí lo estás haciendo, pero no lo recuerdas. :wink:

Si tienes esa sección after_ssl en tu archivo yml, entonces en algún momento configuraste las cosas de tal manera que si alguien ponía un www delante de tu dominio, iría a la dirección www y sería redirigido a la dirección sin www sin un error de certificado.

Mi sugerencia fue instalar vim dentro del contenedor e intentar manipular los archivos allí, pero creo que mi código para agregar a app.yml debería funcionar.

Correcto. Y ahora, si visitas https://www.nzarchitecture.net.nz/, obtendrás un error de certificado. Podrías usar https://forcewww.com/

Podrías ir al enlace de arriba y obtener el nuevo código que creo que debería funcionar, pero no lo he probado ya que no he encontrado un sitio que esté actualizando y lo necesite.

¿Es correcto que tu código sería algo como lo siguiente, si quiero que www.nzarchitecture.net.nz esté cubierto por el mismo certificado letsencrypt que nzarchitecture.net.nz?

after_ssl:
    - replace:
        filename: /usr/local/bin/letsencrypt
        from: /-d nzarchitecture.net.nz /
        to: "-d nzarchitecture.net.nz -d www.nzarchitecture.net.nz "
        global: true

Intenté añadir esta sección (¡excelente terminología, gracias!) al final de app.yml, en lugar de la sección ‘after_ssl:’ original, y ahora puedo reconstruir Discourse sin errores, pero esto no parece ayudarme; mi navegador todavía muestra una respuesta ‘net::ERR_CERT_COMMON_NAME_INVALID’ si intento usar un prefijo ‘www’ antes de mi dominio principal/certificado nzarchitecture.net.nz.

Mi app.yml completo a continuación, en caso de que ayude en algo (contraseña y direcciones de correo electrónico redactadas)

## esta es la plantilla de contenedor Docker de Discourse todo en uno y autónoma
##
## Después de realizar cambios en este archivo, DEBE reconstruir
## /var/discourse/launcher rebuild app
##
## ¡TENGA MUCHO CUIDADO AL EDITAR!
## ¡LOS ARCHIVOS YAML SON SÚPER SÚPER SENSIBLES A ERRORES DE ESPACIO EN BLANCO O ALINEACIÓN!
## visite http://www.yamllint.com/ para validar este archivo según sea necesario

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## Descomente estas dos líneas si desea añadir Lets Encrypt (https)
  - "templates/web.ssl.template.yml"
  - "templates/web.letsencrypt.ssl.template.yml"
  - "templates/import/mysql-dep.template.yml"

## ¿qué puertos TCP/IP debe exponer este contenedor?
## Si desea que Discourse comparta un puerto con otro servidor web como Apache o nginx,
## vea https://meta.discourse.org/t/17247 para más detalles
expose:
  - "80:80"   # http
  - "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## Establezca db_shared_buffers en un máximo del 25% de la memoria total.
  ## será configurado automáticamente por bootstrap según la RAM detectada, o puede anularlo
  db_shared_buffers: "128MB"

  ## puede mejorar el rendimiento de ordenación, pero aumenta el uso de memoria por conexión
  #db_work_mem: "40MB"

  ## ¿Qué revisión de Git debe usar este contenedor? (por defecto: tests-passed)
  #version: tests-passed

env:
  LANG: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## ¿Cuántas solicitudes web concurrentes se admiten? Depende de la memoria y los núcleos de CPU.
  ## será configurado automáticamente por bootstrap según las CPU detectadas, o puede anularlo
  UNICORN_WORKERS: 2

  ## TODO: El nombre de dominio al que responderá esta instancia de Discourse
  ## Requerido. Discourse no funcionará con un número IP desnudo.
  DISCOURSE_HOSTNAME: nzarchitecture.net.nz

  ## Descomente si desea que el contenedor se inicie con el mismo
  ## nombre de host (-h opción) que el especificado anteriormente (por defecto "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: Lista de correos electrónicos separados por comas que serán administradores y desarrolladores
  ## en el registro inicial ejemplo 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: '****************'

  ## TODO: El servidor de correo SMTP utilizado para validar nuevas cuentas y enviar notificaciones
  # Se requieren la DIRECCIÓN SMTP, el nombre de usuario y la contraseña
  # ADVERTENCIA: el carácter '#' en la contraseña SMTP puede causar problemas.
  DISCOURSE_SMTP_ADDRESS: smtp.mailgun.org
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: ****************
  DISCOURSE_SMTP_PASSWORD: "****************"
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (opcional, por defecto true)

  ## Si añadió la plantilla Lets Encrypt, descomente a continuación para obtener un certificado SSL gratuito
  LETSENCRYPT_ACCOUNT_EMAIL: ******************

  ## La dirección CDN http o https para esta instancia de Discourse (configurada para tirar)
  ## vea https://meta.discourse.org/t/14857 para más detalles
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

## El contenedor Docker no tiene estado; todos los datos se almacenan en /shared
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## Los plugins van aquí
## vea https://meta.discourse.org/t/19157 para más detalles
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-bbcode.git
## Cualquier comando personalizado para ejecutar después de la compilación
run:
  - exec: echo "Inicio de comandos personalizados"
  ## Si desea establecer la dirección de correo electrónico 'De' para su primer registro, descomente y cambie:
  ## Después de recibir el primer correo electrónico de registro, vuelva a comentar la línea. Solo necesita ejecutarse una vez.
  #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
  - exec: echo "Fin de comandos personalizados"

after_ssl:
    - replace:
        filename: /usr/local/bin/letsencrypt
        from: /-d nzarchitecture.net.nz /
        to: "-d nzarchitecture.net.nz -d www.nzarchitecture.net.nz "
        global: true

¿Es el hecho de que no haya archivos en /usr/local/bin/ parte del problema?

¿Dónde encuentro el archivo letsencrypt correcto para poner allí, si eso es lo que se necesita?

Y, si ‘letsencrypt’ es el nombre del archivo al final de esa ruta, ¿es normal que no haya una extensión de archivo como parte de este nombre de archivo?

Mi idea es eliminar la línea after_ssl y desindentar las otras.

Si agregas mi clave ssh con

ssh-import-id-gh pfaffman

Y me envías un correo electrónico, veré qué puedo hacer.

¡Gracias! @pfaffman

Acabo de enviarte un correo electrónico.

Aquí tienes una actualización.

Añadir esto a la sección run al final de tu app.yml resolverá el problema de conseguir que /usr/local/bin/letsencrypt solicite certificados para DISCOURSE_HOSTNAME y www.DISCOURSE_HOSTNAME.

- exec: sed -i "s|-d \\${DISCOURSE_HOSTNAME}|-d \\${DISCOURSE_HOSTNAME} -d www.\\${DISCOURSE_HOSTNAME}|g" /usr/local/bin/letsencrypt

Esto (de alguna manera) solía ser suficiente, pero ahora cuando llega la solicitud para http://www.HOSTNAME/.well-known… se redirige al sitio no www en lugar de enviar el desafío que se supone que debe enviar. Intenté hacer algo como esto:

server {
  listen 80;
  listen [::]:80;
  server_name nzarchitecture.net.nz www.nzarchitecture.net.nz;

  # Servir el desafío ACME (Let's Encrypt)
  location ^~ /.well-known/acme-challenge/ {
    root /var/www/discourse/public;  # Asegúrate de que esto coincida con tu webroot de Let's Encrypt
    allow all;
  }

  # Redirigir todo lo demás a HTTPS
  location / {
    return 301 https://$host$request_uri;
  }
}

pero no lo resolví del todo.

Si alguien del equipo está escuchando, sería bueno que hubiera un hook de letsencrypt para que esto pudiera llamarse en un after_letsencrypt. Antes de hacer estos cambios en after_ssl funcionaba, pero parece que ahora si hacemos eso, esto se ejecuta después de ssl, pero antes de letsencrypt.

3 Me gusta

Yo también estoy viendo este problema. Te avisaré si logro solucionarlo.

Mi DISCOURSE_HOSTNAME es www.textkit.com. Estoy haciendo lo contrario de nzarchitecture.net.nz y añadiendo un nombre de host sin www a mi certificado. Esto me funcionó:

- exec: sed -i "s|-d \\${DISCOURSE_HOSTNAME}|-d www.textkit.com -d textkit.com|g" /usr/local/bin/letsencrypt

No puedo decir por qué @pfaffman y nzarchitecture.net.nz tendrían un problema con su versión, aunque quizás el orden de los nombres de host en la mía esté relacionado.

También me encontré con esto.

Eliminé esto (comentándolo):

  after_ssl:
#    - replace:
#        filename: "/etc/runit/1.d/letsencrypt"
#        from: /--keylength/
#        to: "-d example.com --keylength"
#    - replace:
#        filename: "/etc/nginx/conf.d/discourse.conf"
#        from: /return 301 https.+/
#        to: |
#          return 301 https://$host$request_uri;

y agregué esto en la sección run al final según @pfaffman

- exec: sed -i "s|-d \\${DISCOURSE_HOSTNAME}|-d \\${DISCOURSE_HOSTNAME} -d www.\\${DISCOURSE_HOSTNAME}|g" /usr/local/bin/letsencrypt

Esto parece haber sido suficiente para mí:

  • el sitio se reconstruyó y aparentemente tiene certificados válidos
  • la redirección del apex a www está funcionando

¡Gracias @pfaffman!

4 Me gusta

¡Oh! Genial. Quizás el cambio que hicieron y que permitió que las renovaciones de certificados funcionaran también resolvió el problema que yo tenía.

Lo tendré en cuenta si me encuentro con otros sitios que necesiten esto antes de que se acepte la solicitud de extracción (PR).

1 me gusta

Aquí hay algunas partes móviles. ¡Funcionó para mí en esa reconstrucción, informaré aquí si esa situación cambia!

1 me gusta

La PR para permitir renovaciones de certificados aún no se ha fusionado; esa parte sigue pendiente.

Una vez fusionada, debería permitir un app.yml mucho más simplificado.

2 Me gusta

Curiosamente, ese fragmento de código funciona en uno de mis sitios, pero el código antiguo (y solo el código antiguo) funciona en mi otro sitio. :person_shrugging:

¡Bueno, espero que todo esto sea irrelevante pronto de todos modos!

1 me gusta

Eso es muy extraño. ¿Está discourse_docker fijado a una versión antigua?

No, no lo es. No hay mucha diferencia entre las instancias (temas / plugins / configuración similares), excepto que una instancia es bastante más antigua que la otra.

Bueno, esperemos que esto sea solo académico.

1 me gusta

¿Se ha implementado esto en absoluto?

Mi certificado de LetsEncrypt caducó ayer sin renovarse automáticamente. No estoy seguro de si esto tiene algo que ver con los cambios sugeridos en app.yml que hice según este hilo anterior, o con las actualizaciones posteriores de Discourse.

Con la ayuda de la IA (¡sí, lo sé!) he logrado que se renueve, después de seguir a la IA por una serie de caminos sin salida que implicaban usar ngix y certbot (que al final funcionaron, para ser justos), antes de revertir esos cambios y volver al método predeterminado administrado por Discourse. En el proceso tuve que reconstruir un par de veces, así que no estoy seguro de si eso fue lo que desencadenó la renovación.

Lamento las molestias. Tengo curiosidad, ¿cuándo fue la última vez que reconstruyó antes de esto?

Acabamos de verificar y probar el proceso de renovación nuevamente, pero no podemos reproducirlo; nuestras pruebas renuevan correctamente, por lo que o bien no está sucediendo nada de nuestra parte, o hay algo diferente en cómo funciona la renovación de staging frente a la de producción de Let’s Encrypt.

También puedo confirmar que reconstruir su sitio fuerza el proceso de renovación, si todo lo demás falla.

Usamos acme.sh por debajo (en /opt/acme.sh en el contenedor); si se anima, puede ingresar al contenedor docker en ejecución y ejecutar el script para inspeccionar/renovar a través de allí también.

1 me gusta