标签 nfs 下的文章

Why

The reason to mount NFS over SSH is simple for my case: my NAS is in my home, but I need to access it from my laptop when I'm outside my home. I chose NFS as I stay at home most of the time, in which case my laptop is in the same LAN as the NAS. There is obviously no need to set up another set of mechanism.

To secure the NAS, it is better that it stays in the LAN. It would be simpler to set only one port mapping rule from the configuration interface of the router, that is the port for SSH (I still need SSH anyway), from LAN port 22 to WAN port 20022.

In this way, I don't need to set up the authentication and encryption for NFS separately.

Installing NFS on the both machines is easy. Mounting can be easily done when connecting directly. However, when trying to mount over SSH, I found the steps found by Google does not work.

How

In my case, NFSv3 is used.

In addition to nfsd, mountd also need to be accessed from the client. By default, mountd uses a random port. However, to access mountd easily, I fixed the port used by mountd by adding those lines to /etc/services of the server:

mount 32759/udp
mount 32759/tcp

After restarting the server to make the changes into effect, running ssh on the client machine to forward the ports:

ssh home.kmxz.net -fNv -p 20022 -L 3049:localhost:2049  
ssh home.kmxz.net -fNv -p 20022 -L 33759:localhost:32759

The next step is to mount the NFS on the client machine:

sudo mount -v -t nfs -o soft,intr,nolock,port=3049,mountport=33759,tcp localhost:/mnt/aufs /mnt/nas

nolock option is necessary, otherwise the client machine will try to lock files on the client itself. tcp is also necessary, as mountproto will be UDP by default, but SSH only support TCP forwarding.

自己电脑上各种资源实在太多,硬盘空间紧张。此时搭建一个 NAS 放在家里就显得很有必要了。于是今年终于动手了。

硬件

IMG_8828.jpg

由于专门的 NAS 硬件太贵,动辄好几千。我便在淘宝上四百多块钱买了一块 12 * 12 cm 的主板,上面带一块 J1800 双核赛扬(有的 Atom 主板尺寸更小功耗更低,然而价格贵了些)。单独购买外置的 12 V 电源时,考虑到可能同时带一块 3.5" 硬盘和一块 2.5" 硬盘,于是买了 7 A 的适配器。又在淘宝上买了一块 3T 的西数红盘(WD30EFRX)作为硬盘。最后,把老笔记本上的 2G SO-DIMM 内存条拆下来装到主板上。

IMG_8844.jpg

现在硬盘和主板直接放在柜子里,不过有个「机箱」更好。我于是拿卡尺量了一下它们的尺寸和螺丝孔的位置,画了一个外壳:由四片亚克力拼成,硬盘放下面,主板放上面。准备到淘宝上找商家切亚克力板,自己拿螺纹塞规钻出螺纹。

frame.png

软件

软件上考虑使用 NFS 实现文件访问。借用办公室的显示器和键盘安装 Ubuntu 15.04 后将 NAS 拿回家,搭建 NFS 服务器。

考虑到网络读写不稳定,且 NAS 很大作用是保证数据即使在其它客户端被攻陷后也不丢失损坏,便想到用 union mount。Union mount 简而言之就是把一个只读目录(lower)和一个可读写目录(upper)映射到同一个目录(union)里。用户读取 union 中的文件时,实际就是从 upper 或 lower 中读取,而用户修改 union 中的文件时,所有改动都会被存进 upper 里。这样 union 看起来就是一个完全可读写的普通目录,然而 lower 目录实际并不会被更改,因此处于相对安全的境地。我只要定期 ssh 到 NAS 上看看具体修改了哪些内容,把确定需要保留改动从 upper 里写入 lower 里就好。

Union mount 现在最常见的两个实现是 AuFS 和 OverlayFS。前者由于被 Docker 采用,前两年忽然又火了一阵,然而实现非常复杂。后者的原理和实现都非常简洁,且在 3.18 时被合并进了 Linux 内核。因此我选择了 OverlayFS,并且专门为其写了一个工具。事与愿违的是,我发现无法在 OverlayFS 之上建立 NFS 服务器(i.e. OverlayFS 无法被 export 到 NFS)。于是我只好改用 AuFS 了,毕竟 AuFS 官方主页里就有 export to NFS 的指南。

具体设置较为简单:AuFS 部分,在 /etc/fstab 中加入

none /mnt/aufs aufs noauto,x-systemd.automount,br=/var/userdata/upper=rw:/var/userdata/lower=ro 0 3

NFS 部分,安装 nfs-kernel-server 后在 /etc/exports 中加入

/mnt/aufs *(rw,async,fsid=0,crossmnt,root_squash,no_subtree_check)

外网访问

就此,NFS 就已经可以在家里的内网放问了。然而,要在外网访问,需要考虑安全的问题。NFSv4 开始支持使用 Kerberos 进行身份验证。然而搭建 Kerberos 相对麻烦,我便想到曲线救国,直接使用 ssh 进行端口转发完成加密和认证。虽然这样会带来一些 overhead,不过由于我在外网访问 NAS 的频率低于在家里访问,所以问题尚不算大。

接下来就是在路由上设置端口转发允许外网访问到 NAS 的 22 端口。首先想到的是 MiniUPnPc,这样不用进入路由器设置里也可以完成端口映射,且不需要 NAS 有固定的内网 IP。然而联通配的路由器没有开启 UPnP。进路由器设置界面,发现里面既无法直接设置端口映射,也无法打开 UPnP。好在根据网上找到的方法破解了它后,就可以设置端口转发了。既然已经进了路由器管理界面,干脆直接给 NAS 设置了固定的 IP,打开固定的端口映射。再配合上 DDNS,就可以畅快地从外网也访问 NAS 了。