Raspberry Pi 4 - 充当 NAS 和 Time Machine 的持久系统
本页面记录了在 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 发行版的人也有用。