From 732d3092c4ae78efae584e639fe01d44067aa0d3 Mon Sep 17 00:00:00 2001 From: Bohan Yang Date: Sun, 10 Jan 2021 02:27:21 +0000 Subject: [PATCH] Update --- README.md | 46 +++++++------- debi.sh | 177 +++++++++++++++++++++++++----------------------------- 2 files changed, 106 insertions(+), 117 deletions(-) diff --git a/README.md b/README.md index 556d536..e40a59e 100644 --- a/README.md +++ b/README.md @@ -28,27 +28,27 @@ This script is written to reinstall a VPS/virtual machine to Debian 10 Buster. ## Usage - curl -fLO https://raw.githubusercontent.com/bohanyang/debi/master/debi.sh && sudo bash debi.sh + curl -fL https://raw.githubusercontent.com/bohanyang/debi/master/debi.sh | sudo bash -s -- ## Available Options - * `--preset ` Shortcut for applying [preset options](#presets) * `--ip ` Static public/private IP, e.g. `10.0.0.2` - * `--netmask ` e.g. `255.255.255.0` / `ffff:ffff:ffff:ffff::` - * `--gateway ` 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 ` e.g. `255.255.255.0` / `ffff:ffff:ffff:ffff::`. Ignored if `--ip` is not specified + * `--gateway ` 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` - * `--installer-password ` Enable installer network console to monitor installation status. e.g. `ssh installer@10.0.0.2` - * `--authorized-keys-url ` 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` * `--mirror-protocol http` or `https` or `ftp` + * `--https` alias to `--mirror-protocol https` * `--mirror-host deb.debian.org` * `--mirror-directory /debian` * `--security-repository http://security.debian.org/debian-security` Magic value: `'mirror' = :////../debian-security` * `--skip-account-setup` * `--username debian` New user with `sudo` privilege or `root` - * `--password ` New user password to set. **Will be prompted if not specified here** - * `--sudo-password` Verify the user's password when running "sudo" commands + * `--password ` Password of the new user. **You'll be prompted if you choose to not specify it here** + * `--authorized-keys-url ` 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 * `--ntp 0.debian.pool.ntp.org` * `--skip-partitioning` @@ -60,11 +60,11 @@ This script is written to reinstall a VPS/virtual machine to Debian 10 Buster. * `--kernel ` Choose an package for the kernel image * `--cloud-kernel` Choose `linux-image-cloud-amd64` as the kernel image * `--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) * `--full-upgrade` `apt dist-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 * `--hold` Don't reboot or power off after installation * `--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 * `--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** - * `--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 -## Presets +### Presets -### `china` +### `--cdn` - * `--dns '223.5.5.5 223.6.6.6'` * `--mirror-protocol https` - * `--mirror-host mirrors.aliyun.com` + * `--mirror-host deb.debian.org` * `--security-repository mirror` - * `--ntp ntp.aliyun.com` -### `cloud` +### `--aws` - * `--dns '1.1.1.1 1.0.0.1'` * `--mirror-protocol https` - * `--mirror-host deb.debian.org` + * `--mirror-host cdn-aws.deb.debian.org` * `--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` diff --git a/debi.sh b/debi.sh index e96d917..f092874 100755 --- a/debi.sh +++ b/debi.sh @@ -1,4 +1,5 @@ -#!/bin/bash +#!/bin/sh +# shellcheck shell=dash set -euo pipefail @@ -11,20 +12,34 @@ command_exists() { 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() { - 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= @@ -32,9 +47,7 @@ netmask= gateway= dns='8.8.8.8 8.8.4.4' hostname= -installer_ssh=false -installer_password= -authorized_keys_url= +network_console=false suite=buster mirror_protocol=http mirror_host=deb.debian.org @@ -43,8 +56,8 @@ security_repository=http://security.debian.org/debian-security skip_account_setup=false username=debian password= -sudo_password=false -cleartext_password=false +authorized_keys_url= +sudo_with_password=false timezone=UTC ntp=0.debian.pool.ntp.org skip_partitioning=false @@ -69,25 +82,17 @@ dry_run=false while [ $# -gt 0 ]; do 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=$2 @@ -109,15 +114,8 @@ while [ $# -gt 0 ]; do hostname=$2 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=$2 @@ -142,7 +140,7 @@ while [ $# -gt 0 ]; do --skip-account-setup) skip_account_setup=true ;; - --username) + --user|--username) username=$2 shift ;; @@ -150,8 +148,12 @@ while [ $# -gt 0 ]; do password=$2 shift ;; - --sudo-password) - sudo_password=true + --authorized-keys-url) + authorized_keys_url=$2 + shift + ;; + --sudo-with-password) + sudo_with_password=true ;; --timezone) timezone=$2 @@ -287,30 +289,21 @@ fi 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 d-i anna/choose_modules string 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 - - 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 fi @@ -328,24 +321,15 @@ d-i mirror/udeb/suite string $suite EOF if [ "$skip_account_setup" != true ]; then + password_hash= 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 - prompt_password - password="$(busybox mkpasswd -m sha512 "$password")" + password_hash=$(busybox mkpasswd -m sha512 "$password") 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 $save_preseed << 'EOF' @@ -353,13 +337,15 @@ if [ "$skip_account_setup" != true ]; then # Account setup EOF + if [ -n "$authorized_keys_url" ]; then + sshd_conf PasswordAuthentication no + fi if [ "$username" = root ]; 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 - 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 $save_preseed << 'EOF' @@ -367,24 +353,23 @@ d-i passwd/root-login boolean true d-i passwd/make-user boolean false EOF - if [ "$cleartext_password" = true ]; then + if [ -z "$password_hash" ]; then $save_preseed << EOF d-i passwd/root-password password $password d-i passwd/root-password-again password $password EOF 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 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 - 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 - 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 $save_preseed << EOF @@ -394,13 +379,13 @@ d-i passwd/user-fullname string d-i passwd/username string $username EOF - if [ "$cleartext_password" = true ]; then + if [ -z "$password_hash" ]; then $save_preseed << EOF d-i passwd/user-password password $password d-i passwd/user-password-again password $password EOF 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 @@ -524,9 +509,9 @@ EOF [ "$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 @@ -534,7 +519,7 @@ save_grub_cfg='cat' if [ "$dry_run" != true ]; then if [ -z "$architecture" ]; then architecture=amd64 - command_exists dpkg && architecture="$(dpkg --print-architecture)" + command_exists dpkg && architecture=$(dpkg --print-architecture) fi 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 update-grub elif command_exists grub2-mkconfig; then - tmp="$(mktemp)" + tmp=$(mktemp) grep -vF zz_debi /etc/default/grub > "$tmp" cat "$tmp" > /etc/default/grub rm "$tmp" @@ -590,7 +575,7 @@ fi installer_directory="$boot_directory$installer" # 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=" $save_grub_cfg 1>&2 << EOF