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

**URL:** <https://meta.discourse.org/t/an-ordeal-migrating-from-scaleway-to-a-raspberry-pi-4/294354>\
**Category:** Self-hosting\
**Created:** [2024年二月6日 14:57 UTC](https://meta.discourse.org/t/an-ordeal-migrating-from-scaleway-to-a-raspberry-pi-4/294354 "2024-02-06T14:57:03Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![balupton](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/balupton/32/255461_2.png) [@balupton](https://meta.discourse.org/u/balupton)\
**Post date:** [2024年二月6日 14:57 UTC](https://meta.discourse.org/t/an-ordeal-migrating-from-scaleway-to-a-raspberry-pi-4/294354/1 "2024-02-06T14:57:04Z")

</div>

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

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

在连接到树莓派 4 的 USB SATA SSD 上安装了 Ubuntu Server 23.10。  
安装了 LXD，创建了一个 100GiB 的 btfs 回环存储池。  
更新 `default` 配置文件为：

```yaml
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` 配置文件，包含：

```yaml
config:
  limits.memory: 1GiB
  limits.memory.enforce: soft
  security.nesting: 'true'
description: Configuration for Discourse instances
devices: {}
name: discourse

```

使用这些配置文件创建了一个 Ubuntu 23.10 最小服务器镜像。通过 `~/.ssh/config` 中的以下配置访问它：

```plaintext
Host LXD_DISCOURCE_INSTANCE
	ProxyJump LXD_HOST
	User REDACTED
	IdentityFile ~/.ssh/REDACTED.pub

```

遵循 discourse 云安装说明，并从 scaleway 实例恢复了我的 discourse 配置：

```yaml
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 配置中有以下内容：

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

```

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

```plaintext
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。
