Hier sind die Dokumentationen meiner Missgeschicke und meines schließlichen Erfolgs bei der Migration einer Discourse-Instanz von Scaleway auf einen Raspberry Pi 4 mit Cloudflare davor.
Ich habe ein Backup von der Scaleway Discourse-Instanz erstellt, ./launcher stop app ausgeführt und die Maschine heruntergefahren.
Ich habe Ubuntu Server 23.10 auf einer USB-angeschlossenen SATA-SSD installiert, die den Raspberry Pi 4 mit Strom versorgt.
Ich habe LXD installiert und einen 100GiB btrfs-Loopback-Speicherpool erstellt.
Ich habe das default-Profil aktualisiert auf:
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: Standard LXD-Profil
devices:
eth0:
name: eth0
network: lxdbr0
type: nic
root:
path: /
pool: default
type: disk
name: default
Ich habe ein discourse-Profil mit folgendem hinzugefügt:
config:
limits.memory: 1GiB
limits.memory.enforce: soft
security.nesting: 'true'
description: Konfiguration für Discourse-Instanzen
devices: {}
name: discourse
Ich habe ein Ubuntu 23.10 Minimal Server-Image mit diesen Profilen erstellt. Ich habe darauf über die folgende Konfiguration in meiner ~/.ssh/config-Datei zugegriffen:
Host LXD_DISCOURCE_INSTANCE
ProxyJump LXD_HOST
User REDACTED
IdentityFile ~/.ssh/REDACTED.pub
Ich habe die Cloud-Installationsanweisungen von Discourse befolgt und meine Discourse-Konfiguration von der Scaleway-Instanz wiederhergestellt:
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" # nicht benötigt mit Cloudflare
expose:
- "80:80"
- "443:443" # https
params:
db_default_text_search_config: "pg_catalog.english"
env:
LANG: en_US.UTF-8
## HTTPS-Konfiguration für: templates/web.letsencrypt.ssl.template.yml
LETSENCRYPT_ACCOUNT_EMAIL: "redacted" # https
## Der Domainname, auf den diese Discourse-Instanz reagieren wird
DISCOURSE_HOSTNAME: "redacted"
## Liste von per Komma getrennten E-Mails, die bei der ersten Anmeldung zu Administratoren und Entwicklern gemacht werden
## Beispiel 'user1@example.com,user2@example.com'
DISCOURSE_DEVELOPER_EMAILS: "redacted"
## Der Mailserver, den diese Discourse-Instanz verwenden wird
DISCOURSE_SMTP_ADDRESS: "redacted"
DISCOURSE_SMTP_PORT: redacted
DISCOURSE_SMTP_USER_NAME: "redacted"
DISCOURSE_SMTP_PASSWORD: "redacted"
#DISCOURSE_SMTP_DOMAIN: discourse.example.com # (von einigen Anbietern benötigt)
#DISCOURSE_NOTIFICATION_EMAIL: nobody@discourse.example.com # (Adresse, von der Benachrichtigungen gesendet werden)
#DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456
## Alle benutzerdefinierten Befehle, die nach dem Build ausgeführt werden sollen
run:
- exec: rails r "SiteSetting.contact_email='redacted'"
- exec: rails r "SiteSetting.notification_email='redacted'"
## Der Docker-Container ist zustandslos; alle Daten werden in /shared gespeichert
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
Bevor ich jedoch das Backup wiederherstellen konnte, musste ich es neu erstellen. Leider hing der btrfs-Speicherpool beim Schritt yarn install stundenlang und lief schließlich aus, mit nahezu null Last auf der Maschine.
Nach einiger Recherche beschloss ich, stattdessen einen zfs-Speicherpool zu verwenden. Dies kam dann weiter, aber hing immer noch unbegrenzt nach “Background saving terminated with sucess” fest, mit nahezu null Last auf der Maschine.
(Ich habe Screenshots, aber der Upload hier schlägt fehl.)
Ich beschloss dann, LXD aufzugeben und es direkt auf der Ubuntu Server-Instanz auf dem Raspberry Pi 4 zu versuchen.
Zum ersten Mal hatte ich eine erfolgreiche Neuerstellung, jedoch führten alle Zugriffsversuche zu einer Umleitung auf sich selbst, in einer Weiterleitungsschleife.
Die Weiterleitungsschleife hatte zwei Ursachen…
Wenn ich folgendes in meiner Discourse-Konfiguration hatte:
expose:
- "8080:80"
- "8081:443" # https
würde es endlos weiterleiten und immer zu https://hostname weiterleiten wollen.
Dies zu lösen, bedeutete, zurück zu gehen zu:
expose:
- "80:80"
- "443:443" # https
Zweitens führte alles, auf das über den Cloudflare-Tunnel zugegriffen wurde, ebenfalls zu einer endlosen Weiterleitung auf sich selbst. Die Ursache war, wie sich herausstellte, ein Tunnel sowohl für HTTP als auch für HTTPS. Die Änderung des Tunnels auf nur HTTPS löste das Problem.
Andere Dinge, die ich getan habe, aber zu diesem Zeitpunkt unsicher bin, ob sie wichtig waren:
- Ich habe Let’s Encrypt entfernt, da ich stattdessen ein Cloudflare Origin Certificate verwendet habe.
- Ich habe den
Origin Server Nameim HTTPS-Tunnel auf den beabsichtigten Hostnamen gesetzt.
Dinge, die verbessert werden könnten:
- HTTPS vom Ursprung zu Cloudflare könnte vermieden werden, wenn ich die Maschine so konfiguriere, dass sie nur Verbindungen von Cloudflare zulässt, und einen SSH-Tunnel einrichte. Ich bin mir jedoch nicht sicher, ob Discourse besser läuft, wenn HTTPS auf sich selbst läuft (z. B. http2 usw.).
- Ob Let’s Encrypt mit dem Cloudflare-Tunnel funktioniert (ich konnte es nicht testen, da ich beim Verwenden von Let’s Encrypt die Weiterleitungsschleifen hatte).
Wie ich die Weiterleitungsschleifen debuggt habe:
- Zum Debuggen der Discourse-Weiterleitungsschleife: Ich habe
/etc/hostsso eingestellt, dass mein Discourse-Hostname direkt auf die IP-Adresse zeigt, und danncurl -k --head 'https://hostname:8081usw. verwendet, um es zu testen. - Zum Debuggen der Cloudflare-Tunnel-Weiterleitungsschleife: Ich habe dies aus
/etc/hostsentfernt, sodass der Hostname über DNS aufgelöst wird, und danncurl -k --head 'https://hostnameusw. verwendet, um es zu testen.
Es gibt noch eine Reihe anderer nützlicher Dinge und Lernerfahrungen auf dem Weg, aber das kann warten.
Feedback für Discourse:
- Die Neuerstellung muss klarer darüber sein, was sie tut. Zu oft gibt es lange Verzögerungen ohne offensichtliche Aktion.
- Herausfinden, warum das Exponieren unterschiedlicher Ports eine Weiterleitungsschleife verursachen würde.
- Seit Let’s Encrypt aufkam, ist die Dokumentation, wie man sein eigenes SSL-Zertifikat angibt, mühsam zu finden. Außerdem scheint nur ein Zertifikat verwendet werden zu können, da es auf
/var/discourse/shared/standalone/ssl/ssl.keyfestgelegt ist, anstatt z. B. auf/var/discourse/shared/standalone/ssl/CONTAINER_ID.key, z. B./var/discourse/shared/standalone/ssl/app.key— Cloudflare bietet Ursprungszertifikate, daher ist dies eine gute Option für Cloudflare-Benutzer. - Die Veröffentlichung einer umfassenden Schritt-für-Schritt-Anleitung für Cloudflare + Raspberry Pi 4 hätte enorm geholfen. Derzeit delegieren solche Anleitungen zu viele Informationen an Dritte, die keine Ahnung voneinander haben, und die gesamte Komplexität und das Debugging liegen darin, wie die verschiedenen Teile zusammenarbeiten, nicht wie sie allein funktionieren.
Andere “irgendwann”-Aufgaben:
- Herausfinden, warum es in LXD hängen geblieben ist.
- Sehen, ob es in LXD auf einem Raspberry Pi 5, auf Multipass unter macOS oder mit LXD funktioniert, wobei der Speicherpool eine Partition/ein Laufwerk und kein Loopback-Datei ist: da ich dann keine ganze Maschine dafür verschwenden muss.
- Sehen, ob ich Docker und Launcher ohne sudo verwenden kann.