Bohan Yang 5 年 前
コミット
732d3092c4
2 ファイル変更106 行追加117 行削除
  1. 25 21
      README.md
  2. 81 96
      debi.sh

+ 25 - 21
README.md

@@ -28,27 +28,27 @@ This script is written to reinstall a VPS/virtual machine to Debian 10 Buster.
 
 
 ## Usage
 ## Usage
 
 
-    curl -fLO https://raw.githubusercontent.com/bohanyang/debi/master/debi.sh && sudo bash debi.sh <OPTIONS>
+    curl -fL https://raw.githubusercontent.com/bohanyang/debi/master/debi.sh | sudo bash -s -- <OPTIONS>
 
 
 ## Available Options
 ## Available Options
 
 
- * `--preset <string>` Shortcut for applying [preset options](#presets)
  * `--ip <string>` Static public/private IP, e.g. `10.0.0.2`
  * `--ip <string>` Static public/private IP, e.g. `10.0.0.2`
- * `--netmask <string>` e.g. `255.255.255.0` /  `ffff:ffff:ffff:ffff::`
- * `--gateway <string>` e.g. `10.0.0.1`
- * `--dns '8.8.8.8 8.8.4.4'` Ignored if `--ip` is not specified. Quoted string where IP addresses are seperated by spaces
+ * `--netmask <string>` e.g. `255.255.255.0` /  `ffff:ffff:ffff:ffff::`. Ignored if `--ip` is not specified
+ * `--gateway <string>` e.g. `10.0.0.1`. Ignored if `--ip` is not specified
+ * `--dns '8.8.8.8 8.8.4.4'` Quoted string where IP addresses are seperated by spaces. Ignored if `--ip` is not specified
  * `--hostname debian`
  * `--hostname debian`
- * `--installer-password <string>` Enable installer network console to monitor installation status. e.g. `ssh installer@10.0.0.2`
- * `--authorized-keys-url <string>` Setup SSH public key authentication for the new user and enable installer network console. e.g. `https://github.com/bohanyang.keys`
+ * `--network-console` Enable the network console of the installer. `ssh installer@ip` to connect
  * `--suite buster`
  * `--suite buster`
  * `--mirror-protocol http` or `https` or `ftp`
  * `--mirror-protocol http` or `https` or `ftp`
+ * `--https` alias to `--mirror-protocol https`
  * `--mirror-host deb.debian.org`
  * `--mirror-host deb.debian.org`
  * `--mirror-directory /debian`
  * `--mirror-directory /debian`
  * `--security-repository http://security.debian.org/debian-security` Magic value: `'mirror' = <mirror-protocol>://<mirror-host>/<mirror-directory>/../debian-security`
  * `--security-repository http://security.debian.org/debian-security` Magic value: `'mirror' = <mirror-protocol>://<mirror-host>/<mirror-directory>/../debian-security`
  * `--skip-account-setup`
  * `--skip-account-setup`
  * `--username debian` New user with `sudo` privilege or `root`
  * `--username debian` New user with `sudo` privilege or `root`
- * `--password <string>` New user password to set. **Will be prompted if not specified here**
- * `--sudo-password` Verify the user's password when running "sudo" commands
+ * `--password <string>` Password of the new user. **You'll be prompted if you choose to not specify it here**
+ * `--authorized-keys-url <string>` URL to your authorized keys for SSH authentication. e.g. `https://github.com/torvalds.keys`
+ * `--sudo-with-password` Require password when the user invokes `sudo` command
  * `--timezone UTC` https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
  * `--timezone UTC` https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
  * `--ntp 0.debian.pool.ntp.org`
  * `--ntp 0.debian.pool.ntp.org`
  * `--skip-partitioning`
  * `--skip-partitioning`
@@ -60,11 +60,11 @@ This script is written to reinstall a VPS/virtual machine to Debian 10 Buster.
  * `--kernel <string>` Choose an package for the kernel image
  * `--kernel <string>` Choose an package for the kernel image
  * `--cloud-kernel` Choose `linux-image-cloud-amd64` as the kernel image
  * `--cloud-kernel` Choose `linux-image-cloud-amd64` as the kernel image
  * `--no-install-recommends`
  * `--no-install-recommends`
- * `--install 'ca-certificates libpam-systemd'` Additional packages to install. Quoted string where package names are seperated by spaces. **Package names specified here will override the default list, rather than append to it**
+ * `--install 'ca-certificates libpam-systemd'` Additional packages to install. Quoted string where package names are seperated by spaces. Package names specified here will override the default list, rather than append to it
  * `--safe-upgrade` **(Default)** `apt upgrade --with-new-pkgs`. [See](https://salsa.debian.org/installer-team/pkgsel/-/blob/master/debian/postinst)
  * `--safe-upgrade` **(Default)** `apt upgrade --with-new-pkgs`. [See](https://salsa.debian.org/installer-team/pkgsel/-/blob/master/debian/postinst)
  * `--full-upgrade` `apt dist-upgrade`
  * `--full-upgrade` `apt dist-upgrade`
  * `--no-upgrade` 
  * `--no-upgrade` 
- * `--eth` Disable *Consistent Network Device Naming* to get `eth0`, `eth1`, etc. back
+ * `--eth` Disable *Consistent Network Device Naming* to get interface names like *ethX* back
  * `--bbr` Enable TCP BBR congestion control
  * `--bbr` Enable TCP BBR congestion control
  * `--hold` Don't reboot or power off after installation
  * `--hold` Don't reboot or power off after installation
  * `--power-off` Power off after installation rather than reboot
  * `--power-off` Power off after installation rather than reboot
@@ -72,23 +72,27 @@ This script is written to reinstall a VPS/virtual machine to Debian 10 Buster.
  * `--boot-partition` Should be used if `/boot` directory is mounted from a dedicated partition like a LVM setup
  * `--boot-partition` Should be used if `/boot` directory is mounted from a dedicated partition like a LVM setup
  * `--firmware` Load additional [non-free firmwares](https://wiki.debian.org/Firmware#Firmware_during_the_installation)
  * `--firmware` Load additional [non-free firmwares](https://wiki.debian.org/Firmware#Firmware_during_the_installation)
  * `--force-efi-extra-removable` [See](https://wiki.debian.org/UEFI#Force_grub-efi_installation_to_the_removable_media_path). **Useful on Oracle Cloud**
  * `--force-efi-extra-removable` [See](https://wiki.debian.org/UEFI#Force_grub-efi_installation_to_the_removable_media_path). **Useful on Oracle Cloud**
- * `--grub-timeout 5` How many seconds the GRUB menu shows **before entering the installer**
+ * `--grub-timeout 5` How many seconds the GRUB menu shows before entering the installer
  * `--dry-run` Print generated preseed and GRUB entry without downloading the installer and actually saving them
  * `--dry-run` Print generated preseed and GRUB entry without downloading the installer and actually saving them
 
 
-## Presets
+### Presets
 
 
-### `china`
+### `--cdn`
 
 
- * `--dns '223.5.5.5 223.6.6.6'`
  * `--mirror-protocol https`
  * `--mirror-protocol https`
- * `--mirror-host mirrors.aliyun.com`
+ * `--mirror-host deb.debian.org`
  * `--security-repository mirror`
  * `--security-repository mirror`
- * `--ntp ntp.aliyun.com`
 
 
-### `cloud`
+### `--aws`
 
 
- * `--dns '1.1.1.1 1.0.0.1'`
  * `--mirror-protocol https`
  * `--mirror-protocol https`
- * `--mirror-host deb.debian.org`
+ * `--mirror-host cdn-aws.deb.debian.org`
  * `--security-repository mirror`
  * `--security-repository mirror`
- * `--ntp 0.debian.pool.ntp.org`
+
+### `--china`
+
+ * `--dns '223.5.5.5 223.6.6.6'`
+ * `--mirror-protocol https`
+ * `--mirror-host mirrors.aliyun.com`
+ * `--security-repository mirror`
+ * `--ntp ntp.aliyun.com`

+ 81 - 96
debi.sh

@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/bin/sh
+# shellcheck shell=dash
 
 
 set -euo pipefail
 set -euo pipefail
 
 
@@ -11,20 +12,34 @@ command_exists() {
     command -v "$1" > /dev/null 2>&1
     command -v "$1" > /dev/null 2>&1
 }
 }
 
 
-late_command=
-run_later() {
-    [ -z "$late_command" ] && late_command='true'
-    late_command="$late_command; $1"
+in_target=
+late_command() {
+    local cmd
+    for arg in "$@"; do
+        cmd="$cmd $arg"
+    done
+    if [ -n "$cmd" ]; then
+        [ -z "$in_target" ] && in_target='true'
+        in_target="$in_target;$cmd"
+    fi
+}
+
+in_target_backup() {
+    late_command "if [ ! -e \"$1.backup\" ]; then cp \"$1\" \"$1.backup\"; fi"
 }
 }
 
 
-backup() {
-    run_later "if [ ! -e \"$1.backup\" ]; then cp \"$1\" \"$1.backup\"; fi"
+sshd_conf() {
+    [ -z ${backed_sshd+1} ] && in_target_backup /etc/ssh/sshd_config
+    backed_sshd=
+    late_command sed -Ei \""s/^#?$1 .+/$1 $2/"\" /etc/ssh/sshd_config
 }
 }
 
 
 prompt_password() {
 prompt_password() {
-    if [ -z "$password" ]; then
-        read -rs -p 'Password: ' password
-    fi
+    stty -echo
+    echo -n "Choose a password for the new user $username: " > /dev/tty
+    read -r password < /dev/tty
+    stty echo
+    echo > /dev/tty
 }
 }
 
 
 ip=
 ip=
@@ -32,9 +47,7 @@ netmask=
 gateway=
 gateway=
 dns='8.8.8.8 8.8.4.4'
 dns='8.8.8.8 8.8.4.4'
 hostname=
 hostname=
-installer_ssh=false
-installer_password=
-authorized_keys_url=
+network_console=false
 suite=buster
 suite=buster
 mirror_protocol=http
 mirror_protocol=http
 mirror_host=deb.debian.org
 mirror_host=deb.debian.org
@@ -43,8 +56,8 @@ security_repository=http://security.debian.org/debian-security
 skip_account_setup=false
 skip_account_setup=false
 username=debian
 username=debian
 password=
 password=
-sudo_password=false
-cleartext_password=false
+authorized_keys_url=
+sudo_with_password=false
 timezone=UTC
 timezone=UTC
 ntp=0.debian.pool.ntp.org
 ntp=0.debian.pool.ntp.org
 skip_partitioning=false
 skip_partitioning=false
@@ -69,25 +82,17 @@ dry_run=false
 
 
 while [ $# -gt 0 ]; do
 while [ $# -gt 0 ]; do
     case $1 in
     case $1 in
-        --preset)
-            case "$2" in
-                china)
-                    dns='223.5.5.5 223.6.6.6'
-                    mirror_protocol=https
-                    mirror_host=mirrors.aliyun.com
-                    ntp=ntp.aliyun.com
-                    security_repository=mirror
-                    ;;
-                cloud)
-                    dns='1.1.1.1 1.0.0.1'
-                    mirror_protocol=https
-                    mirror_host=deb.debian.org
-                    security_repository=mirror
-                    ;;
-                *)
-                    err "No such preset $2"
-            esac
-            shift
+        --cdn|--aws)
+            mirror_protocol=https
+            [ "$1" = '--aws' ] && mirror_host=cdn-aws.deb.debian.org
+            security_repository=mirror
+            ;;
+        --china)
+            dns='223.5.5.5 223.6.6.6'
+            mirror_protocol=https
+            mirror_host=mirrors.aliyun.com
+            ntp=ntp.aliyun.com
+            security_repository=mirror
             ;;
             ;;
         --ip)
         --ip)
             ip=$2
             ip=$2
@@ -109,15 +114,8 @@ while [ $# -gt 0 ]; do
             hostname=$2
             hostname=$2
             shift
             shift
             ;;
             ;;
-        --installer-password)
-            installer_ssh=true
-            installer_password=$2
-            shift
-            ;;
-        --authorized-keys-url)
-            installer_ssh=true
-            authorized_keys_url=$2
-            shift
+        --network-console)
+            network_console=true
             ;;
             ;;
         --suite)
         --suite)
             suite=$2
             suite=$2
@@ -142,7 +140,7 @@ while [ $# -gt 0 ]; do
         --skip-account-setup)
         --skip-account-setup)
             skip_account_setup=true
             skip_account_setup=true
             ;;
             ;;
-        --username)
+        --user|--username)
             username=$2
             username=$2
             shift
             shift
             ;;
             ;;
@@ -150,8 +148,12 @@ while [ $# -gt 0 ]; do
             password=$2
             password=$2
             shift
             shift
             ;;
             ;;
-        --sudo-password)
-            sudo_password=true
+        --authorized-keys-url)
+            authorized_keys_url=$2
+            shift
+            ;;
+        --sudo-with-password)
+            sudo_with_password=true
             ;;
             ;;
         --timezone)
         --timezone)
             timezone=$2
             timezone=$2
@@ -287,30 +289,21 @@ fi
 
 
 echo 'd-i hw-detect/load_firmware boolean true' | $save_preseed
 echo 'd-i hw-detect/load_firmware boolean true' | $save_preseed
 
 
-if [ "$installer_ssh" = true ]; then
-    $save_preseed << 'EOF'
+while [ -z "$password" ]; do
+    prompt_password
+done
+
+if [ "$network_console" = true ]; then
+    $save_preseed << EOF
 
 
 # Network console
 # Network console
 
 
 d-i anna/choose_modules string network-console
 d-i anna/choose_modules string network-console
 d-i preseed/early_command string anna-install network-console
 d-i preseed/early_command string anna-install network-console
+d-i network-console/password password $password
+d-i network-console/password-again password $password
 EOF
 EOF
-
-    if [ -n "$authorized_keys_url" ]; then
-        backup /etc/ssh/sshd_config
-        run_later 'sed -Ei "s/^#?PasswordAuthentication .+/PasswordAuthentication no/" /etc/ssh/sshd_config'
-        $save_preseed << EOF
-d-i network-console/password-disabled boolean true
-d-i network-console/authorized_keys_url string $authorized_keys_url
-EOF
-    elif [ -n "$installer_password" ]; then
-        $save_preseed << EOF
-d-i network-console/password-disabled boolean false
-d-i network-console/password password $installer_password
-d-i network-console/password-again password $installer_password
-EOF
-    fi
-
+    [ -n "$authorized_keys_url" ] && echo "d-i network-console/authorized_keys_url string $authorized_keys_url" | $save_preseed
     echo 'd-i network-console/start select Continue' | $save_preseed
     echo 'd-i network-console/start select Continue' | $save_preseed
 fi
 fi
 
 
@@ -328,24 +321,15 @@ d-i mirror/udeb/suite string $suite
 EOF
 EOF
 
 
 if [ "$skip_account_setup" != true ]; then
 if [ "$skip_account_setup" != true ]; then
+    password_hash=
     if command_exists mkpasswd; then
     if command_exists mkpasswd; then
-        if [ -z "$password" ]; then
-            password="$(mkpasswd -m sha-512)"
-        else
-            password="$(mkpasswd -m sha-512 "$password")"
-        fi
+        password_hash=$(mkpasswd -m sha-512 "$password")
     elif command_exists busybox && busybox mkpasswd --help >/dev/null 2>&1; then
     elif command_exists busybox && busybox mkpasswd --help >/dev/null 2>&1; then
-        prompt_password
-        password="$(busybox mkpasswd -m sha512 "$password")"
+        password_hash=$(busybox mkpasswd -m sha512 "$password")
     elif command_exists python3; then
     elif command_exists python3; then
-        if [ -z "$password" ]; then
-            password="$(python3 -c 'import crypt, getpass; print(crypt.crypt(getpass.getpass(), crypt.mksalt(crypt.METHOD_SHA512)))')"
-        else
-            password="$(python3 -c "import crypt; print(crypt.crypt('$password', crypt.mksalt(crypt.METHOD_SHA512)))")"
-        fi
-    else
-        cleartext_password=true
-        prompt_password
+        password_hash=$(python3 -c 'import crypt, sys; print(crypt.crypt(sys.argv[1], crypt.mksalt(crypt.METHOD_SHA512)))' "$password")
+    elif command_exists python; then
+        password_hash=$(python -c 'import crypt, sys; print(crypt.crypt(sys.argv[1], crypt.mksalt(crypt.METHOD_SHA512)))' "$password" 2> /dev/null) || password_hash=
     fi
     fi
 
 
     $save_preseed << 'EOF'
     $save_preseed << 'EOF'
@@ -353,13 +337,15 @@ if [ "$skip_account_setup" != true ]; then
 # Account setup
 # Account setup
 
 
 EOF
 EOF
+    if [ -n "$authorized_keys_url" ]; then
+        sshd_conf PasswordAuthentication no
+    fi
 
 
     if [ "$username" = root ]; then
     if [ "$username" = root ]; then
         if [ -z "$authorized_keys_url" ]; then
         if [ -z "$authorized_keys_url" ]; then
-            backup /etc/ssh/sshd_config
-            run_later 'sed -Ei "s/^#?PermitRootLogin .+/PermitRootLogin yes/" /etc/ssh/sshd_config'
+            sshd_conf PermitRootLogin yes
         else
         else
-            run_later "mkdir -m 0700 -p ~root/.ssh && busybox wget -O - \"$authorized_keys_url\" >> ~root/.ssh/authorized_keys"
+            late_command "mkdir -m 0700 -p ~root/.ssh && busybox wget -O - \"$authorized_keys_url\" >> ~root/.ssh/authorized_keys"
         fi
         fi
 
 
         $save_preseed << 'EOF'
         $save_preseed << 'EOF'
@@ -367,24 +353,23 @@ d-i passwd/root-login boolean true
 d-i passwd/make-user boolean false
 d-i passwd/make-user boolean false
 EOF
 EOF
 
 
-        if [ "$cleartext_password" = true ]; then
+        if [ -z "$password_hash" ]; then
             $save_preseed << EOF
             $save_preseed << EOF
 d-i passwd/root-password password $password
 d-i passwd/root-password password $password
 d-i passwd/root-password-again password $password
 d-i passwd/root-password-again password $password
 EOF
 EOF
         else
         else
-            echo "d-i passwd/root-password-crypted password $password" | $save_preseed
+            echo "d-i passwd/root-password-crypted password $password_hash" | $save_preseed
         fi
         fi
     else
     else
-        backup /etc/ssh/sshd_config
-        run_later 'sed -Ei "s/^#?PermitRootLogin .+/PermitRootLogin no/" /etc/ssh/sshd_config'
+        sshd_conf PermitRootLogin no
 
 
         if [ -n "$authorized_keys_url" ]; then
         if [ -n "$authorized_keys_url" ]; then
-            run_later "sudo -u $username mkdir -m 0700 -p ~$username/.ssh && busybox wget -O - \"$authorized_keys_url\" | sudo -u $username tee -a ~$username/.ssh/authorized_keys"
+            late_command "sudo -u $username mkdir -m 0700 -p ~$username/.ssh && busybox wget -O - \"$authorized_keys_url\" | sudo -u $username tee -a ~$username/.ssh/authorized_keys"
         fi
         fi
 
 
-        if [ "$sudo_password" = false ]; then
-            run_later "echo \"$username ALL=(ALL:ALL) NOPASSWD:ALL\" > \"/etc/sudoers.d/90-user-$username\""
+        if [ "$sudo_with_password" = false ]; then
+            late_command "echo \"$username ALL=(ALL:ALL) NOPASSWD:ALL\" > \"/etc/sudoers.d/90-user-$username\""
         fi
         fi
 
 
         $save_preseed << EOF
         $save_preseed << EOF
@@ -394,13 +379,13 @@ d-i passwd/user-fullname string
 d-i passwd/username string $username
 d-i passwd/username string $username
 EOF
 EOF
 
 
-        if [ "$cleartext_password" = true ]; then
+        if [ -z "$password_hash" ]; then
             $save_preseed << EOF
             $save_preseed << EOF
 d-i passwd/user-password password $password
 d-i passwd/user-password password $password
 d-i passwd/user-password-again password $password
 d-i passwd/user-password-again password $password
 EOF
 EOF
         else
         else
-            echo "d-i passwd/user-password-crypted password $password" | $save_preseed
+            echo "d-i passwd/user-password-crypted password $password_hash" | $save_preseed
         fi
         fi
     fi
     fi
 fi
 fi
@@ -524,9 +509,9 @@ EOF
 
 
 [ "$hold" != true ] && echo 'd-i finish-install/reboot_in_progress note' | $save_preseed
 [ "$hold" != true ] && echo 'd-i finish-install/reboot_in_progress note' | $save_preseed
 
 
-[ "$bbr" = true ] && run_later '{ echo "net.core.default_qdisc=fq"; echo "net.ipv4.tcp_congestion_control=bbr"; } > /etc/sysctl.d/bbr.conf'
+[ "$bbr" = true ] && late_command '{ echo "net.core.default_qdisc=fq"; echo "net.ipv4.tcp_congestion_control=bbr"; } > /etc/sysctl.d/bbr.conf'
 
 
-[ -n "$late_command" ] && echo "d-i preseed/late_command string in-target bash -c '$late_command'" | $save_preseed
+[ -n "$in_target" ] && echo "d-i preseed/late_command string in-target dash -c '$in_target'" | $save_preseed
 
 
 [ "$power_off" = true ] && echo 'd-i debian-installer/exit/poweroff boolean true' | $save_preseed
 [ "$power_off" = true ] && echo 'd-i debian-installer/exit/poweroff boolean true' | $save_preseed
 
 
@@ -534,7 +519,7 @@ save_grub_cfg='cat'
 if [ "$dry_run" != true ]; then
 if [ "$dry_run" != true ]; then
     if [ -z "$architecture" ]; then
     if [ -z "$architecture" ]; then
         architecture=amd64
         architecture=amd64
-        command_exists dpkg && architecture="$(dpkg --print-architecture)"
+        command_exists dpkg && architecture=$(dpkg --print-architecture)
     fi
     fi
 
 
     base_url="$mirror_protocol://$mirror_host$mirror_directory/dists/$suite/main/installer-$architecture/current/images/netboot/debian-installer/$architecture"
     base_url="$mirror_protocol://$mirror_host$mirror_directory/dists/$suite/main/installer-$architecture/current/images/netboot/debian-installer/$architecture"
@@ -572,7 +557,7 @@ EOF
         grub_cfg=/boot/grub/grub.cfg
         grub_cfg=/boot/grub/grub.cfg
         update-grub
         update-grub
     elif command_exists grub2-mkconfig; then
     elif command_exists grub2-mkconfig; then
-        tmp="$(mktemp)"
+        tmp=$(mktemp)
         grep -vF zz_debi /etc/default/grub > "$tmp"
         grep -vF zz_debi /etc/default/grub > "$tmp"
         cat "$tmp" > /etc/default/grub
         cat "$tmp" > /etc/default/grub
         rm "$tmp"
         rm "$tmp"
@@ -590,7 +575,7 @@ fi
 installer_directory="$boot_directory$installer"
 installer_directory="$boot_directory$installer"
 
 
 # shellcheck disable=SC2034
 # shellcheck disable=SC2034
-mem="$(grep ^MemTotal: /proc/meminfo | { read -r x y z; echo "$y"; })"
+mem=$(grep ^MemTotal: /proc/meminfo | { read -r x y z; echo "$y"; })
 [ $((mem / 1024)) -lt 483 ] && kernel_params="$kernel_params lowmem/low="
 [ $((mem / 1024)) -lt 483 ] && kernel_params="$kernel_params lowmem/low="
 
 
 $save_grub_cfg 1>&2 << EOF
 $save_grub_cfg 1>&2 << EOF