家庭服务管理:NAS

1 一个NAS都应该能做什么

我是一个经历了家庭互联网从无到有的人,小的时候家里有个电视就算是富裕家庭了,一般的家庭还仅限于有个收音机;后来逐渐的,电视,彩色电视,电话,录像机,那个时候还有一种叫录像厅的地方呢,又租录像带的地方,5毛钱一周;然后出现了VCD,DVD,大哥大,BB机,掌中宝娱乐的东西越来越丰富。

之后我到外面上高中,那是2002年,那个时候已经有网吧了,但是电脑还不是普通家庭可以承受的。

等到我上了大学的时候,就到了2005年,彼时,小灵通还有一席之地,网吧遍地开花,上网一个电话,车接车送,包夜5元还送面包和可乐。但是学校里有笔记本的同学依然是少数,很多时候大家还是用U盘和MP3,MP4来互相拷贝东西,移动硬盘由于造价比较高,并不普及,而且,120G的都算是大容量存储了。

等毕业后,移动硬盘算是比较普及的,但是依然不大,320G和500G的都算大容量了,因为那个年代,资源的体积也是很小的。

逐渐的,很多东西变成了消费品,手机的普及,家庭宽带的普及,3G的出现和4G的升级,互联网才开始完全平民化,我个人来讲,3G的出现时一个转折点,4G的出现让很多想法得以实现。资源的质量也越来越高,以前的120p的资源,到后来的480,然后进化到720p,1080p;后来之间开始普及的2k,4k,蓝光等。存储空间也开始越来越便宜,从1T的hdd到现在消费级别的1T的ssd。

手机,电视,电脑,这是家庭的网络基础互联装备,以前一个硬盘到处插不觉得麻烦,现在建个网路共享我都觉得不方便,所以逐渐的,开始了NAS的路线。

NAS所需的功能,和是否需要NAS都是看个人和家庭的需求是否有必要,否则就是吃灰的产品。那么一个NAS,对我来讲需要以下的功能。

1.1 流媒体

彼时靠文件夹来分辨是什么电影,什么电视剧等等,资源混在一起,或者分成不同目录,甚至不同的硬盘装不同的东西,但是看的时候依然麻烦,而且目前网页观看也成为了大家容易接收的方式,以前电脑必装的千千静听,realplayer,xmplaoer,potplayer等等播放器,如今也变的鲜少有人问津。所以,流媒体服务就成为了一个比较基础的功能,应该能够做到,海报,简介,自动下载字幕,播放,分类这些基础的功能,下面是能够满足这几项条件的推荐。

  • Jellyfin

免费,开源,.Net Core,有TV端,Android端,网页端,PC端,而且,都免费,但是有点小缺点,就是硬解,遇到不支持的格式的就会强制硬解,而且使用服务端硬解,而不会使用本地硬解。

  • Emby

Jellyfin就是从这分家的,因为Emby有收费订阅,TV端就需要订阅,其他的几乎一样。据说硬解能力比Jellyfin强。

  • Plex

这是个很强的产品,大部分都推荐的,但是,订阅后体检更好。TV,手机端都需要订阅后才能用,这个好像是本地硬解,不占用服务器资源,只用了一次,所以不是很确定。

  • elfilm

http://getelfilm.com/

1.2 下载

  • qBittorrent

同时满足了BT下载和挂PT的需求,以前一直都是使用aria2的,但是aria2下载BT和PT需要单独的配置,不能一个端直接满足,所以,最后还是使用了这个。

  • aria2

老牌下载工具

1.3 Home Assistant

基础的家庭物联网工具,我是比较早接触智能家居设备的,这也导致了我家的产品比较割裂,空气净化器是,空调是格力的,扫地机是小米的,电视是乐视的,可视猫眼是叮咚,门锁是美的,有了HomeAssistant后,可以将其中一部分整合到上面。

1.4 旁路网关

流畅的网络体验。

1.5 文件共享

Linux下比较流行的就是SMB,但是现在看来,好像并不是常用的了。

1.6 可扩展性

1.6.1 Docker

1.6.1.1 Home Assistant

家庭物联网

1.6.1.2 qBittorrent

既满足bt又能满足pt

1.6.1.3 Jellyfin

多端免费的媒体管理,自动刮削,硬解。

1.6.1.4 签到

免去了每天手动签到的麻烦过程,但是gthub actions可以替代。

1.6.1.5 百度云

1.6.2 虚拟机

1.6.2.1 windows

挂游戏,一般来说我来玩传奇的时候会挂机。

1.6.2.2 linux

我用来ssh,远程管理k8s。其实nas本身就是Linux。

1.7 云

  • Nextcloud

1.8 ZeroTier

  • 异地访问
  • VPN直连

frpc

  • 内网穿透

1.9 选用什么系统?

1.9.1 群晖

1.9.1.1 黑群晖

内网穿透、稳定的应用(也不一定)、同步、备份。
虽然免费,但是升级什么的比较麻烦。

1.9.1.2 白群晖

内网穿透、稳定的应用(也不一定)、同步、备份、稳定、可升级、贵。

我觉得性价比不高。

1.9.2 ProxmoxVE(推荐★★★★★)

其本质上是一个Debian系统,用起来熟悉。

1.9.2.1 zfs存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ls -l /dev/disk/by-id/
total 0
lrwxrwxrwx 1 root root 9 Dec 30 10:29 ata-SCWW_SSD_16G_0000000000000 -> ../../sda
lrwxrwxrwx 1 root root 10 Dec 30 10:29 ata-SCWW_SSD_16G_0000000000000-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 Dec 30 10:29 ata-SCWW_SSD_16G_0000000000000-part2 -> ../../sda2
lrwxrwxrwx 1 root root 10 Dec 30 10:29 ata-SCWW_SSD_16G_0000000000000-part3 -> ../../sda3
lrwxrwxrwx 1 root root 9 Dec 30 10:29 ata-ST99999999-******-****** -> ../../sdc
lrwxrwxrwx 1 root root 9 Dec 30 10:29 ata-TOSHIBA_******_****** -> ../../sdb

#raid-0
zpool create -f -o ashift=12 nas /dev/disk/by-id/ata-ST99999999-******-****** /dev/disk/by-id/ata-TOSHIBA_******_******

# 加新硬盘
zpool attach nas /dev/disk/by-id/ata-ST88888888-******-******

上面完成后会在根目录下生成一个nas文件夹,就是存储池的空间了。

软raid
创建存储池
做为目录

1.9.2.2 软路由

1
qm importdisk 100 /nas/20201229-Ipv4P-Mini-x86-64-generic-squashfs-combined-efi.img nas-local

1.9.2.3 lxc

做软路由
虚拟机

1.9.3 FreeNAS(推荐★★★)

免费

1.9.4 OMV(OpenMediaVault)

免费、功能过于基础。

1.9.5 Windows Server(推荐★★★★)

免费,这点可能很多人不知道,Windows Server Core是有免费版本的。只是没有桌面环境,但是已经Windows Server了,桌面环境除了浪费空间和资源外,真的就没什么用了。

HyperV可以直接使用Windows Admin Center可以直接进行管理,也可以使用Windows10 的hyper-V远程管理。

硬件直通对硬件本身要求较高,但是一般也够用了。

用起来操作很熟悉。

1.9.6 Ubuntu Server

1.9.7 UNRAID

据说硬件直通性能非常好,但是收费,虽然有破解版。

1.9.8 ESXI

老牌。

1.10 硬件上最好有什么?

1.10.1 网卡

  • 千兆
  • 万兆

1.10.2 Raid卡

  • 多硬盘,也可以用软raid

1.10.3 热插拔

  • 多盘位

1.10.4 USB3

  • 打印机

1.10.5 DC电源

  • 静音

1.10.6 1+N块硬盘

  • 组RAID

2 NAS服务管理

2.1 Jellyfin

2.1.1 电影多版本管理

Wonder Woman 1984这部电影为例,我的电影都是放在/nas/movies里的,所以目录结构是这样的:

1
2
3
4
5
6
7
8
movies/
└── Wonder.Woman.1984.2020
├── Wonder.Woman.1984.2020 - 1080P.mkv
├── Wonder.Woman.1984.2020 - 1080P.china.srt
└── Wonder.Woman.1984.2020 - 2160p.mp4
└── Wonder.Woman.1984.2020 - 8k.mp4
└── Wonder.Woman.1984.2020 - 不是导演剪辑版.mp4
└── Wonder.Woman.1984.2020 - 山寨版.mp4

根据jellyfin文档显示,当多个不同格式的版本合并起来的时候,需要让文件名与文件夹名保持一直然后再后面加{空格}{连字符}{空格}{版本标签}的形式,这样jellyfin就可以进行识别,在电影的界面中就可以进行版本的切换选择,在这一点上不如plex方便了。 其中标签是可以自定义的,连字符不支持.和空格。

** 官方的文档中推荐的文件夹名是Wonder.Woman.1984 (2020) ,但是实际使用中我发现Wonder.Woman.1984.2020也是可以的,在文件管理上,名字中带有空格对我来讲会不大习惯,所以可以根据自己习惯选择对名称的管理。

参考链接

2.1.2 字幕中的方块

一般的解决方式都是在字幕中进行设置,这种方式是使用转码烧录的形式,对cpu和内存都会进行消耗,对于性能比较低的nas来说,压力很大,比如我的j1900矿渣。目前有一个简单的解决办法,升级到>Jellyfin 10.7.0的版本,目前还是rc版,这个版本支持加载自定义的字体了控制台>播放>备用字体文件路径,就解决了。

2.2 docker-compose

2.2 1 安装docker

1
2
3
4
5
apt update
apt install apt-transport-https
apt upgrade -y
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
echo "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list

2.2 2 修改镜像源

/etc/docker目录中添加一个文件daemon.json,文件内容如下

1
2
3
{
"registry-mirrors": ["https://oohnp2oa.mirror.aliyuncs.com"]
}

然后执行

1
2
systemctl daemon-reload
systemctl restart docker.service

参考链接

2.2 3 安装docker-compose

1
apt install docker-ce docker-compose

2.2 4 前期准备

创建子网隔离,非必须。

1
docker network create --subnet 10.10.10.0/24 pve-subnet

该处的pve-subnet对应下面docker-compose.yml文件中networks节点下的name,可以忽略,docker-compose会自动建立。

2.2 5 为什么使用docker-compose

docker虽然部署与管理变的容易,但是当遇到版本升级的时候就需要重新使用命令行进行一次部署,然而很多时候我都懒得进行本分,目前工作中使用的是k8s,在家用nas上我觉得实在是没必要,于是比较传统的docker-compose就是一个很好的解决方案。
每当有版本升级的时候只要修改docker-compose.yml文件中对应的镜像标签,然后重新docker-compose up -d就自动进行拉取部署升级,不会影响其他未修改配置的镜像,就方便很多了。

2.3 Home Assistant

2.3.1 调用本地图片

configuration.yaml文件的位置建立一个www文件夹,将要引用的文件放进去,在配置文件中使用/local对应的就是www文件夹中的文件,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 blueprints
│   └── automation
│   └── homeassistant
│   ├── motion_light.yaml
│   └── notify_leaving_zone.yaml
├── configuration.yaml
├── deps
├── groups.yaml
├── home-assistant.log
├── home-assistant_v2.db
├── scenes.yaml
├── scripts.yaml
├── secrets.yaml
├── tts
└── www
└── floorplan.png

如果要在配置中调用www/floorplan.png则对应的配置文件为:

1
2
3
4
5
6
7
8
type: picture-elements
image: /local/floorplan.png
elements:
- type: state-badge
entity: binary_sensor.updater
style:
top: 65%
left: 38%

2.3.2 水位流量采集

我在天气好的时候会出去钓鱼,但是松花江如果在汛期的时候涨水,有些地方就去不了了,为了不耽误时间,我发现松辽水利网每天8点会发布一次当前的水位流量,所以我进行了采集,这样出门前看一下水位和流速来判断可以去哪个地方钓鱼,避免白跑一趟。

configuration.yaml下面加入下面的内容,就可以在面板中加载进来了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sensor:
- platform: scrape
resource: http://www.slwr.gov.cn/swjgzfw/sssq.asp
name: slwr shuiwei
select: 'script'
index: 1
scan_interval: 3600
value_template: >-
{{ (value | replace ("cvt(","") | replace (");","") | replace ("'","") ) }}
- platform: scrape
resource: http://www.slwr.gov.cn/swjgzfw/sssq.asp
name: slwr liuliang
select: 'font'
index: 8
scan_interval: 3600

2.3.3 小米扫地机器人

第一二代的小米扫地机,使用的是Token的方式加入的,目前有一个简单的工具https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor 运行后输入账号密码就可以获取到局域网中的IPToken设备Id,我们这里使用IPToken就够了。
获取到信息后,在configuration.yaml下面加入下面的内容,就可以在面板中加载进来了。

1
2
3
4
vacuum:
- platform: xiaomi_miio
host: 192.168.0.69
token: **********************************

2.3.4 格力宁韵空调

https://github.com/RobHofmann/HomeAssistant-GreeClimateComponent
下载最新版本解压后如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|   climate.yaml
| configuration.yaml
| info.md
| LICENSE
| README.md
|
+---.github
| \---ISSUE_TEMPLATE
| bug_report.md
| feature_request.md
|
\---custom_components
\---gree
climate.py
manifest.json
__init__.py

如果configuration.yaml同级目录下没有custom_components则直接复制进去,如果已经存在,则复制下面的greecustom_components下,然后在复制climate.yamlconfiguration.yaml同级目录,之后编辑``configuration.yaml同级目录加入一行climate: !include climate.yaml`。

使用格力+接入空调,这样就能在路由器中看到空调的IPMAC,下面会用到,虽然我是在苏宁购买的,但是苏宁的app实在是不好用,于是下载了格力+,在添加设备的时候直接选择宁韵,然后重置空调的wifi,就可以连接了,如果连不上,那么修改wifi里的2.4G无线模式11gb开头的模式。

之后编辑climate.yaml中的内容:

1
2
3
4
5
6
7
8
9
10
- platform: gree
name: 起一个名字,例如ningyun_ac
host: 空调的IP地址
port: 7000
mac: '空调的MAC地址,可以是-分隔,也可以是:分隔'
target_temp_step: 1
lights: input_boolean.first_ac_lights
health: input_boolean.first_ac_health
sleep: input_boolean.first_ac_sleep
powersave: input_boolean.first_ac_powersave

2.3.x lovelace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
title: 保利·上城
views:
- panel: false
title: Home
icon: 'hass:home-assistant'
badges: []
cards:
- type: vertical-stack
cards:
- type: 'custom:weather-card'
entity: weather.bao_li_shang_cheng
number_of_forecasts: '5'
- type: horizontal-stack
cards:
- type: entity
entity: sensor.slwr_shuiwei
name: 水位
unit:
- type: entity
entity: sensor.slwr_liuliang
name: 流量
unit: 立方米
- type: picture-elements
elements:
- type: state-icon
entity: vacuum.xiaomi_vacuum_cleaner
style:
top: 65%
left: 35%
- type: state-icon
entity: climate.ningyun_ac
style:
top: 8%
left: 35%
image: /local/floorplan.png
- type: vertical-stack
cards:
- type: thermostat
entity: climate.ningyun_ac
name: 格力宁韵
- type: picture-glance
image: /local/img/vacuum.png
entities:
- entity: vacuum.xiaomi_vacuum_cleaner
tap_action:
action: more-info
hold_action:
action: none
title: 小米
entity: vacuum.xiaomi_vacuum_cleaner

2.4 syncthing

资源占用小,内网发现,全球发现,内网穿透。

要注意的是从其他设备同步过来的文件夹,默认情况下会出现在/config下,

2.5 frp

如今我遭遇了无法在家的问题,但是手机里的资料还是要同步回家里的NAS,尝试了ngrok、autossh等方案之后,最后还是选定了老牌的frp,之前也用过,但是不知道是版本的问题还是配置的问题,会导致我的网络卡死,这次重新尝试后发现,很稳定,资源的消耗也变小了,在vps上使用nginx绑定泛域名到frps,然后再用frps绑定泛域名,之后直接使用子域名访问各个服务。

2.5.1 服务端nginx配置/etc/nginx/conf.d/nas.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
server {
listen 80;
server_name *.phub.ml;
return 301 https://$host$request_uri;
}

server {
# listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl http2; # managed by Certbot
server_name *.nas.com;

ssl_certificate /etc/letsencrypt/live/nas.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/nas.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot

client_max_body_size 500m;
client_body_buffer_size 256k;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
proxy_connect_timeout 300s;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_buffer_size 64k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_ignore_client_abort on;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
#gzip_http_version 1.0;
gzip_comp_level 5;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary off;
gzip_disable "MSIE [1-6]\.";
location /api/websocket {
proxy_pass http://127.0.0.1:27001/api/websocket;
proxy_read_timeout 60s;
proxy_set_header Host $host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-for $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
location / {
proxy_pass http://127.0.0.1:27001;
proxy_set_header Host $host;
proxy_redirect off;
proxy_buffering off;
proxy_http_version 1.1;
proxy_ssl_server_name on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

2.5.2 服务端的frps配置/etc/frp/frps.ini

1
2
3
4
5
6
7
8
[common]
bind_addr = 0.0.0.0
bind_port = 7557
bind_udp_port = 5775
token = ***************************
vhost_http_port = 27001
vhost_https_port = 5443
tcp_mux = true

2.5.3 客户端的frpc配置frpc.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[common]
server_addr = 000.000.000.000
server_port = 7557
tcp_mux = true
token = *******************

[ssh]
type = tcp
local_port = 22
remote_port = 20002

[qBittorent]
type = http
local_port = 8008
custom_domains = bt.nas.com

[syncthing]
type = http
local_port = 8384
custom_domains = sync.nas.com

[images]
type = http
local_port = 8698
custom_domains = images.nas.com

[openwrt]
type = http
local_ip = 192.168.0.253
local_port = 80
custom_domains = gw.nas.com

[movies]
type = http
local_port = 8096
custom_domains = movies.nas.com

2.5.4 重点内容

  • nginx中的proxy_pass http://127.0.0.1:27001对应到frps.ini中的vhost_https_port = 5443
  • frps.ini中的bind_port = 7557对应到客户端中的server_port = 7557
  • frpc中会出现[E] [control.go:158] [c4426f709c4d9725] work connection closed before response StartWorkConn message: EOF的错误信息,目前没找到解决办法,但是还没发现耽误使用的情况

附录

linux下rename命令进行批量重命名

1
2
3
4
rename 's///g' *.mp4
例如
rename 's/cowboy\.bebop\.//g' *.mkv
将cowboy.bebop替换为空,也就是删掉

其中s为开始,第一个/后面写要查找的字符串,第二个/进行分隔,第三个/前面写替换的字符串,然后g结尾

特殊字符用\进行转义,包括空格[]{}().\~!@#$%^&*_+-=;:’”<>,?`之类的,总之就是会影响正则的都要进行转义

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
version: "3.3"
services:
qbittorrent:
image: ghcr.io/linuxserver/qbittorrent:amd64-latest
container_name: qbittorrent
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Shanghai
- UMASK_SET=022
- WEBUI_PORT=8008
volumes:
- /nas/opt/qbittorrent/config:/config
- /nas:/downloads
ports:
- 6969:6969
- 6969:6969/udp
- 8008:8008
restart: always
deploy:
resources:
limits:
cpus: '0.5'
memory: 200M
home-assistant:
image: homeassistant/home-assistant:2020.12.1
container_name: home-assistant
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Shanghai
volumes:
- /etc/localtime:/etc/localtime:ro
- /nas/opt/home-assistant/config:/config
restart: always
network_mode: 'host'
deploy:
resources:
limits:
cpus: '0.5'
memory: 200M
syncthing:
image: ghcr.io/linuxserver/syncthing
container_name: syncthing
hostname: syncthing
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Shanghai
volumes:
- /nas/syncthing:/config
ports:
- 8384:8384
- 22000:22000
- 21027:21027/udp
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
networks:
default:
external:
name: pve-subnet

启动start.sh文件里,直接使用bash start.sh启动。

1
docker-compose --compatibility -f docker-compose.yml up -d

停止了stop.sh文件里,直接使用bash stop.sh停止。

1
docker-compose --compatibility down

增加--compatibility参数是因为docker不是swam的模式的情况下,deploy节点下对资源的限制是不起作用的。