坑边闲话:Linux 的系统初始化教程对新手非常有帮助,本文提供一个合适的流程化操作,方便用户使用相关服务。本文遵循最小化安装原则,帮助用户逐步构建自己的 Linux 系统。所谓最小化安装,指的是不添加过多的 package,只包含最基本的系统组件。当然,也不包括图形化界面

前期必看步骤使用 ZFSBootMenu 安装 Linux

重装前先备份

若用户是重装系统,请务必记得备份重要数据,比如

  • zsh 历史记录 ~/.config/zsh/.zhistory
  • systemd 的自定义条目,如
    • 多容器组合启动服务 harbor.service, minio.service
    • ZFS 定期快照任务 zfs_snapshot.service
  • /etc/fstab 的特殊挂载条目
  • 家目录中的工程项目
  • 某些特殊的、只存储在本地的容器镜像孤本

1. 配置常规用户·

遵照 使用 ZFSBootMenu 安装 Linux 指导安装的用户,可以直接跳到本章最后一节,此前的步骤已经轻松地完成了前面的这些内容。

1.1 创建新用户·

最小化安装之后,系统里仅有 root 用户,因此先要在 KVM 界面用命令创建合适的用户。执行下列命令:

1
2
sudo useradd -u <USER_ID> -m -s /bin/bash <NEW_USERNAME>
# sudo useradd -u 1000 -m -s /bin/bash newton

特别注意:<USER_ID> 需要小心设置,一般这是一个大于等于 1000 的整数,如果要使用 NAS 上的 NFS 共享,则最好让 NAS 用户与本机用户的 UID 相同。

1.2 提升新用户的权限·

随后,使用 visudo 解锁新用户的系统权限。

1
visudo

输入以下内容:

1
2
<NEW_USERNAME> ALL=(ALL:ALL) NOPASSWD: ALL
# newton ALL=(ALL:ALL) NOPASSWD: ALL

自此,<NEW_USERNAME> 执行 sudo 命令,不再需要输入密码。请慎重考虑!不建议在 NAS 上做本配置

1.3 修改新用户的密码·

为首次登录顺利,我们需要设置密钥:

1
2
passwd <NEW_USERNAME>
# passwd newton

1.4 以新用户身份连接到服务器·

最后进入路由器(这里以 OpenWrt 为例)后台,查看 dhcp 地址分配数据,找到新系统被分配的 IP 地址。为了进行远程连接,需要安装 openssh-server. 此处默认用户在前期过程中已经安装了该组件。

现在使用 SSH 客户端以 <NEW_USERNAME> 身份连接到 Debian 12 系统,正式开始系统配置!

  • 前期使用 bash 配置;
  • 后期使用 zsh,但是关键的长指令还是采用 bash 兼容语法。

2. 设置 ssh-server·

一般来说,通过 ssh 公钥验证的方式登录最为安全,因此我们连接到新系统的第一步就是配置登录方式。

2.1 设置常规用户的授权公钥·

使用 ssh-keygen 生成一套密钥。

1
2
mkdir -p ~/.ssh
touch ~/.ssh/id_ecdsa ~/.ssh/id_ecdsa.pub && chmod 600 ~/.ssh/id_ecdsa

将通用 ecdsa 公钥添加到授权列表里:

1
echo 'ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAGwcEs0xLUh45IbCnMZhAA55oTXKq+3Ez3m6ylsgYofzfTlLt2mW0FMevUWuTQfem3mostbRYU3iARZaxT2jAtP5QGjt2aMevUfpUhi6604M8LB7DKk7N3T2LX5Qs/epCwZdF89o/FtFA2Zjul7XKkuuFAEwFh1yYxzlczz/SeIXBoGXA== newton@pubkey-v2' >> ~/.ssh/authorized_keys

注意:请将上方代码里的 ecdsa 公钥换成你自己的公钥。

随后,编辑 /etc/ssh/sshd_config 文件以修改 sshd 的配置,相关字段设置含义如下:

  • PasswordAuthentication no:禁止使用密码登录
  • PubkeyAuthentication yes:只开启 ssh 公钥认证
  • Port <SSH_PORT>:更改 ssh 服务的端口为<SSH_PORT>

通过以下 sed 命令修改 /etc/ssh/sshd_config

1
2
3
4
5
6
7
8
9
10
11
12
13
bash -c '
# 交互式获取 SSH 端口号
read -p "New SSH service port (default: 22): " SSH_PORT
SSH_PORT=${SSH_PORT:-22}

# 修改 sshd_config 文件
sudo sed -i -e "s/^#Port .*/Port $SSH_PORT/" \
-e "s/^#PubkeyAuthentication .*/PubkeyAuthentication yes/" \
-e "s/^#PasswordAuthentication .*/PasswordAuthentication no/" \
/etc/ssh/sshd_config

echo "SSH configuration updated. Port set to $SSH_PORT."
'

最后,执行下列命令重启 sshd 服务:

1
sudo systemctl restart sshd.service

以后即可使用 ssh 公钥直接登录系统。

2.2 配置常规用户的公私钥·

在用户的家目录下的 .ssh 目录存放了用户的公钥、私钥等文件。建议先通过 ssh-keygen 生成,随后再使用编辑器修改,保证两个文件的权限正确性。直接创建可能导致文件权限不符合要求,无法生效。先前的创建式操作已经生成了 id_ecdsa 私钥,并设置权限为 600,因此可以继续。

ecdsa 私钥:

1
敏感信息:PASS

ecdsa 公钥:

1
echo "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAGwcEs0xLUh45IbCnMZhAA55oTXKq+3Ez3m6ylsgYofzfTlLt2mW0FMevUWuTQfem3mostbRYU3iARZaxT2jAtP5QGjt2aMevUfpUhi6604M8LB7DKk7N3T2LX5Qs/epCwZdF89o/FtFA2Zjul7XKkuuFAEwFh1yYxzlczz/SeIXBoGXA== newton@pubkey-v2" > ~/.ssh/id_ecdsa.pub

2.3 配置 root 用户的公私钥·

重复上述两个步骤即可,此处不再赘述。

3. 配置 apt 源并安装常用软件·

3.1 编辑 /etc/apt/sources.list·

在国内使用 dpkg 进行软件拉取非常不方便,因为 GFW 的存在使得国际访问体验很差,加上中国大陆的国际出口带宽很低,体验更是糟糕。通过使用国内的 APT 源,可以极大地缓解该问题。执行下列命令将 APT 源更改为清华大学 TUNA 镜像站:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sudo tee /etc/apt/sources.list > /dev/null << EOF
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm main contrib non-free non-free-firmware
deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm main contrib non-free non-free-firmware

deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware
deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware

deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-backports main contrib non-free non-free-firmware
deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-backports main contrib non-free non-free-firmware

deb https://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src https://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware

# deb debian-security bookworm-security main contrib non-free non-free-firmware
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security bookworm-security main contrib non-free non-free-firmware
EOF

官方源

若清华 TUNA 不可用或者用户在海外,可以使用 Debian 的官方源。

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo tee /etc/apt/sources.list > /dev/null << EOF
deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware

deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware

deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware

deb http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm-backports main contrib non-free non-free-firmware
EOF

无需重启任何服务,即可使用新的源。如果要正确配置源优先级,可编辑 /etc/apt/preferences.d/stable 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sudo tee /etc/apt/preferences.d/stable > /dev/null << EOF
Package: *
Pin: release a=stable
Pin-Priority: 900

Package: *
Pin: origin "deb.nodesource.com"
Pin-Priority: 950

Package: *
Pin: origin "download.docker.com"
Pin-Priority: 950

Package: *
Pin: origin "pkgs.tailscale.com"
Pin-Priority: 950
EOF

# 优先使用 backport 中的 ZFS 模块:
sudo tee /etc/apt/preferences.d/90_zfs > /dev/null << EOF
Package: src:zfs-linux
Pin: release n=bookworm-backports
Pin-Priority: 990
EOF

其中,Pin-Priority 的数值越高,代表优先级越高。

为了让每次 apt 操作都显示版本号,可以编辑 apt 配置项目:

1
2
3
sudo tee /etc/apt/apt.conf.d/99show-versions > /dev/null << EOF
APT::Get::Show-Versions "true";
EOF

如此一来,每次使用 apt 操作软件均会提示包版本号。

3.2 安装常用软件·

常用以下软件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 更新 apt
sudo apt update

# 2. 升级现有软件 (应该不多,否则就是你没选择合适的 DVD 镜像)
sudo apt update && sudo sudo apt upgrade && sudo apt dist-upgrade

# 3. 安装常用软件
sudo apt install cockpit cockpit-machines cockpit-pcp
sudo apt install bat curl exiftool man-db mediainfo pandoc pv ripgrep rsync tmux tree wget zsh
sudo apt install bridge-utils dnsutils iperf iperf3 net-tools systemd-resolved systemd-timesyncd

# ==> 编辑配置: /etc/systemd/resolved.conf (参考下面的 sed 命令)
# ==> 重启服务: sudo systemctl restart systemd-resolved.service

sudo apt install btop duf gdu htop iotop neofetch open-vm-tools prometheus-node-exporter s-tui sysstat
sudo apt install cifs-utils fio nfs-common open-iscsi python3-libzfs
sudo apt install bison clang cmake flex g++ gcc gdb git luarocks make openjdk-17-jdk repo ruby vim
sudo apt install libfuse2 libssl-dev

# 4. 后面会单独配置 docker-ce,因此不要安装 docker.io

注意

安装了 systemd-resolved 之后有可能无法上网,毕竟该服务会重新配置系统 DNS. 无妨,直接修改配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bash -c '
# 交互式输入 DNS 服务器地址,提供默认值 8.8.8.8
read -p "DNS server address (default: 8.8.8.8): " DNS_SERVER
DNS_SERVER=${DNS_SERVER:-8.8.8.8} # 如果未输入,使用默认值

# 检查是否输入
if [[ -z "$DNS_SERVER" ]]; then
echo "Error: DNS server cannot be empty."
exit 1
fi

# 修改 /etc/systemd/resolved.conf
sudo sed -i \
-e "s/^#DNS=.*/DNS=${DNS_SERVER}/" \
-e "s/^#FallbackDNS=.*/FallbackDNS=1.1.1.1/" \
-e "s/^#Domains=.*/Domains=littlenewton.cn/" \
/etc/systemd/resolved.conf

echo "DNS server editing done. Current DNS: ${DNS_SERVER}"
'

将配置文件中的 DNS 改成内网 DNS 即可!

3.3 获取 python·

3.3.1 安装 miniconda·

1
2
3
4
5
mkdir -p ~/bin && cd ~/bin
TARGET_DIR=${HOME}/bin/miniconda3 # 默认安装位置
curl -o /tmp/Miniconda3-latest-Linux-x86_64.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh && \
bash /tmp/Miniconda3-latest-Linux-x86_64.sh -b -p ${TARGET_DIR}
source ${TARGET_DIR}/bin/activate

3.3.2 安装常见的 Python 包·

1
2
3
conda install python
conda upgrade --all
conda install jupyter ipython

3.4 获取 golang·

Go 是很重要的一个基础语言,目前很多 NeoVim 的插件也依赖 Go 环境。然而,Debian 的上游 Go 版本较低,经常遇到组件要求更高 Go 版本的情况。为此我们选择手动安装。

转到 Go 官网下载页面

执行以下脚本可自动化安装最新版 Golang.

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
#!/bin/bash

# 设置安装目录
INSTALL_DIR="/usr/local/go"
TMP_DIR="/tmp"

# 获取最新版本号并提取正确的版本格式
LATEST_VERSION=$(curl -s 'https://go.dev/VERSION?m=text' | grep -oE 'go[0-9]+\.[0-9]+\.[0-9]+')

# 检查是否成功获取版本号
if [ -z "$LATEST_VERSION" ]; then
echo "Failed to fetch the latest Go version."
exit 1
fi

# 拼接下载链接
GO_DOWNLOAD_URL="https://go.dev/dl/${LATEST_VERSION}.linux-amd64.tar.gz"

# 打印安装版本
echo "Installing Go: $LATEST_VERSION"

# 下载最新版本的 Go
cd $TMP_DIR
wget -q $GO_DOWNLOAD_URL -O "${TMP_DIR}/${LATEST_VERSION}.linux-amd64.tar.gz"

# 清理旧版本
sudo rm -rf $INSTALL_DIR

# 解压新版本
sudo tar -C /usr/local -xzf "${TMP_DIR}/${LATEST_VERSION}.linux-amd64.tar.gz"

# 清理临时文件
rm -f "${TMP_DIR}/${LATEST_VERSION}.linux-amd64.tar.gz"

# 验证安装
/usr/local/go/bin/go version

3.5 获取 rust·

Rust 是新一代内存安全语言,使用 Rust 开发可以降低维护难度。可通过以下命令交互式地安装 Rust 语言。

1
2
3
RUSTUP_PROFILE=complete \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
sh -s -- -y

3.6 获取 neovim·

目前 NeoVim 最新版 v0.10.1 尚未集成到 apt 库,所以需要手动安装。这里笔者选择 appimage 格式。可通过 NeoVim GitHub 仓库 Release 界面查看最新版本。

执行下列命令:

1
2
3
4
cd ~
curl -LO https://github.com/neovim/neovim/releases/download/stable/nvim.appimage
chmod u+x ~/nvim.appimage
sudo mv ~/nvim.appimage /usr/local/bin/nvim.appimage

配置系统级别名:

1
2
3
4
5
6
7
8
CUSTOM_NVIM_PATH=/usr/local/bin/nvim.appimage

sudo update-alternatives --install /usr/bin/ex ex "${CUSTOM_NVIM_PATH}" 110
sudo update-alternatives --install /usr/bin/vi vi "${CUSTOM_NVIM_PATH}" 110
sudo update-alternatives --install /usr/bin/view view "${CUSTOM_NVIM_PATH}" 110
sudo update-alternatives --install /usr/bin/vim vim "${CUSTOM_NVIM_PATH}" 110
sudo update-alternatives --install /usr/bin/nvim nvim "${CUSTOM_NVIM_PATH}" 110
sudo update-alternatives --install /usr/bin/vimdiff vimdiff "${CUSTOM_NVIM_PATH}" 110

下载配置文件:

1
git clone https://github.com/LittleNewton/nvim-config.git ~/.config/nvim

安装 Python 依赖:

1
2
pip3 install -U neovim
pip3 install -U pynvim

安装 LTS 版的 node.jsnpm

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. Download and import the Nodesource GPG key
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg

# 2. Create deb repository
NODE_MAJOR=20
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list

# 3. Run Update and Install
sudo apt-get update
sudo apt-get install nodejs -y

至此,在命令行输入 vim 即可自动安装配置 Vim 及其插件。

4. 配置 zsh 环境·

4.1 配置 zsh·

Zsh 的配置非常简单,已经实现了全部自动化。直接执行以下命令即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
tee ~/.zshenv > /dev/null << 'EOF'
# XDG 规范的路径
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_DATA_HOME="$HOME/.local/share"
export XDG_CACHE_HOME="$HOME/.cache"

# Zsh related config file.
export ZDOTDIR="$XDG_CONFIG_HOME/zsh"
export HISTFILE="$ZDOTDIR/.zhistory" # History filepath
export HISTSIZE=10000 # Maximum events for internal history
export SAVEHIST=10000 # Maximum events in history file

# Zim related config file.
export ZIM_HOME="$XDG_DATA_HOME/zim"
EOF

# 立即加载新的环境变量
source ~/.zshenv

随后下载配置文件:

1
2
git clone https://github.com/LittleNewton/zsh-config.git ~/.config/zsh
# git clone [email protected]:LittleNewton/zsh-config.git ~/.config/zsh

最后将用户的默认 shell 改成 /usr/bin/zsh,命令如下:

1
2
sudo chsh -s /usr/bin/zsh 
# sudo chsh -s /usr/bin/zsh newton

4.2 配置命令行工具·

笔者日常需要用到以下工具:

  • btop 提供了一个美观的系统性能观测 TUI 界面。
  • joshuto 是一个类似 ranger 的命令行文件浏览器。
  • lazygit 提供了一个 TUI 界面和快捷键,高效使用 git.
  • tmux 是一个强大的终端持久化、多路复用软件。笔者的 Tmux 依赖许多插件,其中 Tmux-Powerline 插件的配置较为复杂,因此独立成一个仓库,用户需要手动拉取。

执行下列命令完成所有配置:

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
# 1. joshuto
JOSHUTO_VERSION=$(curl -s https://api.github.com/repos/kamiyaa/joshuto/tags | jq -r '.[].name' | sort -rV | head -n 1)
JOSHUTO_FOLDER="joshuto-${JOSHUTO_VERSION}-x86_64-unknown-linux-musl"
JOSHUTO_DOWNLOAD_URL="https://github.com/kamiyaa/joshuto/releases/download/${JOSHUTO_VERSION}/${JOSHUTO_FOLDER}.tar.gz"
JOSHUTO_COMPRESSED_FILE="${JOSHUTO_FOLDER}.tar.gz"

## 下载并安装最新版本 joshuto
wget -q "$JOSHUTO_DOWNLOAD_URL" -O "/tmp/$JOSHUTO_COMPRESSED_FILE"
tar -C /tmp -xzf "/tmp/${JOSHUTO_COMPRESSED_FILE}"
sudo mv "/tmp/${JOSHUTO_FOLDER}/joshuto" /usr/local/bin

## 清理临时文件
rm "/tmp/${JOSHUTO_COMPRESSED_FILE}"
rm -fr "/tmp/${JOSHUTO_FOLDER}"

## 验证安装
/usr/local/bin/joshuto version

# 2. lazygit
LAZYGIT_VERSION=$(curl -s https://api.github.com/repos/jesseduffield/lazygit/tags | jq -r '.[].name' | sort -rV | head -n 1)
CLEAN_LAZYGIT_VERSION=$(echo "$LAZYGIT_VERSION" | sed 's/^v//')
LAZYGIT_FOLDER="lazygit_${CLEAN_LAZYGIT_VERSION}_Linux_x86_64"
LAZYGIT_COMPRESSED_FILE="${LAZYGIT_FOLDER}.tar.gz"
LAZYGIT_DOWNLOAD_URL="https://github.com/jesseduffield/lazygit/releases/download/${LAZYGIT_VERSION}/${LAZYGIT_COMPRESSED_FILE}"

## 下载并安装最新版本 lazygit
wget -q "$LAZYGIT_DOWNLOAD_URL" -O "/tmp/${LAZYGIT_COMPRESSED_FILE}"
rm -fr "/tmp/${LAZYGIT_FOLDER}" && mkdir -p "/tmp/${LAZYGIT_FOLDER}"
tar -C "/tmp/${LAZYGIT_FOLDER}" -xzf "/tmp/${LAZYGIT_COMPRESSED_FILE}"
sudo mv "/tmp/${LAZYGIT_FOLDER}/lazygit" "/usr/local/bin"

## 清理临时文件
rm "/tmp/${LAZYGIT_COMPRESSED_FILE}"
rm -fr "/tmp/${LAZYGIT_FOLDER}"

## 验证安装
/usr/local/bin/lazygit -v

# 3. 配置环境变量
cd $HOME
GITHUB="https://github.com/LittleNewton"
git clone ${GITHUB}/joshuto-config ~/.config/joshuto
git clone ${GITHUB}/lazygit-config ~/.config/lazygit
git clone ${GITHUB}/tmux-config ~/.config/tmux
git clone ${GITHUB}/tmux-powerline-config ~/.config/tmux-powerline
git clone ${GITHUB}/btop-config.git ~/.config/btop

5. 配置存储·

fstab 的配置因人而异,自行参考。)

5.1 在 /mnt 目录创建挂载点·

为后续所有类型存储挂载创建挂载点。这一步比较重要,因为挂载点的位置影响后续的安排,所以为了简单起见,笔者特意模仿了 TrueNAS 上的存储目录设置 NFS、CIFS 挂载点,方便后续写统一的配置文件。

1
2
3
4
5
sudo mkdir -p /mnt/DapuStor_R5100_RAID-Z1/app_data
sudo mkdir -p /mnt/DapuStor_R5100_RAID-Z1/Documents
sudo mkdir -p /mnt/DapuStor_R5100_RAID-Z1/Software
sudo mkdir -p /mnt/Toshiba_MG06S_RAID-Z1/Downloads
sudo mkdir -p /mnt/WD_HC550_RAID-Z1/Media

5.2 配置 CIFS·

首先配置 smb.cred 密码文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bash -c '
# 定义变量
read -p "Please input SMB username: " SMB_USERNAME
read -s -p "Please input SMB password: " SMB_PASSWORD

# 检查变量是否设置
if [ -z "$SMB_USERNAME" ] || [ -z "$SMB_PASSWORD" ]; then
echo "Error: SMB_USERNAME or SMB_PASSWORD is not set."
exit 1
fi

# 编辑文件
sudo tee /etc/smb.cred > /dev/null << EOF
username=${SMB_USERNAME}
password=${SMB_PASSWORD}
EOF

# 随后设置权限:
sudo chown root:root /etc/smb.cred
sudo chmod 0600 /etc/smb.cred
'

随后遵照本章最后的 /etc/fstab 模板进行配置。

5.3 配置 iSCSI·

5.3.1 修改 open-iscsi 配置文件·

对于 4950-debian,修改 /etc/iscsi/iscsid.conf 文件:

1
sudo nvim /etc/iscsi/iscsid.conf

将相关配置行更改如下:

1
2
3
4
5
6
7
# /etc/iscsi/iscsid.conf
node.session.auth.authmethod = CHAP
node.session.auth.username = iqn.2019-08.cn.littlenewton:4950-debian
node.session.auth.password = xxx
discovery.sendtargets.auth.authmethod = CHAP
discovery.sendtargets.auth.username = iqn.2019-08.cn.littlenewton:4950-debian
discovery.sendtargets.auth.password = xxx

随后修改 initiator 名字:

1
2
3
4
HOSTNAME=$(hostname)
sudo sed -i \
-e "s/^InitiatorName=.*/InitiatorName=iqn.2019-08.cn.littlenewton:${HOSTNAME}/" \
/etc/iscsi/initiatorname.iscsi

5.3.2 运行发现程序并配置登录·

首先运行发现程序,找到可以连接的 node:

1
sudo iscsiadm -m discovery --op=new --op=del --type sendtargets --portal 10.2.1.33

随后登录:

1
sudo iscsiadm -m node -T iqn.2019-08.cn.littlenewton:h12-truenas:teststore --login

现在已经有 session 了:

1
2
3
4
sudo iscsiadm -m session -o show

# [output:]
# tcp: [4] 10.2.1.33:3260,1 iqn.2019-08.cn.littlenewton:h12-truenas:teststore (non-flash)

查看 node 状态,可以发现自动登录被配置为 manual 手动:

1
2
3
4
5
6
7
sudo iscsiadm -m node -o show

[output]
# BEGIN RECORD 2.1.3
node.name = iqn.2019-08.cn.littlenewton:h12-truenas:teststore
node.tpgt = 1
node.startup = manual

必要的话可以配置为自动登录

1
sudo iscsiadm -m node -o update -T iqn.2019-08.cn.littlenewton:h12-truenas:teststore -n node.startup -v automatic

再查看:

1
2
3
4
5
6
7
sudo iscsiadm -m node -o show

[output]
# BEGIN RECORD 2.1.3
node.name = iqn.2019-08.cn.littlenewton:h12-truenas:teststore
node.tpgt = 1
node.startup = automatic

此后重启将默认登录。

5.3.3 临时退出登录·

当我们不想连接 node 之后,先 umount 所有文件系统,然后 logout 该 node:

1
sudo iscsiadm -m node -T iqn.2019-08.cn.littlenewton:h12-truenas:teststore --logout

随后可重新登录。

5.3.4 删除 node·

如果想彻底移除 target,可通过 delete 操作:

1
2
3
4
5
# 先断开会话:-u, --logout, only for `session` and `node`.
sudo iscsiadm -m session iqn.2019-08.cn.littlenewton:h12-truenas:teststore --logout

# 再删除 node
sudo iscsiadm -m node -T iqn.2019-08.cn.littlenewton:h12-truenas:teststore -o delete

此时若重新连接,必须再次执行 discovery 程序。

5.4 修改 /etc/fstab 文件·

执行下列命令追加新内容:

1
2
3
4
5
6
7
8
9
sudo tee -a /etc/fstab > /dev/null << EOF

# NFS 共享
10.2.1.33:/mnt/DapuStor_R5100_RAID-Z1/app_data /mnt/DapuStor_R5100_RAID-Z1/app_data nfs defaults 0 0
10.2.1.33:/mnt/DapuStor_R5100_RAID-Z1/Documents /mnt/DapuStor_R5100_RAID-Z1/Documents nfs defaults 0 0
10.2.1.33:/mnt/DapuStor_R5100_RAID-Z1/Software /mnt/DapuStor_R5100_RAID-Z1/Software nfs defaults 0 0
10.2.1.33:/mnt/Toshiba_MG06S_RAID-Z1/Downloads /mnt/Toshiba_MG06S_RAID-Z1/Downloads nfs defaults 0 0
10.2.1.33:/mnt/WD_HC550_RAID-Z1/Media /mnt/WD_HC550_RAID-Z1/Media nfs defaults 0 0
EOF

对于存储挂载比较复杂的机器,需要遵照下列模板按需选择:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo tee -a /etc/fstab > /dev/null << EOF

# NFS 共享
10.2.1.33:/mnt/DapuStor_R5100_RAID-Z1/app_data /mnt/DapuStor_R5100_RAID-Z1/app_data nfs defaults 0 0
10.2.1.33:/mnt/DapuStor_R5100_RAID-Z1/Documents /mnt/DapuStor_R5100_RAID-Z1/Documents nfs defaults 0 0
10.2.1.33:/mnt/DapuStor_R5100_RAID-Z1/Software /mnt/DapuStor_R5100_RAID-Z1/Software nfs defaults 0 0
10.2.1.33:/mnt/Toshiba_MG06S_RAID-Z1/Downloads /mnt/Toshiba_MG06S_RAID-Z1/Downloads nfs defaults 0 0
10.2.1.33:/mnt/WD_HC550_RAID-Z1/Media /mnt/WD_HC550_RAID-Z1/Media nfs defaults 0 0

# OpenWrt 源代码编译
/dev/disk/by-id/wwn-0x6589cfc000000264078e96d6048c8450 /mnt/DapuStor_R5100_RAID-Z1/openwrt-compile ext4 defaults,_netdev 0 2

# SMB 共享挂载: Dropbox
//10.2.3.1/Dropbox /mnt/DapuStor_R5100_RAID-Z1/Dropbox cifs vers=3.0,credentials=/etc/smb.cred,gid=1000,uid=1000,file_mode=0755,dir_mode=0755 0 0
EOF

刷新 fstabentry,启用挂载的所有存储:

1
sudo mount -av

6. 配置网络·

使用 NetworkManager 配置 Debian 的网络。

温馨提示

不要使用 iproute2 直接配置,否则在图形化桌面和 Cockpit 里看不到管理入口。

NetworkManager 会覆盖已有的所有网络配置,包括 DNS 在内,因此所有配置要使用 NetworkManager 配套工具进行。

6.1 使用 nmtui 命令·

对于不熟悉 nmcli 的新手,可以使用 nmtui 进行配置,图形化方式比较容易被人所接受,直接输入命令,像使用 Plasma KDE 桌面一样配置。

6.2 使用 nmcli 命令行·

先用ip addr看一下网卡名字,确定网卡名字,随后以此创建 Connection Profiles.

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
sh -c '
# 交互式输入 IPv4 地址、网关和 DNS
read -p "IPv4 address (e.g., 10.2.2.21/16): " IPV4_ADDRESS
read -p "Gateway address (e.g., 10.2.2.10): " GATEWAY
read -p "DNS servers (e.g., 10.2.2.10): " DNS_SERVERS

# 检查是否输入有效值
if [[ -z "$IPV4_ADDRESS" || -z "$GATEWAY" || -z "$DNS_SERVERS" ]]; then
echo "Error: IPv4 address, gateway, and DNS servers are required."
exit 1
fi

# 配置第一个 profile
nmcli connection add \
type ethernet \
con-name Ethernet_LAN \
ifname ens33 \
ipv4.method manual \
ipv4.addresses "$IPV4_ADDRESS" \
ipv4.gateway "$GATEWAY" \
ipv4.dns "$DNS_SERVER,1.1.1.1" \
ipv4.dns-search littlenewton.cn \
ipv6.method auto \
autoconnect yes

# 配置第二个 profile
nmcli connection add \
type ethernet \
con-name Ethernet_UCAS \
ifname ens34 \
ipv4.method auto \
ipv6.method auto \
autoconnect yes
'

可通过以下命令输出全部相关网卡:

1
2
3
4
/usr/bin/ip -o link show | awk -F': ' '{print $2}' | grep -Ev '^(lo|docker0|tailscale0|veth)' | while read iface; do
mac=$(cat /sys/class/net/$iface/address)
echo "$mac ($iface)"
done

提示

如果遇到无法上网的情况,可执行下列神奇指令:

1
2
sudo nmcli n on
sudo nmcli n off

7. 配置时区和时钟同步·

出于诸多原因,精确的时间对于网络至关重要,比如:

  • 网络管理:从不同网络设备采集来的日志信息进行分析时,需要以时间作为参照依据。如果不同设备上的系统时间不一致,会因先后顺序等问题给故障定位带来障碍。
  • 计费系统:计费业务对于时间尤其敏感,要求所有设备的时间保持一致,否则会引起计费不准确,导致用户质疑、投诉等。
  • 协同处理:多个系统协同处理同一个复杂事件,为保证正确的执行顺序,多个系统必须参考同一时钟。
  • 系统时间:某些应用或服务需要准确的时间来标记用户登录、交易等操作信息,确保可追溯记录。

因此有一个统一的标准时间对于网络而言意义重大。NTP 就是用来使网络中的各个主机时钟同步的一种协议,他把主机的时钟同步到协调世界时 UTC,其精度在 LAN 网络内可达 1 毫秒内,在 WAN 网络上可以达到几十毫秒内。NTP 是由美国 Delaware 大学 David L .Mills 教授设计的,是最早用于网络中时钟同步的标准之一。NTP 是从时间协议和 ICMP 时间戳报文演变而来。

此外,许多全球性 App,比如 Google Calendar 等,均会使用时区进行事件提醒,如果时区设置不正确,日历将无法工作。

7.1 调整时区·

此配置基于 Systemd,不包含此功能的 Debian 12 将无法使用下面的命令。若用户根据本文逐步配置,则不存在此问题。相关命令如下:

1
2
3
4
5
6
7
8
# 检查时区
timedatectl

# 设置中国时区
sudo timedatectl set-timezone Asia/Shanghai

# 如果在英国就设置伦敦时区
sudo timedatectl set-timezone Europe/London

7.2 调整时钟同步·

时钟同步使用 NTP 协议,该协议非常复杂,但是我们只需要知道配置 NTP 服务器即可。NTP 服务器是至关重要的基础组件,因此很多大型互联网企业都有自己的 NTP 服务,它们的 NTP 服务会通过高质量链路与全球权威授时中心进行时钟同步。通过下列命令查看 systemd-timesyncd 服务状态:

1
sudo systemctl status systemd-timesyncd.service

如果发现大量 timeout 超时记录或其他异常,则需要修改配置文件:

1
2
3
sudo sed -i \
-e "s/^NTP=.*/NTP=time.windows.com ntp.aliyun.com cn.pool.ntp.org/" \
/etc/systemd/timesyncd.conf

随后重启服务并重新查看服务状态:

1
sudo systemctl status systemd-timesyncd.service

至此,便完成了对时区、时钟同步的配置。

8. 设置 docker-cePortainer·

8.1 配置 docker 环境·

容器运行时是现在通用 Linux 环境里不可缺少的一部分,通过容器技术,可快速部署服务。

8.1.1 安装 docker-ce·

容器技术自流行以来,有多个符合标准的运行时,即多个公司、组织研发了合乎标准的“容器”概念实现。此处选择 Docker 公司维护的社区版 Docker-CE 作为示范。

以下脚本来自官方安装教程

先配置 APT 上游:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

随后下载 docker-ce 的相关组件:

1
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

现在即可使用 Docker 服务。

8.1.2 配置 docker 用户组·

由于 Docker-CE 需要以管理员模式运行命令行程序,所以日常使用显得很麻烦。为此,我们可以将普通用户 ${USERNAME} 添加到 docker 用户组里,这样就可以免去 sudo.

应该注意,docker 用户组的权限非常高,和 root 是等同的。因此,后期探索好用的 root-less 容器环境非常有价值。

1
2
3
4
5
6
7
8
9
10
11
12
# 创建 docker 用户组
sudo groupadd docker

# 将当前用户加入 docker 用户组
sudo usermod -aG docker ${USERNAME}

# 重启 docker 服务
sudo systemctl restart docker

# 切换或者退出当前账户并重新登入
su
su ${USERNAME}

8.1.3 配置 Docker 远程管理·

对于不需要更改运行时的 Linux 系统,可直接修改 daemon 配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bash -c '
read -p "Enter the IPv4 address for Docker (e.g., 10.2.6.21): " DOCKER_IP

# 检查是否输入有效的 IPv4 地址
if [[ -z "$DOCKER_IP" ]]; then
echo "Error: IP address cannot be empty."
exit 1
fi

sudo tee /etc/docker/daemon.json > /dev/null << EOF
{
"ipv6": true,
"fixed-cidr-v6": "fd00::/80",
"experimental": true,
"ip6tables": true,
"hosts": [
"tcp://${DOCKER_IP}:2375",
"unix:///var/run/docker.sock"
]
}
EOF

echo "Docker daemon configuration updated with IP: ${DOCKER_IP}"
'

8.2 配置 Portainer·

1
2
docker pull portainer/portainer-ee:latest
docker run -d -p 8000:8000 -p 9443:9443 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ee:latest

portainer-ee 激活密钥可去申请,获得一个五节点或三节点的免费授权。密钥如下:

1
secret

9. 配置 Git·

本章包括用户的 Git 全局配置,以及中国大陆地区的 GitHub 配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
git config --global user.name 'Peng Liu'
git config --global user.email [email protected]
git config --global pull.rebase=true
git config --global credential.helper=store

# 大陆地区的 GitHub 特殊配置
tee ~/.ssh/config > /dev/null << EOF
Host github.com
Hostname ssh.github.com
Port 443
User git
EOF

chmod 600 ~/.ssh/config
git config --list

总结·

这篇文章事无巨细地介绍了我在安装 Debian 12 的过程中要做的步骤,可以说除了剔除了密钥信息之外毫无保留。我认为,任何 Linux 用户都应该把自己通用服务器的配置过程固定化、完善化,这是成为 Linux 管理员的良好习惯。此外,听闻 NixOS 可以对全系统做声明式配置,看起来非常有吸引力,后续有待研究。