Aquí la documentación de mis percances y mi eventual éxito al migrar una instancia de Discourse de Scaleway a una Raspberry Pi 4, con Cloudflare delante.
Creé una copia de seguridad de la instancia de Discourse de Scaleway, y ./launcher stop app, y apagué la máquina.
Instalé Ubuntu Server 23.10 en un SSD SATA conectado por USB alimentando la Raspberry Pi 4.
Instalé LXD, creé un grupo de almacenamiento de loopback btrfs de 100GiB.
Actualicé el perfil default a:
config:
cloud-init.user-data: |
#cloud-config
ssh_pwauth: false
package_update: true
package_upgrade: true
packages:
- openssh-server
- vim
- git
- rsync
users:
- name: root
lock_passwd: true
ssh_import_id: gh:balupton
description: Perfil LXD predeterminado
devices:
eth0:
name: eth0
network: lxdbr0
type: nic
root:
path: /
pool: default
type: disk
name: default
Añadí un perfil discourse con:
config:
limits.memory: 1GiB
limits.memory.enforce: soft
security.nesting: 'true'
description: Configuración para instancias de Discourse
devices: {}
name: discourse
Creé una imagen de Ubuntu 23.10 Minimal Server con esos perfiles. Accedí a ella a través de lo siguiente en mi ~/.ssh/config:
Host LXD_DISCOURCE_INSTANCE
ProxyJump LXD_HOST
User REDACTED
IdentityFile ~/.ssh/REDACTED.pub
Seguí las instrucciones de instalación en la nube de Discourse y restauré mi configuración de Discourse desde la instancia de Scaleway:
templates:
- "templates/postgres.template.yml"
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/cloudflare.template.yml"
- "templates/web.ssl.template.yml" # https
- "templates/web.letsencrypt.ssl.template.yml" # https
# - "templates/web.ratelimited.template.yml" # no necesario con cloudflare
expose:
- "80:80"
- "443:443" # https
params:
db_default_text_search_config: "pg_catalog.english"
env:
LANG: en_US.UTF-8
## Configuración HTTPS para: templates/web.letsencrypt.ssl.template.yml
LETSENCRYPT_ACCOUNT_EMAIL: "redacted" # https
## El nombre de dominio al que responderá esta instancia de Discourse
DISCOURSE_HOSTNAME: "redacted"
## Lista de correos electrónicos separados por comas que se convertirán en administradores y desarrolladores
## en el registro inicial, por ejemplo, 'usuario1@ejemplo.com,usuario2@ejemplo.com'
DISCOURSE_DEVELOPER_EMAILS: "redacted"
## El servidor de correo que utilizará esta instancia de Discourse
DISCOURSE_SMTP_ADDRESS: "redacted"
DISCOURSE_SMTP_PORT: redacted
DISCOURSE_SMTP_USER_NAME: "redacted"
DISCOURSE_SMTP_PASSWORD: "redacted"
#DISCOURSE_SMTP_DOMAIN: discourse.example.com # (requerido por algunos proveedores)
#DISCOURSE_NOTIFICATION_EMAIL: nobody@discourse.example.com # (dirección desde la que se enviarán las notificaciones)
#DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456
## Cualquier comando personalizado para ejecutar después de la compilación
run:
- exec: rails r "SiteSetting.contact_email='redacted'"
- exec: rails r "SiteSetting.notification_email='redacted'"
## El contenedor Docker es sin 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
## Plugins
## https://meta.discourse.org/t/19157
hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone https://github.com/discourse/discourse-adplugin.git
- git clone https://github.com/discourse/discourse-affiliate.git
- git clone https://github.com/discourse/discourse-assign.git
- git clone https://github.com/discourse/discourse-docs.git
- git clone https://github.com/discourse/discourse-topic-voting.git
- git clone https://github.com/discourse/discourse-github.git
- git clone https://github.com/discourse/discourse-saved-searches.git
- git clone https://github.com/discourse/discourse-shared-edits.git
- git clone https://github.com/discourse/discourse-solved.git
# - git clone https://github.com/discourse/discourse-encrypt.git
# - git clone https://github.com/discourse/discourse-reactions.git
# - git clone https://github.com/discourse/discourse-subscriptions.git
Antes de poder restaurar la copia de seguridad, sin embargo, necesitaba reconstruirla. Desafortunadamente, el grupo de almacenamiento btrfs se colgaba en el paso de instalación de yarn durante horas y, finalmente, se agotaba el tiempo de espera, con una carga casi nula en la máquina.
Investigando un poco, decidí probar a usar un grupo de almacenamiento zfs en su lugar, esto avanzaría más, pero aún así se colgaría indefinidamente después de Background saving terminated with sucess, con una carga casi nula en la máquina.
(Tengo capturas de pantalla, sin embargo, subirlas aquí falla.)
Entonces decidí abandonar LXD y probarlo directamente en la instancia de Ubuntu Server en la Raspberry Pi 4.
Por primera vez tuve una reconstrucción exitosa, sin embargo, todos los intentos de acceder a ella redirigían a sí misma, en un bucle de redirección.
El bucle de redirección tenía dos causas…
Si tenía lo siguiente en mi configuración de Discourse:
expose:
- "8080:80"
- "8081:443" # https
Redirigiría sin fin, queriendo siempre redirigir a https://hostname.
Resolver esto fue volver a:
expose:
- "80:80"
- "443:443" # https
En segundo lugar, cualquier cosa accedida a través del túnel de Cloudflare también redirigiría sin fin a sí misma. La causa resultó ser tener un túnel tanto para HTTP como para HTTPS. Cambiar el túnel a solo HTTPS lo resolvió.
Otras cosas que hice pero en este punto no estoy seguro si importaron:
- Eliminé letsencrypt ya que usé un Certificado de Origen de Cloudflare en su lugar.
- He configurado el
Nombre del Servidor de Origenen el túnel HTTPS para que sea el nombre de host deseado.
Cosas que podrían mejorarse:
- Se podría evitar el HTTPS desde el Origen a Cloudflare si bloqueo la máquina para que solo permita conexiones desde Cloudflare y configuro un túnel SSH. Sin embargo, no estoy seguro si Discourse funciona mejor teniendo HTTPS en sí mismo (por ejemplo, http2, etc.).
- Si letsencrypt funciona con el túnel de Cloudflare (no pude probarlo ya que cuando usaba letsencrypt estaba obteniendo los bucles de redirección).
Cómo depuré los bucles de redirección:
- Para depurar el bucle de redirección de Discourse: configuré
/etc/hostspara que apunte mi nombre de host de Discourse directamente a la dirección IP, luego usécurl -k --head 'https://hostname:8081etc para probarlo. - Para depurar el bucle de redirección del túnel de Cloudflare: eliminé eso de
/etc/hostspara que el nombre de host se resuelva a través de DNS, luego usécurl -k --head 'https://hostnameetc para probarlo.
Hay un montón de otras cosas ingeniosas y aprendizajes en el camino, sin embargo, eso puede esperar.
Comentarios para Discourse:
- La reconstrucción necesita ser más clara sobre lo que está haciendo. Con demasiada frecuencia hay largos retrasos sin una acción obvia que se esté realizando.
- Averiguar por qué exponer diferentes puertos causaría un bucle de redirección.
- Dado que letsencrypt se convirtió en una cosa, la documentación sobre cómo especificar el propio certificado SSL es tediosa de descubrir. Además, parece que solo se puede usar un certificado ya que está fijado a
/var/discourse/shared/standalone/ssl/ssl.keyen lugar de, por ejemplo,/var/discourse/shared/standalone/ssl/CONTAINER_ID.key, por ejemplo,/var/discourse/shared/standalone/ssl/app.key— Cloudflare proporciona certificados de origen, por lo que esta es una buena opción para los usuarios de Cloudflare. - Publicar una guía completa paso a paso e inclusiva para Cloudflare + Raspberry Pi 4 habría ayudado enormemente, actualmente tales guías delegan demasiada información a terceros que no tienen conocimiento mutuo, y toda la complejidad y depuración está en cómo funcionan juntas las diferentes partes, no en cómo funcionan solas.
Otras tareas pendientes para algún día:
- Averiguar por qué se colgaba en LXD.
- Ver si funciona en LXD en una Raspberry Pi 5, o en Multipass en macOS, o LXD con el grupo de almacenamiento siendo una partición/disco en lugar de un archivo de loopback: ya que entonces no tengo que desperdiciar una máquina entera en ello.
- Ver si puedo hacer que docker y launcher no necesiten sudo.