一键脚本: 无VNC/救援模式更换VPS系统为Debian

全文转载自Vicer的博客萌咖

背景

  • 玩VPS的时候,常会遇到这种情况:
    商家提供的模板不太好;
    或者喜欢自己定制的环境。
  • 这时候,我们就需要简单的方法。

更新历史

  • [2017.06.04]
    增加全自动方式安装,实现在无救援模式,无VNC的情况下安装Debian.
    已在AWS Lightsail(Ubuntu),DigitalOcean,UltraVPS.eu通过测试.
    默认root密码:Vicer,安装完成后请立即更改密码.
  • [2017.03.28]
    增加了一个之参数选项;
    此参数用于手动指定机器的虚拟化类型。
    一般情况下不需要指定此参数。
  • [2017.03.25]
    修复了一些已知问题。

必要条件

  • KVM/VMware 构架;
  • Debian/Ubuntu/CentOS7 系统;
  • wget 用来下载文件,获取公网IP;
  • route 获取网关,掩码等;
  • sed awk grep 处理文本流;
  • VNC 安装系统。

安装

  • 确保安装了所需软件:
Debian/Ubuntu:
apt-get install -y gawk sed grep

CentOS:
yum install -y gawk sed grep

如果出现了错误,请运行:

Debian/Ubuntu:
apt-get update

CentOS:
yum update
  • 一键安装脚本下载,使用前请打开VNC:
wget --no-check-certificate -qO DebianNET.sh 'https://moeclub.org/attachment/LinuxShell/DebianNET.sh' && chmod -x DebianNET.sh

说明

 Usage:
        bash DebianNET.sh       -d/--debian [7/wheezye|8/jessie]
                                -v/--ver [32/i386|64/amd64]

特别参数,用于指定虚拟化类型:-t/--type [KVM|VMWare]

【默认】安装Debian 7 x32

bash DebianNET.sh -d wheezye -v i386

或者

bash DebianNET.sh -d 7 -v 32

安装Debian 7 x64

bash DebianNET.sh -d wheezye -v amd64

或者

bash DebianNET.sh -d 7 -v 64

安装Debian 8 x32

bash DebianNET.sh -d jessie -v i386

或者

bash DebianNET.sh -d 8 -v 32

安装Debian 8 x64

bash DebianNET.sh -d jessie -v amd64

或者

bash DebianNET.sh -d 8 -v 64

【默认】预览:

运行实例

完整代码

  • InstallOS
#!/bin/bash

while [[ $# -ge 1 ]]; do
  case $1 in
    -v|--ver)
      shift
      VERtmp="$1"
      shift
      ;;
    -d|--debian)
      shift
      vDEBtmp="$1"
      shift
      ;;
    -p|--password)
      shift
      WDtmp="$1"
      shift
      ;;
    -t|--type)
      shift
      Typetmp="$1"
      shift
      ;;
    *)
      echo -ne " Usage:\n\tbash $0\t-d/--debian [7/\033[33m\033[04mwheezye\033[0m|8/jessie]\n\t\t\t\t-v/--ver [32/\033[33m\033[04mi386\033[0m|64/amd64]\n"
      exit 1;
      ;;
    esac
  done

[ -f /boot/grub/grub.cfg ] && GRUBDIR='/boot/grub'
[ -z $GRUBDIR ] && [ -f /boot/grub2/grub.cfg ] && GRUBDIR='/boot/grub2'
[ -z $GRUBDIR ] && echo "Error! Not Found grub path." && exit 1

[ -z $Typetmp ] && {
[ -d '/boot/lost+found' ] && Type='VMWare' || Type='KVM'
} || {
[ $Typetmp == 'KVM' -o $Typetmp == 'VMWare' ] && Type=$Typetmp;
}
[ -z $Type ] && echo -ne "\033[31mError! \033[0mNot selected Virtualization Technology.\nPlease select it from \033[33m\033[04mKVM\033[0m or \033[33m\033[04mVMWare\033[0m! \n\n" && exit 1

[ -n $vDEBtmp ] && {
[ "$vDEBtmp" == '7' -o "$vDEBtmp" == 'wheezy' ] && vDEB='wheezy';
[ "$vDEBtmp" == '8' -o "$vDEBtmp" == 'jessie' ] && vDEB='jessie';
}
[ -n $vDEBtmp ] && {
[ "$VERtmp" == '32' -o "$VERtmp" == 'i386' ] && VER='i386';
[ "$VERtmp" == '64' -o "$VERtmp" == 'amd64' ] && VER='amd64';
}
[ -n $WDtmp ] && myPASSWORD="$WDtmp"

[ -z $vDEB ] && vDEB='wheezy';
[ -z $VER ] && VER='i386';
[ -z $myPASSWORD ] && myPASSWORD='Vicer'

clear && echo -e "\n\033[36m# Install\033[0m"

ASKVNC(){
inVNC='y';
echo -ne "\n\033[34mCan you login VNC?\033[0m\e[33m[\e[32my\e[33m/n]\e[0m "
read inVNCtmp
[[ -n "$inVNCtmp" ]] && inVNC=$inVNCtmp
[ "$inVNC" == 'y' -o "$inVNC" == 'Y' ] && inVNC='y'
[ "$inVNC" == 'n' -o "$inVNC" == 'N' ] && inVNC='n'
}

[ "$inVNC" == 'y' -o "$inVNC" == 'n' ] || ASKVNC;

echo -e "\n[\033[33m$vDEB\033[0m] [\033[33m$VER\033[0m] Downloading..."
wget --no-check-certificate -qO '/boot/initrd.gz' "http://httpredir.debian.org/debian/dists/$vDEB/main/installer-$VER/current/images/netboot/debian-installer/$VER/initrd.gz"
[ $? -ne '0' ] && echo -ne "\033[31mError! \033[0mDownload 'initrd.gz' failed! \n" && exit 1
wget --no-check-certificate -qO '/boot/linux' "http://httpredir.debian.org/debian/dists/$vDEB/main/installer-$VER/current/images/netboot/debian-installer/$VER/linux"
[ $? -ne '0' ] && echo -ne "\033[31mError! \033[0mDownload 'linux' failed! \n" && exit 1

GATEWAY="$(route -n |grep -A1 'Gateway' |awk 'END{print $2}')"
MASK="$(route -n |grep -A2 'mask' |awk 'END{print $3}')"
IPv4="$(wget -qO- checkip.amazonaws.com)"

[ ! -f $GRUBDIR/grub.cfg ] && echo "Error! Not Found grub.cfg. " && exit 1

[ ! -f $GRUBDIR/grub.cfg.old ] && [ -f $GRUBDIR/grub.cfg.bak ] && mv -f $GRUBDIR/grub.cfg.bak $GRUBDIR/grub.cfg.old
mv -f $GRUBDIR/grub.cfg $GRUBDIR/grub.cfg.bak
[ -f $GRUBDIR/grub.cfg.old ] && cat $GRUBDIR/grub.cfg.old >$GRUBDIR/grub.cfg || cat $GRUBDIR/grub.cfg.bak >$GRUBDIR/grub.cfg

CFG0="$(awk '/menuentry /{print NR}' $GRUBDIR/grub.cfg|head -n 1)"
CFG2="$(awk '/menuentry /{print NR}' $GRUBDIR/grub.cfg|head -n 2 |tail -n 1)"
CFG1=""
for CFGtmp in `awk '/}/{print NR}' $GRUBDIR/grub.cfg`
 do
  [ $CFGtmp -gt "$CFG0" -a $CFGtmp -lt "$CFG2" ] && CFG1="$CFGtmp";
 done
[ -z "$CFG1" ] && {
echo "Error! read grub.cfg. "
exit 1
}
sed -n "$CFG0,$CFG1"p $GRUBDIR/grub.cfg >/tmp/grub.new
[ -f /tmp/grub.new ] && [ "$(grep -c '{' /tmp/grub.new)" -eq "$(grep -c '}' /tmp/grub.new)" ] || {
echo -ne "\033[31mError! \033[0mNot configure grub.cfg. \n"
exit 1
}

sed -i "/menuentry.*/c\menuentry\ \'Install OS \[$vDEB\ $VER\]\'\ --class debian\ --class\ gnu-linux\ --class\ gnu\ --class\ os\ \{" /tmp/grub.new
[ "$(grep -c '{' /tmp/grub.new)" -eq "$(grep -c '}' /tmp/grub.new)" ] || {
echo "Error! configure append grub.cfg. "
exit 1
}
sed -i "/echo.*Loading/d" /tmp/grub.new

LinuxKernel="$(grep 'linux.*/' /tmp/grub.new |awk '{print $1}' |head -n 1)"
LinuxIMG="$(grep 'initrd.*/' /tmp/grub.new |awk '{print $1}' |tail -n 1)"

[ "$Type" == 'KVM' ] && {
sed -i "/linux.*\//c\\\t$LinuxKernel\\t\/boot\/linux auto=true hostname=debian domain= -- quiet" /tmp/grub.new
sed -i "/initrd.*\//c\\\t$LinuxIMG\\t\/boot\/initrd.gz" /tmp/grub.new
}

[ "$Type" == 'VMWare' ] && {
sed -i "/linux.*\//c\\\t$LinuxKernel\\t\/linux auto=true hostname=debian domain= -- quiet" /tmp/grub.new
sed -i "/initrd.*\//c\\\t$LinuxIMG\\t\/initrd.gz" /tmp/grub.new
}

sed -i '$a\\n' /tmp/grub.new

[ "$inVNC" == 'n' ] && {
[ -f /etc/network/interfaces ] && {
sed -i ''${CFG0}'i\\n' $GRUBDIR/grub.cfg
sed -i ''${CFG0}'r /tmp/grub.new' $GRUBDIR/grub.cfg
[ -d /boot/tmp ] && rm -rf /boot/tmp
mkdir -p /boot/tmp/
cd /boot/tmp/
gzip -d < ../initrd.gz | cpio --extract --verbose --make-directories --no-absolute-filenames >>/dev/null 2>&1
DISK="$(fdisk -l |grep 'Disk /dev/.*' |awk -F '[ :]' '{print $2}' |grep '^/' |sed '/ram/d' |head -n 1)"
cat >/boot/tmp/preseed.cfg<<EOF
d-i debian-installer/locale string en_US
d-i console-setup/layoutcode string us

d-i keyboard-configuration/xkb-keymap string us

d-i netcfg/choose_interface select auto

d-i netcfg/disable_autoconfig boolean true
d-i netcfg/dhcp_failed note
d-i netcfg/dhcp_options select Configure network manually
d-i netcfg/get_ipaddress string $IPv4
d-i netcfg/get_netmask string $MASK
d-i netcfg/get_gateway string $GATEWAY
d-i netcfg/get_nameservers string 8.8.8.8
d-i netcfg/confirm_static boolean true

d-i mirror/country string manual
d-i mirror/http/hostname string httpredir.debian.org
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string

d-i passwd/root-login boolean ture
d-i passwd/root-password password $myPASSWORD
d-i passwd/root-password-again password $myPASSWORD
d-i passwd/make-user boolean false

d-i clock-setup/utc boolean true
d-i time/zone string US/Eastern
d-i clock-setup/ntp boolean true

d-i partman-auto/init_automatically_partition select Guided - use entire disk
d-i partman-auto/disk string $DISK
d-i partman-auto/method string regular
d-i partman-auto/choose_recipe select atomic
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true

d-i debian-installer/allow_unauthenticated boolean true

tasksel tasksel/first multiselect minimal
d-i pkgsel/include string openssh-server
d-i pkgsel/upgrade select none

popularity-contest popularity-contest/participate boolean false

d-i grub-installer/only_debian boolean true
d-i finish-install/reboot_in_progress note
d-i debian-installer/exit/reboot boolean true

EOF
[ -d /etc/network/interfaces.d ] && ICFGN="$(ls -1 /etc/network/interfaces.d/*.cfg |wc -l)" || ICFGN='0'
[[ -z "$(sed -n '/iface.*inet static/p' /etc/network/interfaces)" ]] && AutoNet='1' || AutoNet='0'
[ "$ICFGN" -ne '0' ] && {
for NetCFG in `ls -1 /etc/network/interfaces.d/*.cfg`
 do 
  [[ -z "$(cat $NetCFG | sed -n '/iface.*inet static/p')" ]] && AutoNet='1' || AutoNet='0'
  [ "$AutoNet" -eq '0' ] && break
 done
}
[ "$AutoNet" -eq '1' ] && {
sed -i '/netcfg\/disable_autoconfig/d' /boot/tmp/preseed.cfg
sed -i '/netcfg\/dhcp_options/d' /boot/tmp/preseed.cfg
sed -i '/netcfg\/get_.*/d' /boot/tmp/preseed.cfg
sed -i '/netcfg\/confirm_static/d' /boot/tmp/preseed.cfg
}
[ -z "$DISK" ] && sed -i '/partman-auto\/disk/d' /boot/tmp/preseed.cfg
rm -rf ../initrd.gz
find . | cpio -H newc --create --verbose | gzip -9 > ../initrd.gz
rm -rf /boot/tmp
} || {
echo "Not found interfaces config."
exit 1
}
}

[ "$inVNC" == 'y' ] && {
sed -i '$i\\n' $GRUBDIR/grub.cfg
sed -i '$r /tmp/grub.new' $GRUBDIR/grub.cfg
echo -e "\n\033[33m\033[04mIt will reboot! \nPlease look at VNC! \nSelect\033[0m\033[32m Install OS [$vDEB $VER] \033[33m\033[4mto install system.\033[04m\n\n\033[31m\033[04mDO NOT CLOSE THE WINDOW! \033[0m\n"
echo -e "\033[35mIPv4\t\tMASK\t\tGATEWAY\033[0m"
echo -e "\033[36m\033[04m$IPv4\033[0m\t\033[36m\033[04m$MASK\033[0m\t\033[36m\033[04m$GATEWAY\033[0m\n\n"

read -n 1 -p "Press Enter to reboot..." INP
if [ "$INP" != '' ] ; then
echo -ne '\b \n'
echo "";
fi
}

chown root:root $GRUBDIR/grub.cfg
chmod 444 $GRUBDIR/grub.cfg

sleep 3 && reboot >/dev/null 2>&1

注意

  • 运行shell,尝试重启后如遇以下报错,请添加特别参数,指定虚拟化。
error: file '/boot/linux' not found
error: you need to load the kernel first.
  • 一般情况下,最后添加以下参数即可解决:
-t VMWare

【默认】示例:

bash DebianNET.sh -d wheezye -v i386 -t VMWare