虽然群晖 NAS 的 DiskStation Manager(DSM)系统操作便于上手,套件中心内的各类工具安装起来也十分方便。但假设你本就有一些 Linux 系统的使用经验,当逐渐适应了使用 DSM,或者说明白 NAS 是怎么一回事后,就会发现,很多步骤(也许)还是直接在 Shell(命令行界面)敲命令来得更趁手一些。

举个在 NAS 上 Shell 使用频率最高的操作:安装 Docker 容器。什么值得买上的大多数文章,除了教你用 Docker 面板安装容器外,有些教程还会教你连接 SSH 后,使用 Docker CLI 命令行安装,例如使用 docker run xxx 这个命令能快速拉起一个容器。Docker CLI 安装当然可以,只是我觉得这种姿势既不够优雅,也不够方便,所以我写了一篇《原来,群晖也能用 Docker Compose!》用来简单介绍 Docker Compose 的使用方法。诚然,你可能会认为使用 Docker Compose 也需要在 Shell 内执行相关命令,也不是有多方便,但 compose 能在部署后修改容器配置,已经要比直接 run 要好得多了。虽然后来,DSM 7 更新了 Docker 面板(现在叫 Container Manager)并支持了 Compose 功能,可实测下来还是 docker compose up -d 更胜一筹。这在 NAS 性能羸弱的情况下更为明显,因为群晖的 Docker 面板可能会因为容器数量众多而崩溃。

而除了部署容器,Shell 内还能执行其他 Linux 指令,例如使用 tree 列出目录树、使用 kill 指令杀掉后台程序等等。换句话说,如果能够充分利用 DSM 的 Shell,就可以发挥其身为 Linux 所应有的功能,从而获得与 DSM 网页端完全不同的使用体验。可也因为 DSM 是魔改的 Linux,默认的 Shell 难用不说,连一个类似 Debian 或 Ubuntu 的包管理工具 APT 都没有,安装 Zsh 乃至 Git 都是问题。不过不要怕,本文的任务就是带领大家缕清思路,在现有的条件下尽可能优化好 DSM 的 Shell,以尽可能少走一些弯路。

但仍有一点要注意:NAS 系统的 Linux 底层主要目的是稳定,便于使用是次要的,因此不要在 Shell 内执行来路不明的命令。

启用家目录

一切开始之前,我们先要启用用户文件夹。因为使用 root 用户并不安全,要养成使用非 root 权限的个人用户操作 Shell 的习惯。

在「控制面板 - 用户与群组 - 高级设置」中,勾选「启动家目录服务」。启用此选项会自动为每个用户创建个人的「home」文件夹。所有用户的个人文件夹名称都为「home」且位于「homes」文件夹中。这样才能在为除了 root 以外的用户安装 ohmyzsh 的时候不会出现目录不存在的报错,每个用户也能配置自己的 Zsh。

登录 Shell

启动 SSH 功能这个大前提我就不再赘述了。

打开 Windows 终端,首先使用命令确认是否安装了 SSH 客户端:

ssh -V

如果输出版本号,那么可以继续操作。否则需要在「系统 - 可选功能 - 添加可选功能」中,安装「OpenSSH 客户端」和「OpenSSH 服务器」。

接着输入 ssh username@ip -p port 连接到 NAS 的 SSH。假设 NAS ip 为 192.168.31.2,SSH 端口设置为 1234,用户为你当前的用户名如 mikusa,连接 SSH 的具体命令为:

ssh mikusa@192.168.31.2 -p 1234

此时会弹出 Are you sure you want to continue connecting (yes/no/[fingerprint])? 的提示,输入 yes 后,再输入你的用户密码即可连接到 SSH。由于输入密码时不可见,密码可以复制后,在终端中右键粘贴后,回车即可。

配置 Shell

安装 Zsh

Z Shell 又称 Zsh, 是一个 Linux 系统中非常流行的命令解释器。功能要比群晖自带的命令解释器强大许多,并且支持自动补全等其他功能。而 ohmyzsh 是 Zsh 的管理工具,可以为 Zsh 安装主题并配置其他社区开发的插件。而本文最主要的目的,就是为了让群晖用上 Zsh。

因为群晖无法使用 sudo apt install zsh 来安装 Zsh,但是有社区将 Zsh 打包成了套件,我们只要安装这个套件即可。

打开群晖套件中心,点击「设置」,选择「套件来源」,点击「新增」。名称随意,在「位置」里填入以下链接:

https://packages.synocommunity.com

应用后稍等一会儿,或者重启套件中心就可以看见新增的「社群」菜单。搜索 「zsh」,安装「Z shell (with modules)」。

由于 DSM 没有 chsh 命令,因此使用别的方法切换 shell 至 zsh。

登录 SSH 后,编辑根目录下的 .profile 文件:

vim ~/.profile

如果存在这个文件,就在最底下加入以下内容;如果没有这个文件,vim 会自动创建这个文件,直接粘贴以下内容:

if [[ -x /usr/local/bin/zsh ]]; then
export SHELL=/usr/local/bin/zsh
exec /usr/local/bin/zsh
fi

一些简单的 vim 用法是:输入 i 开始编辑,右键粘贴,按 ESC 键退出编辑,键入 :wq 保存,键入 :qa 撤销编辑并退出。

后续还会用到 git 命令,所以也一并安装下 Git 吧!

安装 oh my zsh

由于各种各样的网络原因,使用官方脚本自动安装 ohmyzsh 的成功概率太低,所以改为手动安装。

打开终端,登录 SSH,克隆 ohmyzsh 仓库:

git clone https://github.com/ohmyzsh/ohmyzsh.git ~/.oh-my-zsh

如果因为网络问题无法克隆仓库,请自行使用镜像,例如 https://mirror.ghproxy.com/ 。使用时在 https://github.com 前加上该链接即可。

即将原命令修改为:

git clone https://mirror.ghproxy.com/https://github.com/ohmyzsh/ohmyzsh.git ~/.oh-my-zsh

下文不再赘述。

创建新的 zsh 配置文件:

cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

重载配置:

source ~/.zshrc

如果是使用 root 用户操作的,Zsh 及 ohmyzsh 安装到这里就算结束了。而非 root 用户安装到这一步,可能会有如下提示:

[oh-my-zsh] Insecure completion-dependent directories detected:
drwxrwxrwx+ 1 mikusa users 388 Feb 12 18:39 /var/services/homes/mikusa/.oh-my-zsh

[oh-my-zsh] For safety, we will not load completions from these directories until
[oh-my-zsh] you fix their permissions and ownership and restart zsh.
[oh-my-zsh] See the above list for directories with group or other writability.

[oh-my-zsh] To fix your permissions you can do so by disabling
[oh-my-zsh] the write permission of "group" and "others" and making sure that the
[oh-my-zsh] owner of these directories is either root or your current user.
[oh-my-zsh] The following command may help:
[oh-my-zsh]     compaudit | xargs chmod g-w,o-w

[oh-my-zsh] If the above didn't help or you want to skip the verification of
[oh-my-zsh] insecure directories you can set the variable ZSH_DISABLE_COMPFIX to
[oh-my-zsh] "true" before oh-my-zsh is sourced in your zshrc file.

按照提示,键入以下命令就可以修复了:

compaudit | xargs chmod g-w,o-w

安装 Zsh 插件

Zsh 有一堆好用的插件,但我目前只用到了这两个:zsh-syntax-highlightingzsh-autosuggestions

zsh-syntax-highlighting 顾名思义,是一个高亮显示代码的插件,使用 git 命令安装:

git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting

zsh-autosuggestions 是一个命令补全插件:

git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

安装 autojump

这里我还用到了一个自动跳转历史目录的功能 autojump,同样手动安装:

git clone https://github.com/wting/autojump.git

进入目录:

cd autojump

在已经使用 Zsh 作为 Shell 的前提下执行安装脚本,否则会报错:

./install.py

执行后,会输出安装过程:

$ ./install.py
Installing autojump to /var/services/homes/mikusa/.autojump ...
creating directory: /var/services/homes/mikusa/.autojump/bin
creating directory: /var/services/homes/mikusa/.autojump/share/man/man1
creating directory: /var/services/homes/mikusa/.autojump/etc/profile.d
creating directory: /var/services/homes/mikusa/.autojump/share/autojump
copying file: ./bin/autojump -> /var/services/homes/mikusa/.autojump/bin
copying file: ./bin/autojump_argparse.py -> /var/services/homes/mikusa/.autojump/bin
copying file: ./bin/autojump_data.py -> /var/services/homes/mikusa/.autojump/bin
copying file: ./bin/autojump_match.py -> /var/services/homes/mikusa/.autojump/bin
copying file: ./bin/autojump_utils.py -> /var/services/homes/mikusa/.autojump/bin
copying file: ./bin/icon.png -> /var/services/homes/mikusa/.autojump/share/autojump
copying file: ./docs/autojump.1 -> /var/services/homes/mikusa/.autojump/share/man/man1
creating directory: /var/services/homes/mikusa/.autojump/etc/profile.d
creating directory: /var/services/homes/mikusa/.autojump/share/autojump
creating directory: /var/services/homes/mikusa/.autojump/functions
copying file: ./bin/autojump.sh -> /var/services/homes/mikusa/.autojump/etc/profile.d
copying file: ./bin/autojump.bash -> /var/services/homes/mikusa/.autojump/share/autojump
copying file: ./bin/autojump.fish -> /var/services/homes/mikusa/.autojump/share/autojump
copying file: ./bin/autojump.zsh -> /var/services/homes/mikusa/.autojump/share/autojump
copying file: ./bin/_j -> /var/services/homes/mikusa/.autojump/functions

Please manually add the following line(s) to ~/.zshrc:

        [[ -s /var/services/homes/mikusa/.autojump/etc/profile.d/autojump.sh ]] && source /var/services/homes/mikusa/.autojump/etc/profile.d/autojump.sh

        autoload -U compinit && compinit -u

Please restart terminal(s) before running autojump.

提示说要在 .zshrc 中添加一段命令:

[[ -s /root/.autojump/etc/profile.d/autojump.sh ]] && source /root/.autojump/etc/profile.d/autojump.sh
autoload -U compinit && compinit -u

可以不用添加,后续安装完 ohmyzsh 可以直接使用插件配置 autojump。

安装完毕后,就可以删除刚才克隆下来的文件了,看着占地方。

cd ..
rm -rf autojump

坏处是之后要卸载得再 git clone 回来。

配置 oh my zsh

编辑当前用户根目录下的 .zshrc 文件,即可修改 oh my zsh 的配置。我个人能用到的功能不多,也就修改下主题,增加点插件,再配置些命令映射。

使用 vim 编辑 .zshrc 文件:

vim .zshrc

找到 ZSH_THEME 修改主题,例如改成 ys

ZSH_THEME="ys"

接着,找到 plugins 增加插件。除了上面自行安装的 zsh-syntax-highlightingzsh-autosuggestions 外,oh my zsh 内置了许多插件,例如 dockerdocker-compose ,可以在 ~/.oh-my-zsh/plugins 文件夹中找到这些插件,其中包含了具体的插件解释 。此外,再加上先前安装的 autojump

plugins=(git zsh-autosuggestions zsh-syntax-highlighting autojump docker docker-compose z extract sudo cp aliases)

最后,在 .zshrc 文件的最底下添加一些命令映射,比如 acme.sh。

alias dcl="docker system prune -a" #彻底清除 docker 缓存
alias dcu="docker compose up -d  --remove-orphans" #启动容器的同时清除孤立容器
alias acme.sh="docker exec acme.sh acme.sh" #acme.sh

保存完毕后,执行命令刷新 .zshrc 文件:

source .zshrc

演示

简单演示下最终效果,使用 TAB 键自动提示或补全命令。

一键安装及配置

当然,上述一堆繁琐的步骤,其实也不过就是几行命令而已。在已经使用 Zsh 作为 Shell 的前提下,可以直接打包安装:

git clone https://github.com/ohmyzsh/ohmyzsh.git ~/.oh-my-zsh
cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

git clone https://github.com/wting/autojump.git && ./autojump/install.py

git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

sed -i.bak 's/plugins=(\(.*\))/plugins=(\1 autojump zsh-autosuggestions zsh-syntax-highlighting z extract sudo cp aliases docker docker-compose)/' ~/.zshrc

source ~/.zshrc

优化 Shell

这么一番折腾下来,群晖的 Shell 才只是勉强能用。我们还可以执行些额外的操作,方便后续的 Shell 使用。

sudo 免密

使用非 root 用户后,执行一切会动到系统的命令需要加上 sudo 指令。这需要先将该用户添加到 sudo 用户组。使用群晖创建的第一个用户已经在 sudo 用户组内,但执行 sudo 也还是需要输入当前用户的密码,这很麻烦,所以我们要免去使用 sudo 时输入密码的环节。

因为群晖的 Shell 一坨,不能使用 visudo 编辑 /etc/sudoers,所以还是使用 vim 操作。

先确认你的用户名:

id

输出如下,mikusa 就是当前用户的用户名。

$ id
uid=1026(mikusa) gid=100(users) groups=100(users),101(administrators),65537(docker)

接着编辑 /etc/sudoers

sudo vim /etc/sudoers

会让你输入当前用户的密码,然后 i 键入编辑,再方向键跳到最后面,插入:

mikusa ALL=(ALL) NOPASSWD: ALL

其中,mikusa 为你想要免密的用户。千万不要误删或错填了!

然后强制保存:

wq!

这样就能让该用户使用 sudo 命令的时候无需再输入密码了。

使用密钥登录 SSH

群晖上登录 SSH 的话,一般是使用密码。这其实很不安全,也很麻烦。比较极客的操作是为当前用户配置密钥,使用密钥进行登录。

你可以先在电脑的终端上输入以下命令,使用 ed25519 算法生成一个密钥:

ssh-keygen -t ed25519 -C "mynas"

一路回车后,会有如下内容输出:

$ ssh-keygen -t ed25519 -C "mynas"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/c/Users/mikusa/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/mikusa/.ssh/id_ed25519
Your public key has been saved in /c/Users/mikusa/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:QIQ2zmTjGZWXnF80/nfqRhe28UKLIdnt8cHIfuov/dI mynas
The key's randomart image is:
+--[ED25519 256]--+
|     ++o o .o    |
|    O.. =  ...   |
|   B =.. . +o.o  |
|    =  .  + o++* |
|        S  ..=o+O|
|            ..===|
|             .=+ |
|             +o.E|
|            .o+oo|
+----[SHA256]-----+

提示说,公私钥被保存在了 C 盘下的 /Users/mikusa/.ssh 文件夹中。即 C:\Users\mikusa\.ssh ,其中 mikusa 是你的电脑用户名。打开这个文件夹,找到 id_ed25519.pub 公钥文件,复制其中的公钥,将其安装至 NAS 中。

我们先在 NAS 中创建 .ssh 文件夹并赋予权限:

mkdir -p ~/.ssh && chmod 700 ~/.ssh && cd ~/.ssh

安装公钥:

echo 'ssh-ed25519 XXXXXXXXXXXXXXXXX' > authorized_keys

别急着退出,需要进一步修改文件权限:

chmod 600 ~/.ssh/authorized_keys

编辑 SSH 配置文件:

sudo vim /etc/ssh/sshd_config

打开密钥登录功能,找到对应的配置。如果前面有 # 需要删除,并修改后面的 noyes

PubkeyAuthentication yes

重载 sshd:

systemctl restart sshd

在电脑上的 .ssh 文件夹中,我们刚刚生成的私钥名字是 id_ed25519 ,重命名成一个便于记忆的名字,比如 mynas

随后,新建一个名为 config 的文件,填入以下内容:

Host NAS
  HostName 192.168.31.2
  Port 22
  User mikusa
  IdentityFile ~/.ssh/mynas

这应该不用我一一解释含义了吧?

保存完成后,在终端中使用以下命令连接:

SSH NAS

确认使用密钥成功登录后,就可以在 /etc/ssh/sshd_config 配置中禁用密码登录:

PasswordAuthentication no

最后确认是否成功修改了配置:

sudo cat /etc/ssh/sshd_config | grep -E '^PasswordAuthentication|PubkeyAuthentication'

输出

PubkeyAuthentication yes
PasswordAuthentication no

就没问题了,可以使用 systemctl restart sshd 重启 SSH 服务。

使用 Docker

非 root 用户无法直接使用 Docker 命令,我们可以创建一个创建 docker 用户组:

sudo synogroup --add docker

将当前用户加入 docker 用户组:

sudo synogroup --member docker $USER

再将 docker.sock 的用户权限修改为 docker 用户组:

sudo chown root:docker /var/run/docker.sock

就可以正常使用 Docker 命令了。

或者使用 DSM,在「控制面板 - 用户与群组 - 用户群组」中,手动创建一个 docker 用户组,将目标用户添加到该组中,最后在 SSH 中执行修改 docker.sock 的用户权限的命令也是可以的。

最后

经过这一连串的操作,群晖的 Shell 用起来应该会相对原版舒服一些了。可即使优化了群晖 NAS 的 Shell,DSM 系统也不适合用来学习Linux,为了专注存储,DSM 缺失的功能太多,施加的限制也不少。如果想要深度学习 Linux,宁可使用 Windows 的 WSL 功能,也不要直接在 DSM 上执行可能会损坏系统的操作。

最后的最后

我并非专业的程序员,日常用到 Linux 的机会不多,能展示的功能也就到此为止。如果本文有任何技术上的错误,还请不吝指正。

参考