缘起
我对 NAS 的需求主要是存储的需求——我手里有很多照片需要整理和存储,并提供容灾备份(我很喜欢 这个项目)。除此之外,由于我对 Linux/Docker/服务器都有比较多的折腾经验,因此也时常会燃起“折腾一套 homelab” 的想法。
immich
immich-app • Updated Jul 9, 2024
因此趁着毕业季,我从同学的手里入手了一个“DIY”的 NAS,重点的硬件参数如下:
- CPU:i3-10100
- 内存:16G
- 存储空间:512 SSD + 4 个 4T HDD
之所以需要超出一般消费级 NAS 的内存和 CPU,是因为我对 Docker 有强需求,需要给未来的可能需求留出硬件性能。
使用 NixOS 作为操作系统
最近一段时间,由于对 NixOS 提出的“reproducible, declarative and reliable”比较感兴趣;且对其他 NAS 操作系统并没有更多的了解和偏好,因此选用了 NixOS。
装机过程在此不多赘述,值得注意的是,NixOS 的 Graphical ISO image 貌似必须联网才能使用,否则会在安装界面卡住。
由于对快照没有特殊要求,且为了降低运维复杂度,这次我没有使用 Btrfs。我将整个 SSD 挂载在了根目录,并将其余的机械硬盘以 LVM 的方式组成了两个逻辑卷(并挂载到了
/data
下),作为资源的实际存储和备份盘。NixOS 在配置过程中可以用下面两个网站做辅助:
- ‣ 可以方便搜索 packages 和 options。
- ‣ 有一套面向新手的教程,便于快速开始使用 NixOS 、flakes、home-manager。
Self-host 软件
Docker mirror
由于此时 Docker Registry 在我所在的地区无法访问了,因此使用 Cloudflares 的 Workers 弄了个镜像,比如 。网上有很多教程,不在此赘述。
cloudflare-docker-proxy
ciiiii • Updated Jul 9, 2024
Reverse Proxy 与 DNS
Caddy 在易用性上全面超越了 Traefik,因此本 NAS 使用 Caddy 作为反代。具体仓库是:,利用这个仓库,我们仅通过配置 docker compose label 就可以非常方便地将流量从 Caddy 转发到实际的容器端口上。
caddy-docker-proxy
lucaslorentz • Updated Jul 9, 2024
我的域名的服务商就是 Cloudflare,因此我可以通过 Caddy 提供的 ‣ 为我的域名和 wildcard 域名自动签发证书。一个简单的配置如下:
services: caddy: # 注意这里要替换成带有 provider 的镜像 image: lucaslorentz/caddy-docker-proxy:ci-alpine container_name: caddy ports: - 80:80 - 443:443 environment: - CADDY_INGRESS_NETWORKS=caddy networks: - caddy labels: caddy_1: '*.nas.example.com nas.example.com' caddy_1.tls.dns: "cloudflare $CLOUDFLARES_API_KEY" # 用于为 homepage 提供 Admin API caddy_2: ":12019" caddy_2.reverse_proxy: "localhost:2019" caddy_2.reverse_proxy.header_up: Host localhost:2019 caddy_3.admin: ":2019" volumes: - /var/run/docker.sock:/var/run/docker.sock - caddy_data:/data - ./config:/config/caddy restart: unless-stopped networks: caddy: external: true volumes: caddy_data: {}
对于某个服务则可以直接通过 label 指定:
version: '3.7' services: whoami: image: traefik/whoami networks: - caddy labels: caddy: '*.nas.example.com nas.example.com' caddy.1_@whoami: 'host whoami.nas.example.com' caddy.1_handle: '@whoami' caddy.1_handle.reverse_proxy: "{{upstreams 80}}" networks: caddy: external: true
Immich
immich
immich-app • Updated Jul 9, 2024
除了注意增加 caddy 所需的 label 以外,还需注意将存储卷挂载到我们之前组的 LVM (HDD)上面。
由于性能原因,我没有在 NAS 上启用机器学习的镜像。而是在我这台(有独显的)笔记本上不定期的启用 docker,然后让 NAS 上的 immich 定时使用机器学习服务。
在批量导入照片的时候,我发现 immich 在 Windows 底下还有一些 bug,顺手修了一下。
在导入相册之前,还需要针对现有的照片视频资源进行预处理,它们主要包括:
- 对于极其相似的资源,使用 去重(当然 Immich 也提供了对照片的去重)。czkawkaqarmin • Updated Jul 9, 2024
- 由于之前拍摄的视频几乎都是
.MOV
的,采用 H265 的方式进行压制。(没有选择 H264 的主要原因是:H265 可以进一步提高空间利用率)。
- 对于 DJI 录制的极高码率的
.MP4
视频,也再次进行压制(甚至 crf 可以调更大一些)。
需要注意的是,在使用 ffmpeg 时要使用
-map_metadata 0
来保证新视频保留了真正的录制时间。Jellyfin
‣ 用于存放影视资源。目前还没有配置 *arr 周边服务。
为了方便从笔记本传输一些影视资源,我又额外配置了 Samba 并挂载到了笔记本上。
Nextcloud 从入门到劝退
曾经 host 过 nextcloud,对其印象还是比较好的。但是这次 NAS 上我最终决定放弃 nextcloud,原因如下:
- Nextcloud All in One,整体做的比较奇怪,实际上是采用了类似 docker in docker 的方案,导致很多配置是黑盒的。
- Nextcloud 的性能没有我想象得那么好,并且比较吃资源。
- 我对网盘其实没有太多需求,本质上只是需要一个可视化的资源管理器。
因此最终我选用 ‣ 作为替代。
Tailscale
由于没有公网 IP,因此想要在外网访问 NAS 的时候,我通过 ‣ 来解决隧道问题。
由于 Tailscale 会为各个设备自动分配新的 IP,导致一般情况下域名解析失效,因此此时难题是:怎么保证使用 Tailscale 时,能同样通过域名找到我的服务?
首先,Tailscale 自带的 MagicDNS 是无法使用的,因为其既不能自定义域名、也没有 wildcard 解析、更没法进行 DNS Callenge。
好在,Tailscale 提供了自定义 DNS 服务器的能力:
因此我选择在 NAS 上使用 ‣ 自建了一个 DNS,然后按照 Tailscale 的 IP 对域名进行解析。这样就能保证内外网的域名解析是一致的了。
备份策略
本来想使用 进行备份的,但是偶然发现 、更加直观,因此选择了后者。
borg
borgbackup • Updated Jul 9, 2024
restic
restic • Updated Jul 9, 2024
根据两地三副本的策略,在 NAS 上我通过 restic & 定时备份,并会定期将备份 copy 到另一个移动硬盘(也可以考虑云盘)上。
resticprofile
creativeprojects • Updated Jul 9, 2024
硬盘的完整性目前手动通过 SMART 进行检测。
备份 SOP
- 保存最近 4-5 次的 snapshots,过久的数据可以删除。
- 如果有数据写入,则在一周内进行数据 NAS 的 intra-disks 备份。
- 每月将备份数据备份到 NAS 以外的存储介质。该介质尽量远离 NAS 所在的位置。
巡检 SOP
- 每周通过 S.M.A.R.T 检查硬盘状态。(但是很可惜,S.M.A.R.T 状态并不能完全反映硬盘的实际使用能力)如果有异常出现,要:
- 增加备份频率
- 增加备份副本(跨介质)
- 准备备用的存储介质
- 每周通过 restic 校验备份文件是否有损,如有则需及时修复。
恢复 SOP
- 若 SSD 挂了:需要重装系统、相关软件。(TODO:可以将目前的 NixOS 配置和 Docker Compose 文件备份)
- 若直接使用的硬盘挂了:需要更换硬盘,并从备份恢复数据。
- 若备份使用的硬盘挂了:需要更换硬盘,并重新备份。