Matrix 首页推荐
Matrix 是少数派的写作社区,我们主张分享真实的产品体验,有实用价值的经验与思考。我们会不定期挑选 Matrix 最优质的文章,展示来自用户的最真实的体验和观点。
文章代表作者个人观点,少数派仅对标题和排版略作修改。
前言
我有两个树莓派 4B,其中一个我当作了一个电视盒子,具体可以看我之前的文章。不过我买树莓派最初的目的,是想将它作为一个小型服务器,在挂载硬盘后进行文件共享,并在后台运行下载器进行 BT 下载,所以另外一个树莓派就被委以了这项重任。
对于如何将树莓派作为一个小型服务器,我尝试过很多方案。关于系统选择与配置,容器的使用,以及软件的选择,我想我最近终于找到了一个比较满意的答案。虽然不敢说这是个正经的 NAS,但却多少算是手搓了个 NAS 系统吧。
系统的选择
在树莓派上可用的 NAS 系统不多,我知道的只有 openmediavault,我在很久之前安装过一次,感觉不太好用。因为我还是有一点 Linux 的使用经验的,所以在很多时候,成品 NAS 系统的图形化界面对我来说反而是累赘,很多时候进行一些高级配置还是没有直接用终端方便,而且还占用了很多资源。因此我一直以来都是直接用普通的 Linux 发行版,在上面手动配置 smb 文件共享与其他服务。我一直以来都比较习惯在服务器上用 Debian 系的发行版,而且树莓派官方的 Raspberry Pi OS 就是基于 Debian 的,自然 Raspberry Pi OS 就是我最常用的系统,虽然期间我也尝试其他的系统,比如 Ubuntu,甚至是 Manjaro,但是最终都又回到了 Raspberry Pi OS。
不过一直以来 Raspberry Pi OS 都有一个问题困扰我,就是这个系统偏向于教学用途和作为玩具折腾,对于服务器用途,稳定性和软件维护还是有点欠佳,我有点馋红帽系发行版每个大版本五年的软件更新和十年的安全更新,所以就在最近,我尝试着把我正在运行的云服务器,以及树莓派,都换成红帽系的发行版。
目前比较推荐使用的红帽系的发行版有 AlmaLinux 和 Rocky Linux。在红帽改变 CentOS 的定位让其「名存实亡」以及决定不公开 RHEL 源码后,红帽下游的发行版进入过短暂的六神无主的状态,因为这些发行版最初的目的是要达到与 RHEL 百分百兼容,AlmaLinux 和 Rocky Linux 对此的解决方案不完全相同:AlmaLinux 项目不再追求与 RHEL 百分百兼容,而只是做到二进制兼容,也就是说任意为 RHEL 开发的软件都可以在 AlmaLinux 上运行,但不一定会产生相同的 bug;而 Rocky Linux 则是设法绕过了红帽的限制,从其他渠道获取到了 RHEL 的源码,尽量做到与 RHEL 百分百兼容。对于普通的用户,两个发行版用起来大概率几乎没有区别,不过 AlmaLinux 能更快跟进上游的更新,Rocky Linux 则会迟一些。另外 AlmaLinux 还提供了一个迁移工具,可以从旧的 AlmaLinux 升级到新版本,也可以从其他的红帽系发行版迁移到 AlmaLinux,而 Rocky Linux 目前不支持版本迁移。我个人比较倾向选择 Alma Linux,我的其他云服务器目前也都迁移到了 Alma Linux。
不过我在树莓派上最终还是安装了 Rocky Linux,在我最初安装时,虽然 AlmaLinux 和 Rocky Linux 都已经跟进上游推出了 V10 大版本,但 AlmaLinux 在官网上依然没有适用于树莓派的 V10 版本安装镜像可供下载,而 Rocy Linux 10 已经有了树莓派安装镜像。不过在我写这篇文章时,我发现 Rocky Linux 官网的树莓派安装镜像下载选项也消失了,不知道什么原因😂。
(后来我又在 Rocky Linux 的官方论坛里发帖询问了这件事,社区管理员说会「修复」这个问题,现在在官网应该可以直接下载树莓派的镜像了)
系统的下载与安装
如果想要更快的下载速度,可以去国内镜像站下载系统镜像,比如从中国科学技术大学开源软件镜像站下载,我对比过校验值,和我之前在 Rocky Linux 官网下载到的镜像是完全一样的。
系统的安装就很简单了,使用刷写工具,比如 balenaEtcher 或是树莓派官方的 Raspberry Pi Imager,将镜像刷写入 SD 卡中,然后将其插入树莓派中,插电启动即可。
这个系统镜像默认会启用 ssh 服务,插上网线就可以直接用 ssh 远程登入了,默认的用户名和密码分别是 rocky/rockylinux,登入以后,就可以对系统做一系列配置了。
一些初始化配置
扩展存储空间
这个系统镜像默认没有使用全部的 SD 卡空间,想要使系统使用全部的存储空间,只需运行 sudo rootfs-expand
就可以自动扩展空间了。
配置软件源
Rocky Linux 默认的软件源会根据当前的网络位置自动选择最近的镜像站,所以一般情况下无需换源也能有比较快的软件下载速度,而且红帽系的软件源配置文件改起来比较麻烦,所以我就没有换源。
首先进行系统更新:
sudo dnf update
# 或
sudo dnf upgrade
其实现在红帽系的 dnf 包管理器已经把 dnf update
alias 到了 dnf upgrade
,所以上面两个命令其实是一样的,都是更新软件源并更新系统,随便选一个就行。更新完最好重启一下。
之后添加 EPEL 软件源,这是一个适用于红帽系发行版的第三方软件源,包含了很多常用但官方软件源没有的软件包:
# 添加软件源
sudo dnf install epel-release
# EPEL 的很多软件依赖官方的 crb 软件源,所以需要启用这个软件源
sudo /usr/bin/crb enable
EPEL 默认的软件源在国内是挺慢的,所以这次需要换源了,以北京外国语大学开源软件镜像站为例:
sudo sed -e 's!^metalink=!#metalink=!g' \
-e 's!^#baseurl=!baseurl=!g' \
-e 's!https\?://download\.fedoraproject\.org/pub/epel!https://mirrors.bfsu.edu.cn/epel!g' \
-e 's!https\?://download\.example/pub/epel!https://mirrors.bfsu.edu.cn/epel!g' \
-i /etc/yum.repos.d/epel{,-testing}.repo
之后再次运行 sudo dnf update
更新一次即可。
问题修复
这个 Rocky Linux 镜像目前存在一个问题,就是会让树莓派的 CPU 默认运行在省电模式,这个模式下 CPU 的频率会一直处在 600MHz,无法上升到更高的频率。要验证这个问题是否存在,可以安装 stress
和 btop
两个软件包,stress 用来给 CPU 进行压力测试,而 btop 可以用来实时监控 CPU 频率。打开两个 ssh 窗口连接到树莓派,一个窗口运行 btop,默认布局下会在右上角显示目前的 CPU 频率,另一个窗口运行 stress -c 4 -t 60
,表示运行一个持续时间 60 秒、4 个线程的 CPU 压力测试,如果 CPU 的频率一直是 600MHz,就说明树莓派是运行在省电模式下的。

参考官方论坛中的这个帖子,解决方法也比较简单,首先安装 kernel-tools
软件包,之后创建一个新的 systemd 服务文件 /etc/systemd/system/cpupower.service
:
[Unit]
Description=Configure CPU power related settings
After=syslog.target
[Service]
Type=oneshot
RemainAfterExit=yes
EnvironmentFile=/etc/sysconfig/cpupower
ExecStart=/usr/bin/cpupower $CPUPOWER_START_OPTS
ExecStop=/usr/bin/cpupower $CPUPOWER_STOP_OPTS
[Install]
WantedBy=multi-user.target
之后启用服务:
sudo systemctl daemon-reload
sudo systemctl enable --now cpupower.service
然后再次运行一次压力测试,正常没有超过频的树莓派 4B CPU 频率是可以达到 1.5GHz 的,如果在压力测试时频率上升到 1.5GHz,压力测试停止后又回落到 600MHz,就说明问题已经解决了。
用户配置
首先要修改默认密码,这个很简单,运行 passwd
,按提示输入旧密码然后输入两次新密码即可,输密码的时候不会显示,这些都是 Linux 用户习以为常的了,不必多说。
不过这个系统默认的用户名是 rocky,我有点不太习惯,用久了 Raspberry Pi OS 后,我还是习惯用户名是 pi,其实我大可以新添加一个名为 pi 的用户,但是这样的话,新的用户和用户组的 id 就不是最常用的 1000 了,这让强迫症有些难受。
其实也是有办法把现有的用户改名的,不过 Linux 系统不允许修改目前正在使用的用户,所以在改名之前,需要以 root 用户登陆,修改 /etc/ssh/sshd_config
,在最后添加一行 PermitRootLogin yes
以允许 root 用户登陆 ssh,之后运行 sudo systemctl restart sshd
重启 ssh 服务,然后运行 sudo passwd root
为 root 用户设置一个密码,之后便可以退出当前账户的登陆,然后重新以 root 用户登陆,在以 root 用户登陆的情况下,运行:
# 把用户名 rocky 改为 pi
usermod -l pi rocky
# 把用户组也改名成 pi
groupmod -n pi rocky
# 把用户 pi 的家目录改为 /home/pi
usermod -d /home/pi -m pi
之后便可以重新以用户 pi 登陆到树莓派的系统了。为了安全起见,最好把之前在 /etc/ssh/sshd_config
所做的修改复原并重启 ssh 服务以禁止 root 登陆,然后运行 sudo passwd -l root
锁定 root 用户。
语言、时区与时间同步
这个系统镜像默认语言是英语,可以根据自己的需要修改为中文,运行 localectl
可以查看当前使用的语言,运行 locale -a
可以列出当前可用的所有语言,运行 sudo localectl set-locale LANG=zh_CN.UTF-8
可以把语言设置成中文。
运行 timedatectl
可以查看当前使用的时区,系统默认使用的是 UTC 时区,要想修改时区,运行 timedatectl list-timezones
可以查看当前所有可用的时区,然后运行 sudo timedatectl set-timezone Asia/Shanghai
可以将时区修改为上海,其实就是中国的时区,因为绝大多数 Linux 发行版都以上海作为中国的时区。
Rocky Linux 默认使用 chrony 作为时间同步服务,并且默认使用的 ntp 服务器位于国外,可能导致时间同步失败,因为树莓派 4B 没有硬件时钟,所以时间同步失败就会很麻烦。我们可以将默认 ntp 服务器修改为国内可用的 ntp 服务器,编辑 /etc/chrony.conf
,在文件开头找到这样一行:
pool 2.rocky.pool.ntp.org iburst
修改为:
pool ntp.aliyun.com iburst
其实就是把 ntp 服务器修改为了阿里云的公共 ntp 服务器,为了万无一失,还可以把服务器的 ip 填入 hosts 文件里,防止 DNS 解析出错,编辑 /etc/hosts
,添加一行:
203.107.6.88 ntp.aliyun.com
系统精简
这个系统镜像其实默认就已经很精简了,但还是有一些我用不到且占用资源的组件。首先我卸载了防火墙软件 firewalld 和 wifi 管理软件 wpa_supplicant。因为这个树莓派只运行在内网,我不打算将其开放到公网,所以防火墙可有可无,而且 firewalld 还挺占资源的;另外我是只打算用网线连接路由器,用不到无线网络,所以 wpa_supplicant 也不需要。
sudo dnf remove firewalld wpa_supplicant
接着是 SELinux,这是一个由红帽开发的 Linux 安全组件,可以阻止一些高危操作。Rocky Linux 自带了 SELinux 而且默认运行在严格模式,这个模式下很多操作都会被拒绝,比如开放非常规端口什么的,并且 SELinux 在后台运行也会消耗一定资源。因为我明确知道我在做什么,所以我打算禁用 SELinux,SELinux 牵扯到很多系统组件,没法直接卸载,但可以通过配置文件禁用它,编辑 /etc/selinux/config
,找到 SELINUX=enforcing
改成 SELINUX=disabled
,重启系统之后,运行 sestatus
,就可以看到 SELinux 已经被禁用了。
如果不想禁用 SELinux,可以在配置文件里把 SELinux 的模式改成 permissive 宽容模式,或是手动添加允许规则,至于如何添加规则,这就不是本文探讨的内容了,而且我也不懂🤣,具体可以看 SELinux 的官方文档。
安装并配置管理面板
对于如何配置 smb 文件共享以及后续的系统维护,其实我可以直接从终端配置,但太麻烦了,为了一劳永逸,我打算安装 Cockpit,这是一个可以用来管理 Linux 系统的网页面板,并且能通过安装插件来扩展功能,十分好用。实际上,国外知名的企业级 NAS 定制厂商 45Drives 所使用的 NAS 系统就是 Rocky Linux 8 加上一个定制的 Cockpit 网页面板,并且 45Drives 把相关的项目都在 github 上开源了出来,我这次就用到了一些 45Drives 开发的 Cockpit 插件。
安装并配置 Cockpit 本体:
运行:
# 安装 Cockpit 软件包
sudo dnf install cockpit
# 启用 Cockpit
sudo systemctl enable cockpit.socket --now
要注意启用的是套接字 socket 而不是服务 service,因为 Cockpit 自带的 systemd 服务文件无法直接启用,而且启用套接字有一点好处,就是他不会在开机时就开始运行,而是只在需要的时候才会开始运行,这会提升一点开机速度,并且节省一点资源。
然后在同一局域网下的另一台电脑浏览器中输入树莓派的 ip 加上端口 9090,就可以打开 Cockpit 后台了,因为使用了自签证书,浏览器会提示不安全,不用管选择继续访问就行,登陆的用户名和密码就是系统的用户名和密码。登入后会默认处于限制访问模式,无法进行一些高级操作,需要点击主页的「Turn on administrative access」,再输入一次密码后,才能打开管理员模式。这时就可以进行一些基本的系统管理了,比如软件更新和修改网络,还可以在浏览器中打开终端。

挂载并管理外接硬盘
要想在 Cockpit 中挂载外置硬盘,可以安装 cockpit-storaged 插件:
sudo dnf install cockpit-storaged
安装完成后刷新 Cockpit 网页,就可以在左边的侧栏上看到有个「存储」选项了,在这里可以看到连接的外置硬盘,可以对其格式化和挂载。可以看到我的硬盘识别为了 sda,并且挂载到了 /mnt/share
,只需手动挂载一次,之后每次系统启动都会自动挂载了。

要想修改挂载目录的访问权限,可以安装 cockpit-files 插件:
sudo dnf install cockpit-files
刷新之后就可以在看到「文件浏览器」选项了,浏览到 /mnt
目录,单击选择挂载到的 share
目录,点击右上角三个点,选择编辑权限,把所有者和所有组都改成 pi,点击下方的「Change permissions for enclosed files」修改所有子目录的权限。之后这个目录就可以用普通用户访问并编辑了。

文件共享
要想在 Cockpit 中配置文件共享,可以用 45Drives 的 cockpit-file-sharing 插件,另外还推荐安装 cockpit-identities 来管理 smb 的密码。因为 45Drives 的插件是针对 Rocky Linux 8 版本开发的,README 里面的自动安装方式也只适用于 Rocky Linux 8,对于更新的 Rocky Linux 版本,只能手动安装了,需要从 Releases 下载最新版本的 rpm 文件,然后手动安装。
可能因为版本问题 cockpit-file-sharing 在安装时依赖没有装全,少了 samba 软件包,所以还要手动装一下 samba:
sudo dnf install samba
刷新后就可以在 Cockpit 里看见「File Sharing」和「Identities」两个选项了。第一次打开 File Sharing 可能会提示「Samba is Misconfigured」,点下方的「Fix now」让它自动修复即可。

这个插件可以配置 Samba 和 NFS 共享。Samba 共享这里,在下面的「Share Configuration」这里添加新的共享,填上共享的名字、共享的目录,下面的选项基本保持默认就好,点击「Apply」就算是配置好了。NFS 共享就更简单了,添加共享,填上共享的目录和需要的 ip 就可以了,我这里只给我的笔记本电脑(设置了静态 ip 192.168.0.106)开放了 NFS 共享,局域网内其他设备是无法访问的。

在 Linux 下 Samba 的密码和用户密码是分开存储的,需要单独设置,点击「Identities」选项,选择「Users」,选择自己当前的用户,翻到下面,点击「Change Samba Password」,在这里输入密码即可。

这时其实还无法访问共享的文件,因为 Samba 和 NFS 服务还没有启用,在 Cockpit 的「服务」选项卡里,搜索并找到 smb 服务,将其启用,同样的方法,搜索并找到 nfs-server 将其启用,如果想要局域网内的其他电脑自动发现 smb 共享,也可以选择启用 avahi-daemon 服务。这时文件共享就算是配置好了。

其他 Cockpit 插件
Cockpit 还有很多有用的插件,比如 cockpit-zfs-manager 用来创建并管理 ZFS 阵列,和 cockpit-machines 可以用来创建并管理虚拟机。可以在这里查看 Cockpit 所有可用的插件。
另外 45Drives 目前正在开发新的 cockpit-zfs 插件,用来代替旧的 zfs manager 插件,不过目前还在早期开发阶段,感兴趣的可以关注下。
容器管理
除了文件共享,我常用的大部分服务都是用容器部署的,在 Docker 之外还有很多容器化解决方案,比较值得一提的就是 Podman,而且 Podman 也是红帽主导开发的,号称完全兼容 Docker,并且有很多 Docker 没有的特色功能,比如以普通用户权限运行容器、Quadlet 可以用 systemd 管理容器服务等等,并且 Cockpit 也有一个 Podman 插件,可以将容器管理一同集成到 Cockpit 面板里面。
不过我实际用下来觉得 Podman 还是没有 Docker 好用,Quadlet 配置文件写起来实在没有 compose 配置文件简单易上手,想要让多个容器互联也非常麻烦。虽然可以通过安装 podman-compose 来兼容 compose 文件,但仍然存在很多奇奇怪怪的兼容性问题。所以最终我还是决定用 Docker。
安装 Docker
我最初是参照着 Docker 官方的 RHEL 安装文档,但是发现 Docker 的软件源目前似乎还没有 RHEL 10 的版本,所以会安装失败。需要参照 CentOS 的文档:
# 安装 dnf-plugins-core 用来管理软件源
sudo dnf -y install dnf-plugins-core
# 添加 Docker 软件源
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 换源
sudo sed -i 's+https://download.docker.com+https://mirrors.bfsu.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
# Docker 依赖 iptables,可以首先安装 nftables 提供的 iptables 实现,以防止安装到旧的 iptables
sudo dnf install nftables iptables-nft
# 安装 Docker
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 启用 Docker 服务
sudo systemctl enable docker.service --now
# 将当前用户加入 docker 用户组,后续运行 docker 命令无需使用 sudo
sudo groupadd docker
sudo usermod -aG docker $USER
容器管理
Cockpit 有一个 Docker 插件,但已经很久没有更新了,不过好在 Docker 的生态很丰富,有很多适用于 Docker 的网页管理面板,最知名的当属 Portainer 了,不过 Portainer 的用法对我来说太复杂了,而且我也用不到它的很多高级功能。就在最近我发现了一个比较新的项目:Dockge,这是一个十分简单但好用的 Docker compose 管理工具,因为我所有的容器服务都是通过 Docker compose 部署的,所以它完美地解决了我的痛点。Dockge 的作者另一个更加知名的项目是 Uptime Kuma,所以不用担心它的开发质量,另外它的界面也会和 Uptime Kuma 有点像。
Dockge 是需要通过 Docker compose 的方式安装的,去到 Dockge 的官网,可以自动生成所需的 compose 文件,只需要填上自己打算存放 compose 文件的目录以及想要开放的端口,就能自动生成可用的 compose 文件内容了。这里我打算将 compose 文件存放在家目录的 containers 文件夹里,也就是 /home/pi/containers
,端口保持默认 5001。

然后回到终端:
# 创建并进入必要文件夹
mkdir -p /home/pi/containers/dockge
cd /home/pi/containers/dockge
# 下载 compose 文件
curl "https://dockge.kuma.pet/compose.yaml?port=5001&stacksPath=%2Fhome%2Fpi%2Fcontainer" --output compose.yaml
# 启动
docker compose up -d
如果想要在 Dockge 网页面板里运行终端命令,还需要在 compose 文件里添加一个环境变量 DOCKGE_ENABLE_CONSOLE=true
,我的 compose 文件是这样的:
services:
dockge:
image: louislam/dockge:1
container_name: dockge
mem_limit: 256mb
restart: unless-stopped
ports:
- 5001:5001
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/app/data
- /home/pi/containers:/home/pi/containers
environment:
# Tell Dockge where to find the stacks
- DOCKGE_STACKS_DIR=/home/pi/containers
- DOCKGE_ENABLE_CONSOLE=true
其中我还添加了 mem_limit: 256mb
来限制容器可用的内存大小,因为我的树莓派只有 2G 内存,后期运行的服务多了内存可能会不够用,所以需要限制一下,256mb 也完全够 Dockge 运行了。
不过树莓派上的 Rocky Linux 默认是不支持为容器添加内存限制的,所以上面的选项默认会被忽略,要想使内存限制生效,需要添加一个内核参数,编辑 /boot/efi/cmdline.txt
,应该只有一行内容,在行末添加一个 cgroup_enable=memory
,不要另起一行,还要和前面的内容间隔一个空格。修改完后重启,容器的内存限制应该就能生效了。
Dockge 部署完成后,在同一局域网下的另一台电脑浏览器中输入树莓派的 ip 加端口 5001,就可以打开 Dockge 的管理面板了,第一次打开需要设置用户名和密码。
使用 Dockge 可以非常直观地编辑容器常用的的运行选项,开放端口、文件系统映射以及环境变量等都可以在这里编辑,对于不支持的运行选项,也可以直接编辑右侧的 compose 文件。

如果实在不知道如何编辑 compose 文件,Dockge 甚至还支持将 docker cli 命令直接转换成 compose 文件。

另外,Dockge 会把已经添加的 compose 文件整齐地放在各自的文件夹里原样保存,这意味着我们仍然可以用其他编辑器编辑 compose 文件,也可以很容易地将之前的的 docker-compose 项目导入 Dockge,只需按照每个 compose 文件都放在单独的文件夹的规则,将已有的 compose 文件放到 Dockge 保存文件的目录(在我这里就是 /home/pi/containers
),Dockge 就能够自动识别并导入。
总结
因为篇幅原因,本篇只介绍了我在树莓派 4B 上安装并配置系统的过程,在 Rocky Linux 上,通过安装 Cockpit 和 Dockge 可以实现比较方便的图形化系统管理的容器管理,虽然相比正经的 NAS 系统易用性还是差一些,但对于有一定 Linux 运维知识的人来说有更高的自由度。
我之后可能会再写一篇文章,介绍一下我当前部署的容器服务,以及具体的配置方法。
> 关注 少数派小红书,感受精彩数字生活 🍃
> 实用、好用的 正版软件,少数派为你呈现 🚀