释放小七猫的分享欲

Linux 系统的 NAS 之路——存储

tags: NAS, Linux
@ 16/07/2026

Linux 系统的 NAS 之路——多用户存储

本部分讲解存储相关的内容。存储这一块比较灵活,每个人适应的使用方式也不同,这一部分简单分享一下用户量不大的情况下如何分配存储池及权限。

之前部分的内容是使用虚拟机完成的,从这一部分开始,所有的内容都是我个人使用实体机得到的经验。

RAID 与 mergerfs

先介绍一下两者的区别:

  • 本质不同:RAID 是“拼硬盘”(在系统底层把多块盘合成一块),mergerfs 是“拼文件夹”(在用户层面把多个目录合并成一个入口)。
  • 数据读写:RAID 会拆分文件并行读写(快);mergerfs 不拆分文件,每个文件完整存在某块盘上(单文件速度不变)。
  • 数据安全:RAID 有冗余(如 RAID 1/5 可坏盘不丢数据);mergerfs 无冗余,坏哪块盘就丢哪块盘上的文件。
  • 灵活扩展:RAID 扩盘麻烦,常需重建;mergerfs 即插即用,随时增减硬盘。

要性能 + 安全选 RAID;要省心 + 灵活(尤其硬盘大小不一)选 mergerfs。也可以“RAID 打底,mergerfs 统一管理”两者结合用。

不推荐在 NAS 上使用 RAID,我更推荐多备份或者 mergerfs+snapraid 方案。

硬盘管理

硬盘监控与挂载

可以通过 cockpit 面板初始化、格式化、挂载以及监控各硬盘的状态。

不过这种挂载不是持久的,要想持久挂载,必须配置 /etc/fstab。

# units generated from this file.
UUID=2095ed95-b940-4659-8e1d-12470c188a01  /      btrfs  defaults  0  0
UUID=C6F2-34F8 /boot/efi vfat umask=0077,shortname=winnt 0 2
UUID=06521c64-6896-4e73-848e-83d39224506a  /home  btrfs  defaults  0  0

# 数据盘挂载
UUID=263b4390-ccd5-41a9-901d-403c38c4cc84  /vol1  ext4   defaults,noatime  0  0
UUID=e7cc4e75-7d28-4841-8955-41e929ee7ccb  /vol2  btrfs  defaults,noatime  0  0
UUID=0baf7434-99a5-4e6c-bf70-b1bf7fb01eee  /vol3  btrfs  defaults,noatime  0  0
UUID=8b8f1072-20a9-4384-91ef-9d5e5ab66ec1  /vol4  btrfs  defaults,noatime  0  0

存储池

如果要在 Fedora server 上使用 mergerfs 做存储池,需要安装它,但官方仓库中没有这个包,因此需要添加 copr 源:

sudo dnf copr enable gotmax23/mergerfs

然后 sudo dnf update;sudo dnf install mergerfs 即可完成安装。

我将每个硬盘单独格式化并分别挂载到 /vol1-/vol4

sda           8:0    0   2.7T  0 disk
└─sda1        8:1    0   2.7T  0 part /vol3
sdb           8:16   0   2.7T  0 disk
└─sdb1        8:17   0   2.7T  0 part /vol4
sdc           8:32   0  10.9T  0 disk
└─sdc1        8:33   0  10.9T  0 part /vol2
sdd           8:48   0  10.9T  0 disk
└─sdd1        8:49   0  10.9T  0 part /vol1

然后将其中的某些文件夹合并成 mergerfs:

# MergerFS 挂载
/vol1/public/视频文件:/vol2/@public/@视频文件  /vol-mfs/视频  fuse.mergerfs  defaults,allow_other,use_ino,category.create=epmfs,minfreespace=100G,dropcacheonclose=true,cache.files=partial,nonempty  0  0

# MergerFS 挂载
/vol3:/vol4  /vol-mfs/资料  fuse.mergerfs  defaults,allow_other,use_ino,category.create=epmfs,minfreespace=100G,nonempty  0  0

可以看到,mergerfs 可以把不同格式的分区合并成一个。

/vol-mfs/ 就形成了一个大的存储池:

❯ ls /vol-mfs
.  ..  视频  资料
❯ df -h
文件系统                               大小  已用  可用 已用% 挂载点
...                               7.8G   26M  7.7G    1% /tmp
3:4                                    5.5T  2.3T  3.3T   42% /vol-mfs/资                              11T  9.3T  1.1T   91% /vol1
1/public/视频文件:2/@public/@视频文件   22T   20T  2.2T   90% /vol-mfs/视频
...

如果是 RAID 方案的话,RAID 出来的就是一个大存储池,可以很方便地挂载到任意位置,并创建文件夹。

后续就假设所有存储池都在 /vol-mfs/

权限管理

如果 NAS 只有一个用户,那一切都好说,只要确保这个用户对需要访问的文件有权限就行。但一旦用户多于 1 位,就要考虑隐私的问题,我们不希望用户 2 去访问用户 1 的隐私文件。同时,我们希望某些存储池是可以大家一起访问的。

❯ tree -L2
.
├── 视频
│   └── Videos
└── 资料
    ├── 1000
    ├── 1001
    └── public

例如,我这里有视频和资料两个存储池,其中,视频是所有人都可以访问的,而资料中的 public 为所有人可访问,但 1000 和 1001 文件夹只能让对应用户访问。

要实现这个需求,最简单的方式是 acl,直接给对应权限即可。

但我还是想用最原始的方法解决这个问题,因为用户数不多并且权限管理没有那么精细。

如果你有很多用户,并且各自权限存在交叉,那么一定要用 ACL 来简化管理。

通过以下命令授予 1000 用户访问权限:

cd 资料
sudo chown -R 1000:1000 1000/
# 700 也可以,更安全,750 够用
sudo chmod -R 750 1000/

sudo chown -R 1001:1001 1001/
# 700 也可以,更安全,750 够用
sudo chmod -R 750 1001/

对于共享的文件夹,可以将它们的用户组设为 100(users 组),并将需要访问的用户加入 users 组。

sudo chown -R 1000:100 public/
sudo chmod -R 775 public/

这种方式用起来一般不会出问题,但有时候一些新创建的文件没有继承文件夹的属组,可能导致无法访问的问题。新创建的文件默认继承创建者的主要组(primary group),而不是父目录的组。

针对这个问题,可以在目录上设置 SGID 位,强制该目录下所有新建文件和子目录自动继承父目录的属组。

# 1. 确保目录属组为 users (100)
sudo chown -R 1000:100 public/

# 2. 设置 SGID 位 (2775) + 现有文件权限 775
sudo chmod -R 2775 public/

此外,还需要配合 umask 确保组可写

SGID 解决了组继承问题,但新文件的权限还受 umask 影响。如果用户的 umask 是 0022,新文件权限为 644,组内用户仍然无法写入。

ACL

前文内容针对用户权限的管理还是比较复杂的,各种配置权限,SGID 位,用户、文件夹一多,管理起来就很麻烦了。

针对这种情况,ACL 可以用最简单的方式解决这个需求。

还是以 public 文件夹为例:

# 为目录设置默认 ACL,让新文件默认组可读写
sudo setfacl -d -m g:users:rwx public/
sudo setfacl -m g:users:rwx public/

使用 ACL 后,即使 SGID 未生效,新文件也会按照 ACL 规则赋予组权限。

ACL 常用操作有以下几个:

(内容为 AI 生成)


1. 查看 ACL

# 查看文件的 ACL
getfacl 文件名

# 查看目录的 ACL(含默认 ACL)
getfacl 目录名

输出示例:

# file: public/
# owner: user1
# group: users
user::rwx
group::rwx
group:users:rwx          # 额外添加的组权限
mask::rwx
other::r-x
default:user::rwx        # 默认 ACL(新建文件继承)
default:group::rwx
default:mask::rwx
default:other::r-x

2. 为特定用户设置权限

# 让用户 zhangsan 对文件有读写执行权限
setfacl -m u:zhangsan:rwx 文件或目录

# 让用户 zhangsan 只有读权限
setfacl -m u:zhangsan:r-- 文件或目录

3. 为特定组设置权限

# 让组 developers 有读写执行权限
setfacl -m g:developers:rwx 文件或目录

# 让组 testers 有读执行权限
setfacl -m g:testers:rx 文件或目录

4. 设置默认 ACL(新文件/子目录继承)

默认 ACL 会传递给目录下新建的文件和子目录,现有文件不受影响。

# 让新建文件默认继承 users 组的 rwx 权限
setfacl -d -m g:users:rwx 目录名

# 让新建文件默认让 zhangsan 有 rwx 权限
setfacl -d -m u:zhangsan:rwx 目录名

5. 删除 ACL 条目

# 删除特定用户的 ACL
setfacl -x u:zhangsan 文件或目录

# 删除特定组的 ACL
setfacl -x g:developers 文件或目录

# 删除所有默认 ACL
setfacl -k 目录名

# 彻底清除所有 ACL(恢复为传统权限)
setfacl -b 文件或目录

6. 递归应用 ACL

# 给目录及所有子目录/文件添加 ACL(不设置默认)
setfacl -R -m g:users:rwx 目录名

# 给目录及所有子目录设置默认 ACL(仅目录会继承默认设置)
setfacl -R -d -m g:users:rwx 目录名

注意:-R 只影响当前已存在的文件,-d 影响未来新建的文件。两者常配合使用。


7. 复制 ACL

# 将文件A的ACL复制给文件B
getfacl 文件A | setfacl --set-file=- 文件B

# 将目录A的ACL复制给目录B
getfacl 目录A | setfacl --set-file=- 目录B

总的来说,如果你需要精细化的权限控制,就必须使用 ACL,完全看应用场景。如果用户数不大,存储池层数不多,传统的 ugo/rwx 权限模型已经足够满足需求。

私有云系统

有时候我们并不满足于单纯的文件存储功能,我们还希望拥有网页查看文件、协同办公、外网分享等等功能。