从 Scaleway 迁移到 Raspberry Pi 4 的一次艰难经历

这是我遇到的麻烦以及最终成功将 discourse 实例从 scaleway 迁移到树莓派 4,并在前面使用 cloudflare 的文档。

从 scaleway discourse 实例创建备份,然后运行 ./launcher stop app,并关闭机器。

在连接到树莓派 4 的 USB SATA SSD 上安装了 Ubuntu Server 23.10。
安装了 LXD,创建了一个 100GiB 的 btfs 回环存储池。
更新 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 最小服务器镜像。通过 ~/.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,直接在树莓派 4 上的 Ubuntu Server 实例上尝试。
这是我第一次成功重建,但所有访问尝试都会重定向到自身,形成重定向循环。

重定向循环有两个原因……

如果我的 discourse 配置中有以下内容:

expose:
  - "8080:80"
  - "8081:443"  # https

它会无限重定向,总是想重定向到 https://hostname
解决这个问题是回到:

expose:
  - "80:80"
  - "443:443"  # https

其次,通过 cloudflare 隧道访问的任何内容也会无限重定向到自身。结果发现原因是同时为 HTTP 和 HTTPS 设置了隧道。将隧道更改为仅 HTTPS 解决了这个问题。

我做的其他事情,但此时不确定是否重要:

  1. 我删除了 letsencrypt,因为我改用了 Cloudflare Origin Certificate。
  2. 我已将 HTTPS 隧道中的“Origin Server Name”配置为目标主机名。

可以改进的地方:

  1. 如果我将机器锁定为仅允许来自 Cloudflare 的连接,并设置 SSH 隧道,就可以避免从 Origin 到 Cloudflare 的 HTTPS。但是,我不确定 Discourse 是否在拥有 HTTPS(例如 http2 等)的情况下运行得更好。
  2. letsencrypt 是否与 cloudflare 隧道一起工作(我无法测试,因为当我使用 letsencrypt 时,我遇到了重定向循环)。

我如何调试重定向循环:

  • 对于调试 discourse 重定向循环:我将 /etc/hosts 设置为将我的 discourse 主机名直接指向 IP 地址,然后使用 curl -k --head 'https://hostname:8081 等进行测试。
  • 对于调试 cloudflare 隧道重定向循环:我从 /etc/hosts 中删除了它,以便主机名通过 DNS 解析,然后使用 curl -k --head 'https://hostname 等进行测试。

一路上还有很多其他巧妙的事情和学习,但那些可以稍后讨论。

对 discourse 的反馈:

  • 重建需要更清楚地说明它在做什么。太长的时间延迟,但没有明显的动作正在执行。
  • 找出为什么暴露不同的端口会导致重定向循环。
  • 自从 letsencrypt 出现以来,关于如何指定自己的 SSL 证书的文档很难找到。而且似乎只能使用一个证书,因为它固定在 /var/discourse/shared/standalone/ssl/ssl.key 而不是例如 /var/discourse/shared/standalone/ssl/CONTAINER_ID.key,例如 /var/discourse/shared/standalone/ssl/app.key — cloudflare 提供源证书,这对 cloudflare 用户来说是一个不错的选择。
  • 发布一个全面的分步指南,涵盖 cloudflare + 树莓派 4 的所有内容,将非常有帮助,目前这类指南将过多的信息委托给第三方,而这些第三方彼此之间没有了解,所有的复杂性和调试都在于不同部分如何协同工作,而不是它们如何单独工作。

其他一些未来的待办事项:

  • 找出它为什么会在 LXD 中挂起。
  • 查看它是否可以在树莓派 5 上的 LXD,或 macOS 上的 Multipass,或使用分区/驱动器而不是回环文件的存储池的 LXD 中工作:这样我就不必浪费一台完整的机器来做这件事。
  • 查看我是否可以让 docker 和 launcher 不需要 sudo。
3 个赞