diff --git a/README.en.md b/README.en.md
index 001349e..d23bf44 100644
--- a/README.en.md
+++ b/README.en.md
@@ -11,7 +11,7 @@ Reinstall server with one-click [中文](README.md)
## Highlights
-- Support installation of 16 common Linux distributions.
+- Support installation of 17 common Linux distributions.
- Support for installing Windows using the official original ISO. The script can automatically search for the ISO and drivers.
- Support reinstallation in any direction, meaning `Linux to Linux`, `Linux to Win`, `Win to Win`, `Win to Linux`.
- Specifically tailored for low-spec machines, addressing insufficient memory that prevents network installation.
@@ -36,6 +36,7 @@ Reinstall server with one-click [中文](README.md)
| Fedora | 39, 40 | 512 MB \* | 5 GB |
| openEuler | 20.03, 22.03, 24.03 | 512 MB \* | 5 GB |
| openSUSE | 15.5, 15.6, Tumbleweed (Rolling) | 512 MB \* | 5 GB |
+| NixOS | 24.05 | 512 MB | 5 GB |
| Arch | Rolling | 512 MB | 5 GB |
| Gentoo | Rolling | 512 MB | 5 GB |
| Windows (DD) | Any | 512 MB | Depending on the image |
@@ -153,6 +154,7 @@ bash reinstall.sh centos 9
opencloudos 8|9
oracle 7|8|9
fedora 39|40
+ nixos 24.05
debian 9|10|11|12
openeuler 20.03|22.03|24.03
alpine 3.17|3.18|3.19|3.20
@@ -295,7 +297,7 @@ Use `Dism++` File menu > Open Image File, select the iso to be installed to get
## How to Modify the Script
1. Fork this repository.
-2. Modify the `confhome` at the beginning of `reinstall.sh` and `reinstall.bat`.
+2. Modify the `confhome` and `confhome_cn` at the beginning of `reinstall.sh` and `reinstall.bat`.
3. Make changes to the other code.
## Thanks
diff --git a/README.md b/README.md
index 5a2f016..21e0e89 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
## 亮点
-- 支持安装 16 种常见 Linux 发行版
+- 支持安装 17 种常见 Linux 发行版
- 支持用官方原版 iso 安装 Windows,并且脚本会自动查找 iso 和驱动
- 支持任意方向重装,也就是支持 `Linux to Linux`、`Linux to Win`、`Win to Win`、`Win to Linux`
- 专门适配低配小鸡,解决内存过少导致无法进行网络安装
@@ -36,6 +36,7 @@
| Fedora | 39, 40 | 512 MB \* | 5 GB |
| openEuler | 20.03, 22.03, 24.03 | 512 MB \* | 5 GB |
| openSUSE | 15.5, 15.6, Tumbleweed (滚动) | 512 MB \* | 5 GB |
+| NixOS | 24.05 | 512 MB | 5 GB |
| Arch | 滚动 | 512 MB | 5 GB |
| Gentoo | 滚动 | 512 MB | 5 GB |
| Windows (DD) | 任何 | 512 MB | 取决于镜像 |
@@ -153,6 +154,7 @@ bash reinstall.sh centos 9
opencloudos 8|9
oracle 7|8|9
fedora 39|40
+ nixos 24.05
debian 9|10|11|12
openeuler 20.03|22.03|24.03
alpine 3.17|3.18|3.19|3.20
@@ -295,7 +297,7 @@ Windows Server 2022 SERVERDATACENTER
## 如何修改脚本
1. Fork 本仓库
-2. 修改 `reinstall.sh` 和 `reinstall.bat` 开头的 `confhome`
+2. 修改 `reinstall.sh` 和 `reinstall.bat` 开头的 `confhome` 和 `confhome_cn`
3. 修改其它代码
## 感谢
diff --git a/reinstall.sh b/reinstall.sh
index 51c5c02..b7ec455 100644
--- a/reinstall.sh
+++ b/reinstall.sh
@@ -39,6 +39,7 @@ Usage: $reinstall____ centos 9
opencloudos 8|9
oracle 7|8|9
fedora 39|40
+ nixos 24.05
debian 9|10|11|12
openeuler 20.03|22.03|24.03
alpine 3.17|3.18|3.19|3.20
@@ -234,6 +235,7 @@ test_url_real() {
tmp_file=$tmp/img-test
+ # TODO: 好像无法识别 nixos 官方源的跳转
# 有的服务器不支持 range,curl会下载整个文件
# 用 dd 限制下载 1M
# 并过滤 curl 23 错误(dd限制了空间)
@@ -960,6 +962,22 @@ setos() {
fi
}
+ setos_nixos() {
+ if is_in_china; then
+ mirror=https://mirror.nju.edu.cn/nix-channels
+ else
+ mirror=https://nixos.org/channels
+ fi
+
+ if is_use_cloud_image; then
+ :
+ else
+ # 传统安装
+ test_url $mirror/nixos-$releasever/store-paths.xz xz
+ eval ${step}_mirror=$mirror
+ fi
+ }
+
setos_gentoo() {
if is_in_china; then
mirror=https://mirror.nju.edu.cn/gentoo
@@ -1281,6 +1299,7 @@ verify_os_name() {
'opencloudos 8|9' \
'oracle 7|8|9' \
'fedora 39|40' \
+ 'nixos 24.05' \
'debian 9|10|11|12' \
'openeuler 20.03|22.03|24.03' \
'alpine 3.17|3.18|3.19|3.20' \
@@ -1333,7 +1352,7 @@ install_pkg() {
find_pkg_mgr() {
if [ -z "$pkg_mgr" ]; then
- for mgr in dnf yum apt pacman zypper emerge apk; do
+ for mgr in dnf yum apt pacman zypper emerge apk opkg nix-env; do
is_have_cmd $mgr && pkg_mgr=$mgr && return
done
return 1
@@ -1459,6 +1478,15 @@ install_pkg() {
[ -z "$apt_updated" ] && apt update && apt_updated=1
DEBIAN_FRONTEND=noninteractive apt install -y $pkg
;;
+ opkg)
+ [ -z "$opkg_updated" ] && opkg update && opkg_updated=1
+ opkg install $pkg
+ ;;
+ nix-env)
+ # 不指定 channel 会很慢,而且很占内存
+ [ -z "$nix_updated" ] && nix-channel --update && nix_updated=1
+ nix-env -iA nixos.$pkg
+ ;;
esac
}
@@ -1500,7 +1528,7 @@ check_ram() {
case "$distro" in
netboot.xyz) echo 0 ;;
alpine | debian | kali | dd) echo 256 ;;
- arch | gentoo | windows) echo 512 ;;
+ arch | gentoo | nixos | windows) echo 512 ;;
redhat | centos | alma | rocky | fedora | oracle | ubuntu | anolis | opencloudos | openeuler) echo 1024 ;;
opensuse) echo -1 ;; # 没有安装模式
esac
@@ -1517,7 +1545,7 @@ check_ram() {
has_cloud_image=$(
case "$distro" in
redhat | centos | alma | rocky | oracle | fedora | debian | ubuntu | opensuse | anolis | openeuler) echo true ;;
- netboot.xyz | alpine | dd | arch | gentoo | kali | windows) echo false ;;
+ netboot.xyz | alpine | dd | arch | gentoo | nixos | kali | windows) echo false ;;
esac
)
@@ -2924,7 +2952,7 @@ mkdir_clear "$tmp"
# 强制忽略/强制添加 --ci 参数
# debian 不强制忽略 ci 留作测试
case "$distro" in
-dd | windows | netboot.xyz | kali | alpine | arch | gentoo)
+dd | windows | netboot.xyz | kali | alpine | arch | gentoo | nixos)
if is_use_cloud_image; then
echo "ignored --ci"
cloud_image=0
@@ -3025,7 +3053,10 @@ if is_efi; then
xargs -I {} cmd /c bcdedit /delete {}
else
# shellcheck disable=SC2046
- find $(get_maybe_efi_dirs_in_linux) /boot -type f -name 'custom.cfg' -exec rm -f {} \;
+ # 如果 nixos 的 efi 挂载到 /efi,则不会生成 /boot 文件夹
+ # find 不存在的路径会报错退出
+ find $(get_maybe_efi_dirs_in_linux) $([ -d /boot ] && echo /boot) \
+ -type f -name 'custom.cfg' -exec rm -f {} \;
install_pkg efibootmgr
efibootmgr | grep -q 'BootNext:' && efibootmgr --quiet --delete-bootnext
diff --git a/trans.sh b/trans.sh
index e9ca934..53fa327 100644
--- a/trans.sh
+++ b/trans.sh
@@ -340,7 +340,7 @@ EOF
}
umount_all() {
- dirs="/mnt /os /iso /wim /installer /nbd /nbd-boot /nbd-efi /root"
+ dirs="/mnt /os /iso /wim /installer /nbd /nbd-boot /nbd-efi /root /nix"
regex=$(echo "$dirs" | sed 's, ,|,g')
if mounts=$(mount | grep -Ew "$regex" | awk '{print $3}' | tac); then
for mount in $mounts; do
@@ -359,6 +359,7 @@ clear_previous() {
dmsetup remove_all
fi
disconnect_qcow
+ rc-service --ifexists --ifstarted nix-daemon stop
swapoff -a
umount_all
@@ -820,6 +821,164 @@ EOF
done
}
+space_to_newline() {
+ sed 's/ /\n/g'
+}
+
+trim() {
+ sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
+}
+
+quote_word() {
+ sed -E 's/([^[:space:]]+)/"\1"/g'
+}
+
+quote_line() {
+ awk '{print "\""$0"\""}'
+}
+
+add_space() {
+ space_count=$1
+
+ spaces=$(printf '%*s' "$space_count" '')
+ sed "s/^/$spaces/"
+}
+
+# 不够严谨,谨慎使用
+nix_replace() {
+ local key=$1
+ local value=$2
+ local type=$3
+ local file=$4
+ local key_ value_
+
+ key_=$(echo "$key" | sed 's \. \\\. g') # . 改成 \.
+
+ if [ "$type" = array ]; then
+ local value_="[ $value ]"
+ fi
+
+ sed -i "s/$key_ =.*/$key = $value_;/" "$file"
+}
+
+create_nixos_network_config() {
+ conf_file=$1
+ true >$conf_file
+
+ # 头部
+ cat <>$conf_file
+networking = {
+ usePredictableInterfaceNames = false;
+EOF
+
+ for ethx in $(get_eths); do
+ # ipv4
+ if is_staticv4; then
+ get_netconf_to ipv4_addr
+ get_netconf_to ipv4_gateway
+ IFS=/ read -r address prefix < <(echo "$ipv4_addr")
+ cat <>$conf_file
+ interfaces.$ethx.ipv4.addresses = [
+ {
+ address = "$address";
+ prefixLength = $prefix;
+ }
+ ];
+ defaultGateway = {
+ address = "$ipv4_gateway";
+ interface = "$ethx";
+ };
+EOF
+ fi
+
+ # ipv6
+ if is_staticv6; then
+ get_netconf_to ipv6_addr
+ get_netconf_to ipv6_gateway
+ IFS=/ read -r address prefix < <(echo "$ipv6_addr")
+ cat <>$conf_file
+ interfaces.$ethx.ipv6.addresses = [
+ {
+ address = "$address";
+ prefixLength = $prefix;
+ }
+ ];
+ defaultGateway = {
+ address = "$ipv6_gateway";
+ interface = "$ethx";
+ };
+EOF
+ fi
+ done
+
+ # 全局 dns
+ need_set_dns=false
+ for ethx in $(get_eths); do
+ if is_staticv4 || is_staticv6 || is_need_manual_set_dnsv6; then
+ need_set_dns=true
+ break
+ fi
+ done
+
+ if $need_set_dns; then
+ cat <>$conf_file
+ nameservers = [
+$(get_current_dns | quote_line | add_space 4)
+ ];
+EOF
+ fi
+
+ # 尾部
+ cat <>$conf_file
+};
+EOF
+
+ # nixos 默认网络管理器是 dhcpcd
+ # 但配置静态 ip 时用的是脚本
+ # /nix/store/qcr1xxjdxcrnwqwrgysqpxx2aibp9fdl-unit-script-network-addresses-eth0-start/bin/network-addresses-eth0-start
+ # ...
+ # if out=$(ip addr replace "181.x.x.x/24" dev "eth0" 2>&1); then
+ # echo "done"
+ # else
+ # echo "'ip addr replace "181.x.x.x/24" dev "eth0"' failed: $out"
+ # exit 1
+ # fi
+ # ...
+
+ # 禁用 ra
+ for ethx in $(get_eths); do
+ if should_disable_ra_slaac; then
+ mode=1
+ if [ "$mode" = 1 ]; then
+ cat <>$conf_file
+boot.kernel.sysctl."net.ipv6.conf.$ethx.accept_ra" = false;
+EOF
+ elif [ "$mode" = 2 ]; then
+ # nixos 配置静态 ip 时用的是脚本
+ # 好像因此不起作用
+ cat <>$conf_file
+networking.dhcpcd.extraConfig =
+ ''
+ interface $ethx
+ ipv6ra_noautoconf
+ '';
+EOF
+ elif [ "$mode" = 3 ]; then
+ # 暂时没用到 networkd
+ cat <>$conf_file
+systemd.network.networks.$ethx = {
+ matchConfig.Name = "$ethx";
+ networkConfig = {
+ IPv6AcceptRA = false;
+ };
+ };
+EOF
+ fi
+ fi
+ done
+
+}
+
install_alpine() {
hack_lowram_modloop=true
hack_lowram_swap=true
@@ -986,6 +1145,166 @@ get_build_threads() {
min $threads_by_ram $threads_by_core
}
+install_nixos() {
+ os_dir=/os
+ keep_swap=true
+
+ # 挂载分区,创建 swapfile
+ mount_part_basic_layout /os /os/efi
+ need_ram=2048
+ swap_size=$(get_need_swap_size $need_ram)
+ create_swap_if_ram_less_than $need_ram /os/swapfile
+
+ # 步骤
+ # 1. 安装 nix (nix-xxx)
+ # 2. 用 nix 安装 nixos-install-tools (nixos-xxx)
+ # 3. 运行 nixos-generate-config 生成配置 + 编辑
+ # 4. 运行 nixos-install
+
+ # nix 安装方式 分支 版本
+ # apk add nix 3.20 2.22.0 # nix 本体跟正常的软件一样,不在 /nix/store 里面
+ # env -iA nixpkgs.nix 24.05 2.18.5
+ # sh <(curl -L https://nixos.org/nix/install) unstable? 2.24.2
+
+ # 安装 nix
+ mkdir -p /os/nix /nix
+ mount --bind /os/nix /nix
+ apk add nix
+
+ # TODO: 有时安装系统时会出错,卡在
+ # copying path '/nix/store/gcbrjlfm5h21ybf1h2lfq773zafjmzjr-curl-8.7.1-man' from 'https://cache.nixos.org'...
+ # 但是 cpu 空载
+
+ # 设置 nix 镜像和线程
+ # alpine 默认设置了 4 线程
+ # https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/community/nix/APKBUILD#L125
+ sed -i '/max-jobs/d' /etc/nix/nix.conf
+ echo "max-jobs = $(get_build_threads 2048)" >>/etc/nix/nix.conf
+ if is_in_china; then
+ echo "substituters = $mirror/store" >>/etc/nix/nix.conf
+ fi
+ rc-service nix-daemon restart
+
+ # 添加 channel
+ # shellcheck disable=SC2154
+ nix-channel --add $mirror/nixos-$releasever nixpkgs
+ nix-channel --update
+
+ # 安装 channal 的 nix
+ # shellcheck source=/dev/null
+ if false; then
+ nix-env -iA nixpkgs.nix
+ . ~/.nix-profile/etc/profile.d/nix.sh
+ fi
+
+ # 安装 nixos-install-tools
+ nix-env -iA nixpkgs.nixos-install-tools
+
+ # 添加 nix-env 安装的软件到 PATH
+ PATH="/root/.nix-profile/bin:$PATH"
+
+ # 生成配置
+ nixos-generate-config --root /os
+
+ # configuration.nix
+ if is_efi; then
+ nix_bootloader="boot.loader.efi.efiSysMountPoint = \"/efi\";"
+ else
+ nix_bootloader="boot.loader.grub.device = \"/dev/$xda\";"
+ fi
+
+ if is_in_china; then
+ nix_substituters="nix.settings.substituters = lib.mkForce [ \"$mirror/store\" ];"
+ fi
+
+ if [ -e /os/swapfile ] && $keep_swap; then
+ nix_swap="swapDevices = [{ device = \"/swapfile\"; size = $swap_size; }];"
+ fi
+
+ # TODO: 准确匹配网卡,添加 udev 或者直接配置 networkd 匹配 mac
+ create_nixos_network_config /tmp/nixos_network_config.nix
+
+ # sed -e '1s/^/\n/' -e '$a\\' # 也可以在前后添加空行
+ {
+ echo # 前面的空行
+ cat <>$os_dir/etc/locale.gen
@@ -1442,7 +1761,7 @@ create_part() {
mkfs.ext4 -E nodiscard -F -L os /dev/$xda*1 #1 os
mkfs.ext4 -E nodiscard -F -L installer /dev/$xda*2 #2 installer
fi
- elif [ "$distro" = alpine ] || [ "$distro" = arch ] || [ "$distro" = gentoo ]; then
+ elif [ "$distro" = alpine ] || [ "$distro" = arch ] || [ "$distro" = gentoo ] || [ "$distro" = nixos ]; then
if is_efi; then
# efi
parted /dev/$xda -s -- \
@@ -3776,6 +4095,10 @@ else
create_part
install_arch_gentoo
;;
+ nixos)
+ create_part
+ install_nixos
+ ;;
*)
create_part
mount_part_for_iso_installer