Scaleway から Raspberry Pi 4 への Discourse インスタンスの移行、および Cloudflare を前面に配置した際の私の失敗談と最終的な成功についてのドキュメントです。
Scaleway の Discourse インスタンスからバックアップを作成し、./launcher stop app を実行してマシンをシャットダウンしました。
Raspberry Pi 4 に接続された USB SATA SSD から Ubuntu Server 23.10 をインストールしました。
LXD をインストールし、100GiB の btrfs ループバックストレージプールを作成しました。
default プロファイルを以下のように更新しました。
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: Default LXD profile
devices:
eth0:
name: eth0
network: lxdbr0
type: nic
root:
path: /
pool: default
type: disk
name: default
discourse プロファイルを以下を追加して作成しました。
config:
limits.memory: 1GiB
limits.memory.enforce: soft
security.nesting: 'true'
description: Configuration for Discourse instances
devices: {}
name: discourse
これらのプロファイルを使用して Ubuntu 23.10 Minimal Server イメージを作成しました。~/.ssh/config で以下のようにアクセスしました。
Host LXD_DISCOURCE_INSTANCE
ProxyJump LXD_HOST
User REDACTED
IdentityFile ~/.ssh/REDACTED.pub
Discourse のクラウドインストール手順に従い、Scaleway インスタンスから Discourse の設定を復元しました。
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" # not needed with cloudflare
expose:
- "80:80"
- "443:443" # https
params:
db_default_text_search_config: "pg_catalog.english"
env:
LANG: en_US.UTF-8
## HTTPS configuration for: templates/web.letsencrypt.ssl.template.yml
LETSENCRYPT_ACCOUNT_EMAIL: "redacted" # https
## The domain name this Discourse instance will respond to
DISCOURSE_HOSTNAME: "redacted"
## List of comma delimited emails that will be made admin and developer
## on initial signup example 'user1@example.com,user2@example.com'
DISCOURSE_DEVELOPER_EMAILS: "redacted"
## The mailserver this Discourse instance will use
DISCOURSE_SMTP_ADDRESS: "redacted"
DISCOURSE_SMTP_PORT: redacted
DISCOURSE_SMTP_USER_NAME: "redacted"
DISCOURSE_SMTP_PASSWORD: "redacted"
#DISCOURSE_SMTP_DOMAIN: discourse.example.com # (required by some providers)
#DISCOURSE_NOTIFICATION_EMAIL: nobody@discourse.example.com # (address to send notifications from)
#DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456
## Any custom commands to run after building
run:
- exec: rails r "SiteSetting.contact_email='redacted'"
- exec: rails r "SiteSetting.notification_email='redacted'"
## The Docker container is stateless; all data is stored in /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
バックアップを復元する前に、再構築する必要がありました。残念ながら、btrfs ストレージプールは yarn install のステップで数時間ハングし、最終的にタイムアウトしました。マシンの負荷はほとんどありませんでした。
調査の結果、zfs ストレージプールを使用することにしましたが、それでも Background saving terminated with sucess の後にハングし続け、マシンの負荷はほとんどありませんでした。
(スクリーンショットはありますが、ここにアップロードすると失敗します。)
LXD を断念し、Raspberry Pi 4 の Ubuntu Server インスタンスで直接試すことにしました。
初めて再構築が成功しましたが、アクセスを試みるとすべてリダイレクトループで自身にリダイレクトされました。
リダイレクトループの原因は 2 つありました…
Discourse の設定に以下が含まれている場合:
expose:
- "8080:80"
- "8081:443" # https
無限にリダイレクトされ、常に https://hostname にリダイレクトしようとしました。
これを解決するには、以下に戻しました。
expose:
- "80:80"
- "443:443" # https
次に、Cloudflare Tunnel 経由でアクセスされたものはすべて無限に自身にリダイレクトされました。原因は、HTTP 用のトンネルと HTTPS 用のトンネルの両方を持っていたことでした。トンネルを HTTPS のみに変更することで解決しました。
その他に行ったことですが、現時点では重要かどうか不明です。
- Let’s Encrypt を削除し、代わりに Cloudflare Origin Certificate を使用しました。
- HTTPS トンネルの
Origin Sever Nameを目的のホスト名に設定しました。
改善できる点:
- マシンを Cloudflare からの接続のみを許可するようにロックダウンし、SSH トンネルを設定すれば、オリジンから Cloudflare までの HTTPS を回避できます。しかし、Discourse が HTTPS を自身で実行する方がパフォーマンスが良いのか(例:http2 など)は不明です。
- Let’s Encrypt が Cloudflare Tunnel で機能するかどうか(Let’s Encrypt を使用していたときにリダイレクトループが発生していたため、テストできませんでした)。
リダイレクトループのデバッグ方法:
- Discourse のリダイレクトループのデバッグ:
/etc/hostsを設定して、Discourse ホスト名を直接 IP アドレスにマッピングし、curl -k --head 'https://hostname:8081などを使用してテストしました。 - Cloudflare Tunnel のリダイレクトループのデバッグ:ホスト名が DNS で解決されるように
/etc/hostsから削除し、curl -k --head 'https://hostnameなどを使用してテストしました。
途中で他にも多くの便利なことや学習がありましたが、それは後回しにできます。
Discourse へのフィードバック:
- 再構築が何をしているのかをより明確にする必要があります。多くの場合、明らかなアクションが実行されていないのに長時間遅延が発生します。
- 異なるポートを公開するとリダイレクトループが発生する理由を調べる必要があります。
- Let’s Encrypt が登場して以来、独自の SSL 証明書を指定する方法に関するドキュメントを見つけるのが困難です。また、
/var/discourse/shared/standalone/ssl/ssl.keyのように 1 つの証明書しか使用できないように見えますが、例えば/var/discourse/shared/standalone/ssl/CONTAINER_ID.keyのように、/var/discourse/shared/standalone/ssl/app.keyのように、Cloudflare はオリジン証明書を提供しているため、Cloudflare ユーザーにとっては良いオプションです。 - Cloudflare + Raspberry Pi 4 の包括的なステップバイステップガイドを発行すれば、非常に役立ったでしょう。現在、そのようなガイドは、互いに認識していないサードパーティに多くの情報を委任しており、すべての複雑さとデバッグは、個々の部分がどのように機能するかではなく、それらがどのように連携して機能するかに関係しています。
その他のいつかやるべきこと:
- LXD でハングした理由を調べる。
- Raspberry Pi 5 の LXD、macOS の Multipass、またはループバックファイルではなくパーティション/ドライブをストレージプールとして使用する LXD で機能するかどうかを確認する。そうすれば、マシン全体を無駄にする必要がなくなります。
- Docker と launcher が sudo を必要としないようにできるかどうかを確認する。