index | ~dongdigua

在 NanoPi R2S 上运行 FreeBSD

Table of Contents

曾经有两个树莓派, Pi3 因为碰水, Zero 因为腐蚀, 都报废了

我想在 R2S 上运行 BSD, 因为:

  1. it's cool 2) base system 足够, 只需要安装少量包 3) 简洁, 适合小设备

1. 艰辛的历程

  • 带上手套防止腐蚀, 用螺丝刀和弯头镊子 (文具盒里随手使用) 撬开外壳
  • 缝合了一个 OpenBSD 镜像, 用 Arduino Uno 当串口连接 UART, 输出毫无意义的字符
  • 运行 OpwnWRT, 依旧输出垃圾
  • 运行 Armbian, 依旧输出垃圾, 想到是不是串口出错了
  • 翻箱倒柜找到一个 USB Mini-B 线用于 山寨版 Arduino Nano (CH340 芯片)
  • 重新烧写 OpenBSD 镜像, 成功启动, 但键盘无法输入, 无法安装
  • 缝合 FreeBSD 镜像, 成功启动, ssh 登录 (user/passwd:freebsd), 耶!
  • 合上外壳

1.1. 关于镜像制作

总的来说就是:

dd if=FreeBSD-14.1-RELEASE-arm64-aarch64-ROCK64.img of=root.img bs=1M
dd if=usr/lib/linux-u-boot-edge-nanopi-r2s/idbloader.bin of=root.img seek=64 conv=notrunc
dd if=usr/lib/linux-u-boot-edge-nanopi-r2s/uboot.img of=root.img seek=16384 conv=notrunc
dd if=usr/lib/linux-u-boot-edge-nanopi-r2s/trust.bin of=root.img seek=24576 conv=notrunc
doas dd if=root.img of=/dev/sda

2. 开始

  • 中国用户第一件事先换源: bjtu FreeBSD 镜像USTC
  • 改密码, /usr/local/etc/sudoers
    不用 doas 因为 persist 选项只在 OpenBSD 上可用
  • 主机名, 路由器配置 DHCP 静态 IP, 本机 /etc/hosts 加入主机名解析
  • 改 shell 配置, 基本还是之前那样
    在 fortune 里看到一个不错的 PS1, 弄个新 PS1 换换口味

    PS1='(\[$(tput md)\]\t <\w>\[$(tput me)\]) $(echo $?) \[\033[01;31m\]\[\033[00m\] '
    
  • 降 CPU 频率是当然能减少能耗的 /etc/sysctl.conf

    dev.cpu.0.freq=408
    

3. 第一个服务: gopher

su
# freecolor 用于 https://github.com/dongdigua/dongdigua.github.io/blob/main/gmi/docker/cgi/stat.cgi
pkg add gophernicus freecolor
vi /etc/inetd.conf
echo 'inetd_enable="YES"' >> /etc/rc.conf
mkdir /var/gopher
# don't also chown nobody group so it belongs to wheel group
chown nobody /var/gopher
chmod 775 /var/gopher
service inetd onestart

4. frpc daemon

frp 这完意好啊, 但是 Debian 搁置了挺长时间也没加入
我作为 RHEL7 入坑 Linux 的用户, 没有体验过 systemd 之前的服务管理, 这里可以体验一把.
本来以为还得学 rc 脚本, 结果把同目录的 frps 改改就行了

cd /usr/local/etc/rc.d
cp frps frpc
sed -i '' 's/frps/frpc/g' frpc

别忘了把 gophernicus 的 host 和 port 改成远程主机的

4.1. SSH 命根子

有时想加一个端口转发, 然后一 restart, SSH 也断了, 所以应该把 SSH 转发分开来单独一个服务

5. git 服务器

本来想弄个 ssh git 和 cgit, 但仔细考虑感觉没有啥用, 我的 repo 都托管在我朋友的服务器上.
又想弄个 sourcehut, 但真的太麻烦了.
那不如弄个 gitea, 测试一下一些奇怪的功能, 再做一份镜像.
很重要的一点: HTTP_ADDR 应设置成 0.0.0.0

这种比较大的服务可以放在 jail 里, 参考 Absolute FreeBSD

6. jail(8)

通用 jail 设置:

6.1. 主机

/etc/jail.conf

exec.clean;
exec.start="sh /etc/rc";
exec.stop="sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
exec.clean;
mount.devfs;

6.2. in-jail

/etc/crontab 取消 save-entropy 和 adjkerntz
/etc/rc.conf 进程越少越好, 似乎我不需要 sendmail (14.0 默认 dma 了,可以不用加这三行)

sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"

pkg mirror

6.3. rm: Operation not permitted

chflags -R noschg file/folder

7. Gemini

曾经我的 Gemini 是用 Docker 跑在朋友的服务器上, 但是一出问题调试很费劲.
现在有个稳定的服务器, 就可以本地跑, 省去许多麻烦.

依旧使用 jail

su
pkg -j gemini install gmid git # python39 and perl5 are included in git
jexec -U root gemini git clone https://github.com/dongdigua/dongdigua.github.io.git --depth 1 /dongdigua.github.io
jexec -U root gemini sh

then run in sh:

cd /dongdigua.github.io
git config --global filter.dater.smudge 'perl -pe "\$last_date = `git log --pretty=format:\\"%ad\\" -1`;s/\\\$Date\\\$/\\\$Date: \$last_date\\\$/"'
git config --global filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'
openssl req -x509 -newkey rsa:4096 -nodes             \
        -out /usr/local/etc/ssl/gmid/localhost.crt      \
        -keyout /usr/local/etc/ssl/gmid/localhost.key   \
        -subj "/CN=localhost"

openssl req -x509 -newkey rsa:4096 -nodes             \
        -out /usr/local/etc/ssl/gmid/example.com.crt      \
        -keyout /usr/local/etc/ssl/gmid/example.com.key   \
        -subj "/CN=example.com"

/usr/local/etc/gmid.conf:

user "_gmid"

server "r2s.local" {
        root "/dongdigua.github.io"
        cert "/usr/local/etc/ssl/gmid/localhost.crt"
        key  "/usr/local/etc/ssl/gmid/localhost.key"

        cgi "/cgi/*"
        default type "text/plain"
}

server "example.com" {
        root "/dongdigua.github.io"
        cert "/usr/local/etc/ssl/gmid/example.com.crt"
        key  "/usr/local/etc/ssl/gmid/example.com.key"

        cgi "/cgi/*"
        default type "text/plain"
}

/etc/periodic/daily/update-git:

#! /bin/sh

cd /dongdigua.github.io
git pull --rebase
python3.9 misc/mdlist2gmi.py > posts.gmi
cp -r gmi/docker/cgi .
rm index.gmi
git checkout -- index.gmi

8. LED

死机这一教训使我意识到必须得有一个不用网络的方式观察服务器状态, 正常 LED 是常亮的, 但死机也亮着.
先写一个 blink, 就像 Arduino 入门那样.

…太无趣了, 不是吗. 我看 led(4) 的时候发现 morse(6) 有意思, 于是就写了一个用摩斯码打印温度和内存的 rc

#!/bin/sh

# PROVIDE: blink
# KEYWORD: shutdown

. /etc/rc.subr

name=blink
rcvar=blink_enable
blink_enable=${blink_enable:-"NO"}

start_cmd="${name}_start &"
stop_cmd="morse -l sos > /dev/led/nanopi-r2s\:red\:sys"

blink_start() {
while true
do
        echo 0 > /dev/led/nanopi-r2s\:red\:sys
        morse -l "$(sysctl -n hw.temperature.CPU | cut -c 1-2)" > /dev/led/nanopi-r2s\:red\:sys
        sleep 60
done
}

load_rc_config $name
run_rc_command "$1"

9. Web Server

9.1. obhttpd?

httpd 其实算是一个比较年轻的软件, 这里有关于为什么 OpenBSD 要自己做一个 Web Server 的历史
重载配置:

sudo pkill -HUP obhttpd

当我弄 BlueMap 的时候, 发现只有 gzip 压缩文件的时间比原文件新的时候才会加上 Content-Encoding: gzip
但是, BlueMap 这种东西只有 .gz 文件, 所以就 404, httpd 也没有手动加 header 的方式.

nginx, 启动!

9.2. nginx

由于默认的 nginx autoindex 太难看, 我想用 fancyindex 但是默认安装里又没带.
反正得自己编译, 那不如用 ports 编译一个.
其实 apache 的 autoindex 挺好, 还带 icon, 但是 apache 的配置我真的受不了.

默认的 fancyindex 颜色有点丑, 写个 patch 改一下 (能 inline 就不加 CSS)
根本不用看 doc, 直接凭直觉照猫画虎, 先在 Makefile.extmod 里面加上

HTTP_FANCYINDEX_EXTRA_PATCHES=  ${PATCHDIR}/extra-patch-nginx-http-fancyindex-css

颜色基本上是 aur.archlinux.org, Arch Blue 是这个帖子, #39c5bb 懂的都懂.

archlinux.org #08c
wiki.archlinux.org #0077bb
bbs.archlinux.org #07b
aur.archlinux.org #07b

--- ../ngx-fancyindex-0.5.2/template.h.orig     2021-10-28 19:28:07.000000000 +0000
+++ ../ngx-fancyindex-0.5.2/template.h  2023-08-30 11:36:48.142878000 +0000
@@ -9,9 +9,8 @@
 "body,html {"
 "background:#fff;"
-"font-family:\"Bitstream Vera Sans\",\"Lucida Grande\","
-"\"Lucida Sans Unicode\",Lucidux,Verdana,Lucida,sans-serif;"
+"font-family:monospace;"
 "}"
 "tr:nth-child(even) {"
-"background:#f4f4f4;"
+"background:#e4eeff;"
 "}"
 "th,td {"
@@ -21,5 +20,5 @@
 "text-align:left;"
 "font-weight:bold;"
-"background:#eee;"
+"background:#ecf2f5;"
 "border-bottom:1px solid #aaa;"
 "}"
@@ -29,8 +28,9 @@
 "}"
 "a {"
-"color:#a33;"
-"}"
-"a:hover {"
-"color:#e33;"
+"text-decoration:none;"
+"color:#1793d1;"
+"}"
+"a:hover {"
+"color:#39c5bb;"
 "}"
 "</style>"

我甚至还可以把 SSL, MAIL, STREAM 的功能通通去掉, 因为我的环境用不到.

9.3. Caddy

不舒服 :(

10. MediaWiki?

don't
如果你不想被嵌入式设备糟糕的性能浪费一上午的时间最后得到加载时间大于10秒的网页, 放弃吧…
有足够性能的服务器还可以编译带 SQLite 支持的 port

我想使用 MediaWiki 主要想尝试 MinecraftWiki Schematic Module

11. mDNS

先是 avahi-app
两个都要开啊, 要不然会很慢的!

avahi_daemon_enable="YES"
avahi_dnsconfd_enable="YES"

但是 avahi-app 依赖项太多了,很多都是跟图形界面有关的
然后我看到了这个 How to install and configure mDNSResponder

mdnsresponderposix_enable="YES"
mdnsresponderposix_flags="-n $hostname"

12. ports

之前有一次用 portsnap(8) 解包 ports 结果崩了然后文件系统坏了, 这回用 git, 没事.

git clone --depth=1 https://git.FreeBSD.org/ports.git /usr/ports

12.1. install ports's dependencies with pkg

USE_PACKAGE_DEPENDS=1

13. ZFS?

之前我只是在唯一的U口上插了一个 32G U盘, 但随着我在服务器上放的东西越来越多并越来越依赖它,
我开始对数据安全担忧: 万一哪天整个U盘坏了呢? 而且这似乎正在发生着, 我已经看到这样的报错了:

(da1:umass-sim1:1:0:0): CAM status: CCB request completed with an error
(da1:umass-sim1:1:0:0): Retrying command, 1 more tries remain

所以我考虑用 ZFS 组个 RAIDz, 这样 3 块 32G U盘可以得到接近 64G 的空间并且允许一个U盘坏掉.
创建存储池等基本操作请看 Chapter 22. The Z File System (ZFS)
弄完我就开心地睡觉了, 后台把之前U盘的东西 rsync 过来, 寻思这么先进的文件系统不会出什么问题吧, 即使有也能自我修复.
第二天一早醒来, DEGRADED, 一个盘掉了, 查看 dmesg, 又是大量的报错:

(da1:umass-sim1:1:0:0): Retrying command, 0 more tries remain
(da1:umass-sim1:1:0:0): SYNCHRONIZE CACHE(10). CDB: 35 00 00 00 00 00 00 00 00 00
(da1:umass-sim1:1:0:0): CAM status: CCB request completed with an error
(da1:umass-sim1:1:0:0): Error 5, Retries exhausted
(da1:umass-sim1:1:0:0): got CAM status 0x44
(da1:umass-sim1:1:0:0): fatal error, failed to attach to device
da1 at umass-sim1 bus 1 scbus1 target 0 lun 0
da1: <Netac OnlyDisk 2.00>  s/n 8355111095836336751 detached
(da1:umass-sim1:1:0:0): Periph destroyed

嘶~ 不应该呀, 新买的盘. 拔掉尝试修复以及几次重启和重新创建阵列后, 还是过一段时间三个盘中就会有 1~2 个坏的.
因为之前的盘一直没坏, 所以可以排除 USB 集线器的问题, 所以问题就出在 朗科京东自营旗舰店 上买的这仨盘.
上 #archlinux-cn-offtopic 问一圈:

18:27 <digua> 各位, 朗科京东自营旗舰店 的U盘质量怎么样啊, 我买了 3 个, 组 ZFS 坏了俩
...
18:28 <nichi_bot> [啥玩意啊 咋回事啊 那咋整啊 大佬帮帮忙啊] > <@matterbridge:nichi.co> [digua] 各位, 朗科京东自营旗舰店 的U盘质量怎么样啊, 我买了 3 个, 组 ZFS 坏了俩
18:28 <nichi_bot> [啥玩意啊 咋回事啊 那咋整啊 大佬帮帮忙啊] 。。。。。
18:28 <nichi_bot> [gauge] u 盘还要 zfs 嘛
18:28 <nichi_bot> [啥玩意啊 咋回事啊 那咋整啊 大佬帮帮忙啊] 你不知道 U 盘用的是最次最次的颗粒吗
18:29 <nichi_bot> [啥玩意啊 咋回事啊 那咋整啊 大佬帮帮忙啊] 起夜级挑剩下来的给消费级 nvme 挑剩下来的给 sata 硬盘挑剩下来的给 U 盘
18:29 <digua> gauge, 用在软路由上(
18:30 <nichi_bot> [啥玩意啊 咋回事啊 那咋整啊 大佬帮帮忙啊] ?你软路由还 zfs
18:30 <nichi_bot> [Kimiblock Moe] U 盘不就拿来刷 archiso 嘛
18:30 <nichi_bot> [Kimiblock Moe] 除此以外还有啥用啊
18:30 <nichi_bot> [啥玩意啊 咋回事啊 那咋整啊 大佬帮帮忙啊] 我以为 j1900 跑 esxi 和 pve 已经够离谱了
18:31 <digua> 弄着玩呀
18:31 <HoroBot> 🍋🙈🐰🙊🍈🌝
18:31 <nichi_bot> [啥玩意啊 咋回事啊 那咋整啊 大佬帮帮忙啊] 你真要弄的话 建议搞点硬盘盒然后插 nvme
...
18:34 <nichi_bot> [Jack Smith] > <@matterbridge:nichi.co> [digua] 各位, 朗科京东自营旗舰店 的U盘质量怎么样啊, 我买了 3 个, 组 ZFS 坏了俩
18:34 <nichi_bot> [Jack Smith] u盘不可靠🤣
...
18:34 <nichi_bot> [Jack Smith] > <啥玩意啊 咋回事啊 那咋整啊 大佬帮帮忙啊> ?你软路由还 zfs
18:34 <nichi_bot> [Jack Smith] 我tf卡btrfs🙈

ZFS 这个技术很棒, 但得等我弄到靠谱的盘…

又买了两个海康威视星云固态盘, 只买两个是因为我感觉小处理器可能计算校验和会有压力.
这回速度可以, 3MB/s

大量 IO 任务还是会阻塞, 可以用 nq 排个队列.

14. Upgrade to 14.0

我发现默认安装是带 debug symbol 的, 但对我来说没用, 想取消掉.

The following components of FreeBSD seem to be installed:
kernel/generic kernel/generic-dbg world/base world/base-dbg

The following components of FreeBSD do not seem to be installed:

Does this look reasonable (y/n)? n

How to remove debug components from system
给出的方案是 rm -rf /usr/lib/debug, 但我也与下面帖子的人有一样的疑问: 是否在别的地方还有 debug 的东西?
我下了 base-dbg.txz 和 kernel-dbg.txz 然后 tar tvf, 哦, 只有 /usr/lib/debug/.
然后:

The following components of FreeBSD seem to be installed:
kernel/generic world/base

The following components of FreeBSD do not seem to be installed:
kernel/generic-dbg world/base-dbg

15. BBR

ftp ftp.freebsd.org
tar -C / -zxf src.txz
cd /usr/src/sys/arm64/conf
mv ROCKCHIP ROCKCHIP-bbr
cd /usr/src
make buildkernel TARGET_ARCH=aarch64
make installkernel TARGET_ARCH=aarch64 DESTDIR=/root/aarch64

在 vbox 里 900 多秒就编译完了

/etc/src.conf

KERNCONF=ROCKCHIP-bbr
MALLOC_PRODUCTION=yes

重启时我心里也没底, 但没发生什么意外.

16. When Things Go Wrong

换新插排断电后又启动不了了,修复文件系统也没用。
这时,FreeBSD 发行模式的优点就体现出来了:
只需启动 FreeBSD Live 系统(Linux 内核默认不开启 UFS_FS_WRITE ),
把旧系统的 SD 卡和新刷系统的 SD 卡挂上,把 /usr/local /etc /var/db 拷过去,基本就复刻了原来的系统。
(如果啥都不想变,也可以把原来系统直接装 Jail 里)
难以想象如果这是个 Linux 发行版会怎样困难……

17. Ref

dongdigua CC BY-NC-SA 禁止转载到私域(公众号,非自己托管的博客等)

Date: 2023-07-10 Mon 00:00 Build: 2024-07-25 Thu 02:16

Proudly made with Emacs Org mode

Email me to add comment