Raspberry Pi 4 - 充当 NAS 和 Time Machine 的持久系统

来自 Alpine Linux

本页面记录了在 Raspberry Pi 系统上作为 NAS 和 Time Machine 运行的 Alpine Linux 的 Sys 模式安装。

修补匠、裁缝、树莓派

我继续购买了一个配备 4GB RAM 的 Raspberry Pi 4B,我打算将其用作作业调度服务器,但却发现建议的操作系统 Raspberry Pi OS 是 32 位的。幸运的是,我最近非常喜欢的 Linux 发行版 Alpine 提供了适用于 Raspberry Pi 的 aarch64 版本,这意味着它是 64 位内核和用户空间。不幸的是,截至 3.12 版本,该发行版目前尚未设置为持久存储,更像是一个实况游乐场。从网上各种指南中收集零星信息,可以通过一些修补来弥补这一点。在本页中,您将找到如何在 Raspberry Pi 上设置持久的 64 位操作系统、共享 USB 连接的磁盘,同时添加一些有趣的软件。

如果您继续购买 Pi 4,请注意它具有 micro-HDMI 端口。我以为它们是 mini 端口,我已经有了相应的线缆,但唉,又不得不购买一个适配器。此外,当连接 USB 磁盘时,最好是外部供电。但是,Pi 可以为功耗较低的新型外部 SSD 驱动器供电。我首先尝试了通过 USB 供电的基于磁盘的磁性驱动器,但它的表现有些奇怪。话虽如此,让我们继续看看如何为自己打造一台闪亮的小型新服务器。

为持久性而修补

从我的 macOS 上的 Alpine 下载 v3.12 tarball 后,就该为 Pi 设置 SDHC 卡了。我实际上借用了几年前送给我女儿的旧款 MacBook Air,因为它内置了读卡器,而我的新款 Air 则没有。Pi 从 FAT32 分区启动,但我们希望系统稍后驻留在 ext4 分区中,因此我们将首先为启动分区保留一小部分卡空间。这是使用 macOS 中的终端使用以下命令完成的。

diskutil list
diskutil partitionDisk /dev/disk2 MBR "FAT32" ALP 256MB "Free Space" SYS R
sudo fdisk -e /dev/disk2
> f 1
> w
> exit

tarball 应该在到达您的下载文件夹后解压缩。如果没有,请对 tar 使用“xvzf”选项。

cd /Volumes/ALP
tar xvf ~/Downloads/alpine-rpi-3.12.0-aarch64.tar
nano usercfg.txt

新创建的文件 usercfg.txt 应包含以下内容

enable_uart=1
gpu_mem=32
disable_overscan=1

无头模式的最小内存量为 32MB。UART 的东西超出了我的理解范围,但似乎是一个推荐的设置。移除过扫描可以为您提供更多的屏幕空间。如果您打算将其用作台式计算机而不是无头服务器,您可能需要为 GPU 分配更多内存并启用声音。有关选项的完整规范,请访问官方 Raspberry Pi 主页。

之后,我们只需要确保卡未被占用,因此我们切换到安全目录,然后弹出卡(确保所有挂起的写入都已完成)。

cd ..
diskutil eject /dev/disk2

将 SDHC 卡放入 Pi 并启动。使用“root”作为用户名,不使用密码登录。这假定您已连接所有其他设备,例如键盘和显示器。

setup-alpine

在设置过程中,根据需要选择您的键盘布局、主机名等。但是,当询问将配置存储在哪里时,键入“none”,apk 缓存目录也一样。如果您想完全按照本指南进行操作,您还应该选择“chrony”作为 NTP 客户端。不过,这里最重要的是启动并运行您的网络。有关设置程序的完整描述,请访问 Alpine 主页。

apk update
apk upgrade
apk add cfdisk
cfdisk /dev/mmcblk0

在 cfdisk 中,选择“Free space”和选项“New”。它将建议使用所有可用空间,因此只需按 Enter,然后选择选项“primary”,然后选择“Write”。键入“yes”将分区表写入磁盘,然后选择“Quit”。

apk add e2fsprogs
mkfs.ext4 /dev/mmcblk0p2
mount /dev/mmcblk0p2 /mnt
setup-disk -m sys /mnt
mount -o remount,rw /media/mmcblk0p1

忽略有关 extlinux 的警告。这个技巧和以下技巧是在 Alpine Wiki 中找到的,但顺序有些混乱。

rm -f /media/mmcblk0p1/boot/*
cd /mnt
rm boot/boot
mv boot/* /media/mmcblk0p1/boot/
rm -Rf boot
mkdir media/mmcblk0p1
ln -s media/mmcblk0p1/boot boot

现在需要修复挂载点,因此运行

apk add nano
nano etc/fstab

如果您喜欢其他编辑器(因为人们往往对这些东西变得很执着),那么请随意使用任何让您感觉比 nano 更好的编辑器。添加以下行

/dev/mmcblk0p1   /media/mmcblk0p1   vfat   defaults   0 0

现在内核需要知道根文件系统在哪里。

nano /media/mmcblk0p1/cmdline.txt

在文件中唯一一行的末尾附加以下内容

root=/dev/mmcblk0p2

退出 nano 后,可以安全地重启,因此

reboot

重启后,使用“root”作为用户名和您在之前的 setup-alpine 期间选择的密码登录。现在您拥有了一个持久系统,并且所做的一切都会保留,这与原始发行版的配置方式相反。

为远程访问而定制

OpenSSH 应该已经安装,但它不允许远程 root 登录。我们最初将放宽此限制。本文的最后一部分是关于加固的部分,我们再次禁止 root 登录。如果您打算从 Internet 访问此盒子,我强烈建议您加固 Pi。

nano /etc/ssh/sshd_config

取消注释并更改 PermitRootLogin 行(大约在第 30 行),将其更改为

PermitRootLogin yes

然后重启服务

rc-service sshd restart

现在您应该可以 ssh 到您的 Pi 了。当您可以将内容剪切并粘贴到终端窗口中时,以下步骤会更容易。感觉幸运吗?那么现在是断开键盘和显示器的好时机。

保持时间同步

如果您选择 chrony 作为 NTP 客户端,它可能需要很长时间才能真正更正时钟。由于 Pi 没有硬件时钟,因此有必要在启动时更正时间,因此我们将更改配置,以便在首次 10 次查找期间时钟偏差超过 60 秒时进行设置。

nano /etc/chrony/chrony.conf

将以下行添加到文件底部。

makestep 60 10

检查日期,重启服务,然后再次检查(现在希望已更正的)日期。

date
rc-service chronyd restart
date

拥有正确的时间是一件好事,尤其是在构建作业调度服务器时。

静音风扇

与 Pi 一起,我还购买了一个风扇,即 Pimoroni Fan Shim。根据评论,它是冷却 Pi 的更好方法之一,但现在对我来说发表意见还为时过早。除非安装了控制器软件,否则它将始终全速运行。它并不吵闹,但坐在距离 Pi 一米的地方仍然可以注意到。同样,由于控制器软件需要安装一些先决条件,因此需要进行一些修补。我们在重启之间丢失了 nano,因此我们将继续并再次添加它。

apk update
apk upgrade
apk add nano

我们需要的其他软件位于 Alpine 的“community”存储库中。为了激活该存储库,我们需要编辑一个文件

nano /etc/apk/repositories

取消注释第二行(以 v3.12/community 结尾),退出,然后安装必要的软件包。

apk update
apk add git bash python3 python3-dev py3-pip py3-wheel build-base

在这些先决条件就位后,使用以下命令安装风扇 shim 软件

git clone https://github.com/pimoroni/fanshim-python
cd fanshim-python
./install.sh
apk add py3-psutil
cd examples
./install-service.sh

最后一个脚本将失败并显示“systemctl: command not found”,因为 Alpine 使用 OpenRC 作为其 init 系统,而不是此脚本假定的 systemd。我们将改为编写我们自己的启动脚本

nano /etc/init.d/fanshim

这个新文件应包含以下内容

#!/sbin/openrc-run
name="fanshim"
command="/usr/bin/python3 /root/fanshim-python/examples/automatic.py"
command_args="--on-threshold 65 --off-threshold 55 --delay 2"
pidfile="/var/run/$SVCNAME.pid"
command_background="yes"

您可以探索 fanshim 的许多有趣选项,例如调整其 RGB led。现在我们希望它在启动时运行,因此将其添加到默认运行级别,然后启动它。

rc-update add fanshim default
rc-service fanshim start

享受宁静!

添加和共享磁盘

我们将传输的一些文件将非常大。如果能够从 macOS 的 Finder 中轻松访问文件也很棒,因此我添加了一个 USB3 连接的 4TB 存储硬盘。以下内容与设置 NAS 非常相似,事实上,我爱上 Alpine 的方式是通过从头开始构建我自己的 NAS(主要区别在于磁盘更多并且使用了 zfs)。

首先我们需要更改文件系统。磁盘格式化为 FAT32,这非常不适合网络磁盘。Samba 是我们将用于共享的工具,它或多或少需要一个支持扩展属性的文件系统。插入驱动器后,我们将重新分区驱动器并将其格式化为 ext4。

cfdisk /dev/sda

使用 cfdisk,删除任何现有分区并创建一个新分区。默认情况下它应该变为“Linux filesystem”。在“Quit”之前不要忘记“Write”。然后格式化它

mkfs.ext4 /dev/sda1

现在我们需要添加 autofs 以实现自动挂载。

apk add autofs

为了配置 autofs,首先

nano /etc/autofs/auto.master

在以 /misc 开头的未注释行之后添加以下行。它还将在 5 分钟后断开硬盘连接以节省能源

/-   /etc/autofs/auto.hdd   --timeout=300

然后创建这个新的配置文件

nano /etc/autofs/auto.hdd

将以下行添加到空文件中。

/hdd   -fstype=ext4   :/dev/sda1

现在,需要创建用户 pi。

adduser pi
smbpasswd -a pi

为 pi 用户选择所需的密码。后一个密码稍后将存储在 macOS 钥匙串中,因此很容易忘记,因此请将其记录在某个地方。

将 autofs 添加到启动项并立即启动它。将 /hdd 的所有权更改为 pi。

rc-update add autofs default
rc-service autofs start
chown -R pi.pi /hdd

完成这些设置(可以通过 /hdd 访问磁盘)后,就该设置共享了。为此,我们将使用 samba 和 avahi 进行网络发现。

apk add samba avahi dbus
nano /etc/samba/smb.cfg

现在,这是我的整个 smb.cfg 文件的样子,其中包含使 macOS 上的内容运行良好的所有调整。

[global]
 create mask = 0664
 directory mask = 0775
 veto files = /.DS_Store/lost+found/
 delete veto files = true
 nt acl support = no
 inherit acls = yes
 ea support = yes
 security = user
 passdb backend = tdbsam
 map to guest = Bad User
 vfs objects = catia fruit streams_xattr recycle
 acl_xattr:ignore system acls = yes
 recycle:repository = .recycle
 recycle:keeptree = yes
 recycle:versions = yes
 fruit:aapl = yes
 fruit:metadata = stream
 fruit:model = MacSamba
 fruit:veto_appledouble = yes
 fruit:posix_rename = yes 
 fruit:zero_file_id = yes
 fruit:wipe_intentionally_left_blank_rfork = yes 
 fruit:delete_empty_adfiles = yes 
 server max protocol = SMB3
 server min protocol = SMB2
 workgroup = WORKGROUP    
 server string = NAS      
 server role = standalone server
 dns proxy = no
[Harddisk]
 comment = Raspberry Pi Removable Harddisk                     
 path = /hdd    
 browseable = yes          
 writable = yes            
 spotlight = yes           
 valid users = pi       
 fruit:resource = xattr 
 fruit:time machine = yes
 fruit:advertise_fullsync = true

如果您对将磁盘用作 Apple 设备的 Time Machine 备份不感兴趣,则可以删除最后两行。我可能不会使用它,但由于这是我配置 NAS 的方式,并且弄清楚如何使其工作很麻烦,所以我认为我会将其留在这里以供参考。以任何方式将其保留在那里都没有害处。

让我们也配置 avahi-daemon,方法是为 samba 服务创建一个配置文件。Avahi 将使用 Bonjour 公告服务器,使其易于从 macOS 中识别(它们会自动显示在 Finder 中)。

nano /etc/avahi/services/samba.service

这个新文件应包含以下内容

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">%h</name>
<service>
<type>_smb._tcp</type>
<port>445</port>
</service>
<service>
<type>_device-info._tcp</type>
<port>0</port>
<txt-record>model=RackMac</txt-record>
</service>
<service>
<type>_adisk._tcp</type>
<txt-record>sys=waMa=0,adVF=0x100</txt-record>
<txt-record>dk0=adVN=HDD,adVF=0x82</txt-record>
</service>
</service-group>

请注意,如果您对将磁盘用作 Time Machine 备份不感兴趣,则可以删除包含 adVN=HDD 的 txt-record。尽管如此,保留它也不会有任何坏处。

最后,是时候将 samba 和 avahi 添加到启动项并启动服务了。

rc-update add samba default
rc-update add avahi-daemon default
rc-service samba start
rc-service avahi-daemon start

现在应该可以从 macOS 中看到该磁盘了。记住单击“Connect as…”并输入“pi”作为用户名和您之前选择的 smbpasswd。选中“Remember this password in my keychain”框,以便下次更快地访问。有时,由于 Catalina 中的一个错误,当访问远程磁盘时,您可能会收到“The original item cannot be found”。如果发生这种情况,强制退出 Finder,您应该可以再次正常使用。如果有人知道解决此问题的任何其他方法,请告诉我!

自动化

现在,此服务器将用作作业服务器。运行的某些作业将需要 PostgreSQL 中的 psql 命令,而另一些作业将是 R 作业。让我们安装两者,或者任何您需要满足您需求的程序。如果您不确定要运行什么或者只需要内置 shell 脚本等基本服务,您可以暂时跳过此步骤。

apk add R postgresql

为了自动化这些作业,我们将使用 Cronicle。它依赖于 node.js,因此我们需要安装先决条件。它的运行脚本是使用 curl 获取的,因此也需要安装它。

apk add nodejs npm curl

安装按如下方式完成(即使它看起来在此处已损坏,它也是一个单行程序)。

curl -s https://raw.githubusercontent.com/jhuckaby/Cronicle/master/bin/install.js | node

我想使用标准端口,因此我需要稍微更改配置。

nano /opt/cronicle/conf/config.json

将 base_app_url 从端口 3012 更改为 80。在更下方的位置,将 http_port 从 3012 更改为 80,将 https_port 从 3013 更改为 443。如果您希望发送邮件,请将文件开头的 smtp_hostname 更改为您正在使用的邮件中继。之后,需要运行初始化脚本。

/opt/cronicle/bin/control.sh setup

现在我们只需要让它在启动时运行。但是,这是一项我们不想使用 PID“终止”的服务,因此我们将启用本地脚本,以便以受控方式启动和停止服务。

rc-update add local default
nano /etc/local.d/cronicle.start

这个新文件应包含以下行

/opt/cronicle/bin/control.sh start

现在我们需要创建一个停止文件

nano /etc/local.d/cronicle.stop

该文件应包含以下内容

/opt/cronicle/bin/control.sh stop

为了使本地脚本守护程序运行这些脚本,它们需要是可执行的。

chmod +x /etc/local.d/cronicle.*

完成这些操作后,让我们保护安全。

加固

现在大多数配置都已完成,是时候加固 Pi 了。首先,我们将使用 iptables 中内置的“limit”安装一个防火墙,并提供一些基本的登录保护。假设您位于 setup-alpine 期间设置的 192.168.1.0/24 范围内,则应运行以下命令。只有本地网络上的客户端才能访问共享文件夹。

apk add ufw@testing
rc-update add ufw default
ufw allow 22
ufw limit 22/tcp
ufw allow 80
ufw allow 443
ufw allow from 192.168.1.0/24 to any app CIFS
ufw allow Bonjour

完成规则设置后,是时候禁止通过 ssh 进行 root 登录,并确保仅使用最新的协议。

nano /etc/ssh/sshd_config

将之前显示 yes 的行更改为 no,并在文件底部添加其他行(从这个安全站点借用)

PermitRootLogin no
PrintMotd no
Protocol 2
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com

之后,启用 ufw 并重启 sshd。请注意,如果此处出现问题,您将需要再次插入显示器和键盘以本地登录并修复问题。

ufw enable
rc-service sshd restart

现在是重启并重新连接以检查一切是否正常工作的好时机。

reboot

由于 root 无法登录,您将改为以“pi”身份登录。此用户可以通过以下命令(临时,直到退出)提升权限

su

另一种选择是使用 sudo,但我现在将保持这样,然后继续设置一些作业。那是另一篇文章的故事了。

我希望本指南对您有所帮助。它应该对任何在他们的 Raspberry Pi 上修补 Alpine 的人有用,并且可能对在不同硬件上运行其他 Linux 发行版的人也有用。