From f82c9ad784603d9b41d58b5f18bceedd0c56096d Mon Sep 17 00:00:00 2001 From: bin456789 Date: Mon, 19 Aug 2024 00:42:12 +0800 Subject: [PATCH] =?UTF-8?q?nixos:=20=E6=94=AF=E6=8C=81=E5=AE=89=E8=A3=85?= =?UTF-8?q?=20nixos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.en.md | 6 +- README.md | 6 +- reinstall.sh | 41 ++++++- trans.sh | 327 ++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 369 insertions(+), 11 deletions(-) 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