#! /bin/bash echo "" echo "Updating local packages..." errors=`apt-add-repository universe >/dev/null 2>/dev/null && apt update 2>&1 >/dev/null` if [ "$?" = "0" ]; then echo "Done." else echo "Failed to add universal repository, update apt repository - $errors" exit 1 fi echo "" echo "Installing required setup configuration utilities..." errors=$(apt install -y dialog net-tools gdisk zfs-initramfs debootstrap >/dev/null 2>/dev/null) if [ "$?" = "0" ]; then echo "Done." else echo "Failed to install net-tools, gdisk, zfs-initramfs, or debootstrap - $errors" exit 2 fi #calculate width and height of console width=`tput cols` height=`tput lines` window=$((height - 5)) # gather input at the start devices=""; for device in $(ls /dev/disk/by-id | grep -v part); do devices="$devices $device off"; done disks=`dialog --separate-output --no-cancel --no-items --title "Root devices" --checklist "Select root OS disks:" $height $width ${window}$devices 2>&1 1>/dev/tty` diskcount=`echo "$disks" | wc -l` diskoptions="12 35 5 raidz off raidz2 off raidz3 off mirror off none off" if [ "$diskcount" = "0" ] ; then echo "No disks found to use for boot device"; exit 112; fi if [ "$diskcount" = "1" ]; then diskoptions="8 35 1 none off"; fi if [ "$diskcount" = "2" ]; then diskoptions="9 35 2 mirror off none off"; fi if [ "$diskcount" = "3" ]; then diskoptions="10 35 3 raidz off mirror off none off"; fi if [ "$diskcount" = "4" ]; then diskoptions="12 35 5 raidz off raidz2 off raidz3 off mirror off none off"; fi if [ "$diskcount" = "5" ]; then diskoptions="12 35 5 raidz off raidz2 off raidz3 off mirror off none off"; fi if [ "$diskcount" = "6" ]; then diskoptions="12 35 5 raidz off raidz2 off raidz3 off mirror off none off"; fi if [ "$diskcount" -gt "6" ]; then diskoptions="11 35 4 raidz2 off raidz3 off mirror off none off"; fi if [ "$diskcount" -gt "11" ]; then diskoptions="10 35 3 raidz3 off mirror off none off"; fi raidtype=`dialog --no-items --no-cancel --title "Root pool ZFS RAID" --radiolist "Select root pool ZFS RAID type:" $diskoptions 2>&1 1>/dev/tty` hostname=""; while [ -z "$hostname" ]; do hostname=`dialog --no-cancel --inputbox "Hostname:" 8 40 2>&1 >/dev/tty`; done domainname=""; while [ -z "$domainname" ]; do domainname=`dialog --no-cancel --inputbox "Domain name root (for fully qualified domain, e.g. company.com):" 8 40 2>&1 >/dev/tty`; done fqdn="${hostname}.${domainname}" nicdevices=""; for nic in $(ip -o link show | awk -F': ' '{print $2}' | grep -v '^lo'); do nicdevices="$nicdevices $nic off"; done nics=`dialog --separate-output --no-cancel --no-items --title "Bridged network devices" --checklist "Select the network devices to be bridged to br0:" $height $width ${window}$nicdevices 2>&1 1>/dev/tty` networktype=`dialog --no-items --no-cancel --title "Network type" --radiolist "Select the network type:" 9 40 2 dhcp off static off 2>&1 1>/dev/tty` if [ "$networktype" = "static" ]; then address=""; while [ -z "$address" ]; do address=`dialog --no-cancel --inputbox "IP Address:" 8 40 2>&1 >/dev/tty`; done subnet=""; while [ -z "$subnet" ]; do subnet=`dialog --no-cancel --inputbox "Subnet mask:" 8 40 2>&1 >/dev/tty`; done gateway=""; while [ -z "$gateway" ]; do gateway=`dialog --no-cancel --inputbox "Gateway:" 8 40 2>&1 >/dev/tty`; done dns1=""; while [ -z "$dns1" ]; do dns1=`dialog --no-cancel --inputbox "Primary DNS server:" 8 40 2>&1 >/dev/tty`; done dns2=`dialog --no-cancel --inputbox "Secondary DNS server:" 8 40 2>&1 >/dev/tty` fi admin=""; while [ -z "$admin" ]; do admin=`dialog --no-cancel --inputbox "Admin user:" 8 40 2>&1 >/dev/tty`; done rootpassword="" while [ "$rootpassword" = "" ]; do rootpassword=`dialog --no-cancel --title "Root password" --insecure --passwordbox "Enter root password:" 8 40 2>&1 1>/dev/tty` confirmpassword=`dialog --no-cancel --title "Root password confirmation" --insecure --passwordbox "Re-enter root password:" 8 40 2>&1 1>/dev/tty` if ! [ "$rootpassword" = "$confirmpassword" ]; then echo "Password does not match confirmation - please retry the setup" rootpassword="" fi done admins=`dialog --no-items --no-cancel --title "Root pool ZFS RAID" --inputbox "List administrator e-mail addresses separated by comma:" 10 40 2>&1 1>/dev/tty` a=""; for x in `timedatectl list-timezones`; do a="$a $x" ; done smtp=""; while [ -z "$smtp" ]; do smtp=`dialog --no-cancel --inputbox "Outoing e-mail SMTP proxy server:" 8 40 2>&1 >/dev/tty`; done email=""; while [ -z "$email" ]; do email=`dialog --no-cancel --inputbox "Outgoing mail username:" 8 40 2>&1 >/dev/tty`; done emailpassword="" while [ "$emailpassword" = "" ]; do emailpassword=`dialog --no-cancel --title "Outgoing e-mail SMTP mail password" --insecure --passwordbox "Enter outgoing e-mail SMTP password:" 8 40 2>&1 1>/dev/tty` confirmpassword=`dialog --no-cancel --title "Outgoing e-mail SMTP mail password" --insecure --passwordbox "Re-enter outgoing e-mail SMTP password:" 8 40 2>&1 1>/dev/tty` if ! [ "$emailpassword" = "$confirmpassword" ]; then echo "Password does not match confirmation - please retry the setup" emailpassword="" fi done timezone=`dialog --no-items --no-cancel --menu "Select time zone:" $height 40 ${window}${a} 2>&1 1>/dev/tty` #timedatectl list-timezones #timezone=`dialog --no-cancel --title "Timezone" --inputbox "Time zone:" 8 40 "America/Los_Angeles" 2>&1 1>/dev/tty` for disk in `echo "$disks"`; do echo "" echo "Partitioning disk $disk..." errors=`sgdisk --zap-all /dev/disk/by-id/$disk 2>&1 1>/dev/null && sgdisk -n2:1M:+512M -t2:EF00 /dev/disk/by-id/$disk 2>&1 1>/dev/null && sgdisk -n3:0:+512M -t3:BF01 /dev/disk/by-id/$disk 2>&1 1>/dev/null && sgdisk -n4:0:0 -t4:BF01 /dev/disk/by-id/$disk 2>&1 1>/dev/null` if ! [ "$?" = "0" ]; then echo "Failed to partition disk $disk - $errors" exit 3 fi echo "Done." done # create boot mirror list bootmirror=""; rootraidz=""; for disk in `echo "$disks"`; do bootmirror="$bootmirror /dev/disk/by-id/${disk}-part3"; rootraidz="$rootraidz /dev/disk/by-id/${disk}-part4"; done # refresh drives or there are missing partitions partprobe 2>/dev/null 1>/dev/null # wait for the partitions to show up for disk in `echo "$disks"`; do pending="0" while ! [ -e "/dev/disk/by-id/${disk}-part3" ]; do partprobe 2>/dev/null 1>/dev/null if [ "$pending" = "0" ]; then echo "" && echo "Waiting for ${disk} partition 3 to update..."; pending="1"; fi sleep 3 done if [ "$pending" = "1" ]; then echo "Done."; fi done echo "" echo "Creating boot zpool..." errors=`zpool create -f -o ashift=12 -d -o feature@async_destroy=enabled -o feature@bookmarks=enabled -o feature@embedded_data=enabled -o feature@empty_bpobj=enabled -o feature@enabled_txg=enabled -o feature@extensible_dataset=enabled -o feature@filesystem_limits=enabled -o feature@hole_birth=enabled -o feature@large_blocks=enabled -o feature@lz4_compress=enabled -o feature@spacemap_histogram=enabled -o feature@userobj_accounting=enabled -O acltype=posixacl -O canmount=off -O compression=lz4 -O devices=off -O normalization=formD -O relatime=on -O xattr=sa -O mountpoint=/ -R /mnt bpool mirror$bootmirror 2>&1 1>/dev/null` if ! [ "$?" = "0" ]; then echo "Failed to create boot pool - $errors" exit 4 fi echo "Done." # no striped mirror support yet # special exception for none raid - this just operates the disks like a stripe, for 1 or more disk - *not* recommended if [ "$raidtype" = "none" ]; then raidtype="" else raidtype=" $raidtype" fi echo "" echo "Creating main zpool..." error=`zpool create -f -o ashift=12 -O acltype=posixacl -O canmount=off -O compression=lz4 -O dnodesize=auto -O normalization=formD -O relatime=on -O xattr=sa -O mountpoint=/ -R /mnt rpool${raidtype}${rootraidz} 2>&1 1>/dev/null` if ! [ "$?" = "0" ]; then echo "Failed to create main pool - $errors" exit 5 fi echo "Done." echo "" echo "Setting up main zpool dataset configuration..." errors=`zfs create -o canmount=off -o mountpoint=none rpool/ROOT 2>&1 1>/dev/null && zfs create -o canmount=off -o mountpoint=none bpool/BOOT 2>&1 1>/dev/null && zfs create -o canmount=noauto -o mountpoint=/ rpool/ROOT/ubuntu 2>&1 1>/dev/null && zfs mount rpool/ROOT/ubuntu 2>&1 1>/dev/null && zfs create -o canmount=noauto -o mountpoint=/boot bpool/BOOT/ubuntu 2>&1 1>/dev/null && zfs mount bpool/BOOT/ubuntu 2>&1 1>/dev/null && zfs create rpool/home 2>&1 1>/dev/null && zfs create -o mountpoint=/root rpool/home/root 2>&1 1>/dev/null && zfs create -o canmount=off rpool/var 2>&1 1>/dev/null && zfs create -o canmount=off rpool/var/lib 2>&1 1>/dev/null && zfs create rpool/var/log 2>&1 1>/dev/null && zfs create rpool/var/spool 2>&1 1>/dev/null && zfs create -o com.sun:auto-snapshot=false rpool/var/cache 2>&1 1>/dev/null && zfs create -o com.sun:auto-snapshot=false rpool/var/tmp 2>&1 1>/dev/null && chmod 1777 /mnt/var/tmp 2>&1 1>/dev/null && zfs create rpool/opt 2>&1 1>/dev/null && zfs create rpool/srv 2>&1 1>/dev/null && zfs create -o canmount=off rpool/usr 2>&1 1>/dev/null && zfs create rpool/usr/local 2>&1 1>/dev/null && zfs create rpool/var/mail 2>&1 1>/dev/null && zfs create -o com.sun:auto-snapshot=false rpool/var/lib/docker 2>&1 1>/dev/null && zfs create -o com.sun:auto-snapshot=false rpool/var/lib/nfs 2>&1 1>/dev/null && zfs create -o com.sun:auto-snapshot=false rpool/tmp 2>&1 1>/dev/null && chmod 1777 /mnt/tmp 2>&1 1>/dev/null` if ! [ "$?" = "0" ]; then echo "Error setting up ZFS settings - $errors" exit 5 fi echo "Done." echo "" echo "Bootstrapping..." errors=`debootstrap bionic /mnt 2>&1 1>/dev/null` if ! [ "$?" = "0" ]; then echo "Failed to bootstrap root - $errors" exit 6 fi echo "Done." echo "" echo "Disabling ZFS devices..." errors=`zfs set devices=off rpool 2>&1 1>/dev/null` if ! [ "$?" = "0" ]; then echo "Failed to set devices=off for root pool- $errors" exit 7 fi echo "Done." echo "" echo "Setting hostname..." echo "$hostname" > /mnt/etc/hostname echo "127.0.0.1 $hostname $fqdn" > /mnt/etc/hosts echo "127.0.1.1 $hostname" >> /mnt/etc/hosts echo "Done." echo "" echo "Setting default apt repositories" echo "deb http://archive.ubuntu.com/ubuntu bionic main universe" > /mnt/etc/apt/sources.list echo "deb-src http://archive.ubuntu.com/ubuntu bionic main universe" >> /mnt/etc/apt/sources.list echo "deb http://security.ubuntu.com/ubuntu bionic-security main universe" >> /mnt/etc/apt/sources.list echo "deb-src http://security.ubuntu.com/ubuntu bionic-security main universe" >> /mnt/etc/apt/sources.list echo "deb http://archive.ubuntu.com/ubuntu bionic-updates main universe" >> /mnt/etc/apt/sources.list echo "deb-src http://archive.ubuntu.com/ubuntu bionic-updates main universe" >> /mnt/etc/apt/sources.list echo "Done." #echo "network:" > /mnt/etc/netplan/bridge.yaml #echo " version: 2" >> /mnt/etc/netplan/bridge.yaml #echo " renderer: networkd" >> /mnt/etc/netplan/bridge.yaml #echo " ethernets:" >> /mnt/etc/netplan/bridge.yaml #for nic in "$nics"; do #echo " ${nic}:" >> /mnt/etc/netplan/bridge.yaml #echo " dhcp4: no" >> /mnt/etc/netplan/bridge.yaml #done #echo " bridges:" >> /mnt/etc/netplan/bridge.yaml #echo " br0:" >> /mnt/etc/netplan/bridge.yaml #echo " macaddress: ${macaddr}" >> /mnt/etc/netplan/bridge.yaml #echo " dhcp4: yes" >> /mnt/etc/netplan/bridge.yaml #echo " parameters:" >> /mnt/etc/netplan/bridge.yaml #echo " stp: true" >> /mnt/etc/netplan/bridge.yaml #echo " forward-delay: 0" >> /mnt/etc/netplan/bridge.yaml #echo " interfaces:" >> /mnt/etc/netplan/bridge.yaml #for nic in `echo "$nics"`; do #echo " - ${nic}" >> /mnt/etc/netplan/bridge.yaml #done echo "" echo "Setting up boot pool import service..." echo "[Unit]"> /mnt/etc/systemd/system/zfs-import-bpool.service echo " DefaultDependencies=no" >> /mnt/etc/systemd/system/zfs-import-bpool.service echo " Before=zfs-import-scan.service" >> /mnt/etc/systemd/system/zfs-import-bpool.service echo " Before=zfs-import-cache.service" >> /mnt/etc/systemd/system/zfs-import-bpool.service echo "" >> /mnt/etc/systemd/system/zfs-import-bpool.service echo "[Service]" >> /mnt/etc/systemd/system/zfs-import-bpool.service echo " Type=oneshot" >> /mnt/etc/systemd/system/zfs-import-bpool.service echo " RemainAfterExit=yes" >> /mnt/etc/systemd/system/zfs-import-bpool.service echo " ExecStart=/sbin/zpool import -N -o cachefile=none bpool" >> /mnt/etc/systemd/system/zfs-import-bpool.service echo "[Install]" >> /mnt/etc/systemd/system/zfs-import-bpool.service echo " WantedBy=zfs-import.target " >> /mnt/etc/systemd/system/zfs-import-bpool.service echo "Done." echo "" echo "Creating home directory..." errors=`zfs create rpool/home/${admin} 2>&1 1>/dev/null` if ! [ "$?" = "0" ]; then echo "Unable to create home directory - $errors" exit 9 fi echo "Done." echo "" echo "Mounting chroot mounts..." mount --rbind /dev /mnt/dev mount --rbind /proc /mnt/proc mount --rbind /sys /mnt/sys echo "Done." echo "" echo "Entering chroot..." echo "#!/bin/bash" > /mnt/setup-chroot.sh echo "HOSTNAME=\"$hostname\"" >> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh echo "echo \"\"" >> /mnt/setup-chroot.sh echo "echo \"Mounting /proc/self/mounts...\"" >> /mnt/setup-chroot.sh echo "ln -s /proc/self/mounts /etc/mtab" >> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh echo "echo \"\"" >> /mnt/setup-chroot.sh echo "echo \"Updating apt repositories on root pool...\"" >> /mnt/setup-chroot.sh echo 'errors=`apt update 2>&1 1>/dev/null`' >> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to update apt repositories on root pool - $errors"' >> /mnt/setup-chroot.sh echo " exit 1">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo "echo \"Done.\"">> /mnt/setup-chroot.sh echo "echo \"\"">> /mnt/setup-chroot.sh echo "echo \"Setting locale...\"" >> /mnt/setup-chroot.sh echo 'errors=`locale-gen en_US.UTF-8 2>&1 1>/dev/null`' >> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to set the locale to en_US.UTF-8 - $errors"' >> /mnt/setup-chroot.sh echo " exit 1">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh echo "echo \"\"" >> /mnt/setup-chroot.sh echo "echo \"Setting time zone...\"" >> /mnt/setup-chroot.sh echo "cp /usr/share/zoneinfo/$timezone /etc/localtime" >> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh echo "echo \"\"" >> /mnt/setup-chroot.sh echo "echo \"Installing linux image, ifupdown dnsutils nfs-kernel-server apparmor-profiles vim bridge-utils net-tools bash screen tmux zfs-initramfs dosfstools mailutils ssmtp openssh-server ufw docker.io sharutils...\"" >> /mnt/setup-chroot.sh echo "errors=\$(DEBCONF_FRONTEND='noninteractive' apt install -y --no-install-recommends linux-image-generic 2>&1 1>/dev/null && apt purge -y netplan 2>&1 1>/dev/null && apt autoremove -y 2>&1 1>/dev/null && DEBCONF_FRONTEND='noninteractive' apt install -y ifupdown dnsutils nfs-kernel-server apparmor-profiles vim bridge-utils net-tools bash screen tmux zfs-initramfs dosfstools mailutils ssmtp openssh-server ufw docker.io sharutils 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to install preliminary software - $errors"' >> /mnt/setup-chroot.sh echo " exit 1">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh # network configuration should have optional static configuration - not just DHCP, it's very important echo "echo \"\"" >> /mnt/setup-chroot.sh echo "echo \"Enabling networking service...\"" >> /mnt/setup-chroot.sh echo "error=\$(systemctl unmask networking 2>&1 1>/dev/null && systemctl enable networking 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to enable networking service - $errors"' >> /mnt/setup-chroot.sh echo " exit 118">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh # configure docker storage to use zfs mkdir -p /mnt/etc/docker echo "{\"storage-driver\":\"zfs\"}" > /mnt/etc/docker/daemon.json echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /mnt/etc/sysctl.conf echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /mnt/etc/sysctl.conf echo "net.ipv6.conf.lo.disable_ipv6 = 1" >> /mnt/etc/sysctl.conf echo 'echo ""' >> /mnt/setup-chroot.sh echo 'echo "Creating EFI partition..."' >> /mnt/setup-chroot.sh firstdisk=`echo "$disks" | head -n1` echo "error=\$(mkdosfs -F 32 -s 1 -n EFI /dev/disk/by-id/${firstdisk}-part2 2>&1 1>/dev/null && mkdir /boot/efi 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to create dos file system for EFI partition - $errors"' >> /mnt/setup-chroot.sh echo " exit 100">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo "echo PARTUUID=$(blkid -s PARTUUID -o value /dev/disk/by-id/${firstdisk}-part2) /boot/efi vfat nofail,x-systemd.device-timeout=0 0 1 >> /etc/fstab" >> /mnt/setup-chroot.sh echo "errors=\$(mount /boot/efi 2>&1 1>/dev/null && apt install -y grub-efi-amd64-signed shim-signed 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to mount EFI partition or install grub-EFI - $errors"' >> /mnt/setup-chroot.sh echo " exit 1">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo 'echo "Done."' >> /mnt/setup-chroot.sh echo "echo ''" >> /mnt/setup-chroot.sh echo 'echo "Setting root password..."' >> /mnt/setup-chroot.sh echo "errors=\$(echo 'root:${rootpassword}' | chpasswd 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo "if ! [ \"\$?\" = \"0\" ]; then echo \"Could not set root password - \$errors\"; exit 21; fi" >> /mnt/setup-chroot.sh echo 'echo "Done."'>> /mnt/setup-chroot.sh echo 'echo ""' >> /mnt/setup-chroot.sh echo 'echo "Enabling boot pool import service..."'>> /mnt/setup-chroot.sh echo "errors=\$(systemctl enable zfs-import-bpool.service 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to enable boot pool import service - $errors"' >> /mnt/setup-chroot.sh echo " exit 102">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo 'echo "Done."'>> /mnt/setup-chroot.sh #echo 'echo ""'>> /mnt/setup-chroot.sh #echo 'echo "Enabling tmp file system mounting..."'>> /mnt/setup-chroot.sh #echo "errors=\$(cp /usr/sharesystemd/tmp.mount /etc/systemd/system/ 2>&1 1>/dev/null && systemctl enable tmp.mount 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh #echo "if ! [ \"\$?\" = \"0\" ]; then echo \"Failed to enable tmp file system mounting - \$errors\"; exit 103; fi" >> /mnt/setup-chroot.sh #echo 'echo "Done."'>> /mnt/setup-chroot.sh #addgroup --system lpadmin #addgroup --system sambashare echo 'echo ""' >> /mnt/setup-chroot.sh echo "echo \"Checking ZFS root...\"" >> /mnt/setup-chroot.sh echo 'zfscheck=$(grub-probe /boot 2>&1 1>/dev/null)' >> /mnt/setup-chroot.sh echo "if ! [ \"\$?\" = \"0\" ]; then echo \"grub-probe check failed - \$zfscheck\"; exit 2; fi" >> /mnt/setup-chroot.sh echo "echo \"Success.\"" >> /mnt/setup-chroot.sh echo 'echo ""' >> /mnt/setup-chroot.sh echo 'echo "Updating initramfs..."' >> /mnt/setup-chroot.sh echo 'errors=$(update-initramfs -u -k all 2>&1 1>/dev/null)' >> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to update initramfs - $errors"' >> /mnt/setup-chroot.sh echo " exit 1">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh # you need sed to do this right! echo 'echo ""' >> /mnt/setup-chroot.sh echo 'echo "Modifying grub for ZFS root..."' >> /mnt/setup-chroot.sh echo "errors=\$(sed -ir 's/quiet splash//g' /etc/default/grub 2>&1 1>/dev/null && sed -ir 's/GRUB_CMDLINE_LINUX=\".*\"/GRUB_CMDLINE_LINUX=\"root=ZFS=rpool\/ROOT\/ubuntu\"/g' /etc/default/grub 2>&1 1>/dev/null && sed -ir 's/^#GRUB_TERMINAL=console/GRUB_TERMINAL=console/g' /etc/default/grub 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo "if ! [ \"\$?\" = \"0\" ]; then echo \"Failed to set grub ZFS root - \$errors\"; exit 104; fi" >> /mnt/setup-chroot.sh echo 'echo "Done."' >> /mnt/setup-chroot.sh echo 'echo ""' >> /mnt/setup-chroot.sh echo 'echo "Updating grub..."' >> /mnt/setup-chroot.sh echo 'errors=$(update-grub 2>&1 1>/dev/null)'>> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to update grub - $errors"' >> /mnt/setup-chroot.sh echo " exit 1">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh echo 'echo ""' >> /mnt/setup-chroot.sh echo 'echo "Installing grub UEFI on plex1..."' >> /mnt/setup-chroot.sh echo "errors=\$(grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck --no-floppy 2>&1 1>/dev/null && umount /boot/efi 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo "if ! [ \"\$?\" = \"0\" ]; then echo \"Failed to install grub UEFI on plex1 - \$errors\"; exit 104; fi" >> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh if ! [ "$disks" = "" ]; then echo 'echo ""' >> /mnt/setup-chroot.sh echo 'echo "Copying EFI partition to other boot disks..."' >> /mnt/setup-chroot.sh i="2" for disk in `echo "$disks" | tail -n+2`; do echo "errors=\$(dd if=/dev/disk/by-id/${firstdisk}-part2 of=/dev/disk/by-id/${disk}-part2 2>&1 1>/dev/null && efibootmgr -c -g -d /dev/disk/by-id/${disk} -p 3 -L "ubuntu-$i" -l '\EFI\ubuntu\grubx64.efi' 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo "if ! [ \"\$?\" = \"0\" ]; then echo \"EFI copy failed - \$errors\"; exit 20; fi" >> /mnt/setup-chroot.sh i=$((i + 1)) done echo 'echo "Done."' >> /mnt/setup-chroot.sh fi # error check this as one big block echo "zfs set mountpoint=legacy bpool/BOOT/ubuntu" >> /mnt/setup-chroot.sh echo "echo \"bpool/BOOT/ubuntu /boot zfs nodev,relatime,x-systemd.requires=zfs-import-bpool.service 0 0\" >> /etc/fstab" >> /mnt/setup-chroot.sh echo "zfs set mountpoint=legacy rpool/var/log">> /mnt/setup-chroot.sh echo "echo \"rpool/var/log /var/log zfs nodev,relatime 0 0\" >> /etc/fstab" >> /mnt/setup-chroot.sh echo "zfs set mountpoint=legacy rpool/var/spool">> /mnt/setup-chroot.sh echo "echo \"rpool/var/spool /var/spool zfs nodev,relatime 0 0\" >> /etc/fstab" >> /mnt/setup-chroot.sh echo "zfs set mountpoint=legacy rpool/var/tmp" >> /mnt/setup-chroot.sh echo "echo \"rpool/var/tmp /var/tmp zfs nodev,relatime 0 0\" >> /etc/fstab" >> /mnt/setup-chroot.sh echo "zfs set mountpoint=legacy rpool/tmp" >> /mnt/setup-chroot.sh echo "echo \"rpool/tmp /tmp zfs nodev,relatime 0 0\" >> /etc/fstab" >> /mnt/setup-chroot.sh echo 'echo ""' >> /mnt/setup-chroot.sh echo 'echo "Enabling SSH..."'>> /mnt/setup-chroot.sh echo "sed -ir 's/^ *#? *ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/g' /etc/ssh/sshd_config" >> /mnt/setup-chroot.sh echo "sed -ir 's/^#PasswordAuthentication.*/PasswordAuthentication no/g' /etc/ssh/sshd_config" >> /mnt/setup-chroot.sh echo "sed -ir 's/^UsePAM.*/UsePAM no/g' /etc/ssh/sshd_config" >> /mnt/setup-chroot.sh echo "sed -ir 's/^#PermitRootLogin.*/PermitRootLogin no/g' /etc/ssh/sshd_config" >> /mnt/setup-chroot.sh echo "errors=\$(systemctl enable ssh 2>&1 1>/dev/null)">> /mnt/setup-chroot.sh #&& ufw allow in on any from any to any port 22 proto tcp 2>&1 1>/dev/null echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to enable SSH - $errors"' >> /mnt/setup-chroot.sh echo " exit 101">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo 'echo "Done."'>> /mnt/setup-chroot.sh echo 'echo ""'>> /mnt/setup-chroot.sh echo 'echo "Creating admin user..."'>> /mnt/setup-chroot.sh # error check this echo "useradd $admin" >> /mnt/setup-chroot.sh echo "cp -a /etc/skel/.[!.]* \"/home/$admin\"" >> /mnt/setup-chroot.sh echo "chown -R ${admin}:${admin} \"/home/$admin\"" >> /mnt/setup-chroot.sh echo "usermod -a -G adm,cdrom,dip,plugdev,sudo -s /bin/bash \"$admin\"" >> /mnt/setup-chroot.sh echo "echo '${admin}:${rootpassword}' | chpasswd" >> /mnt/setup-chroot.sh echo 'echo "Done."'>> /mnt/setup-chroot.sh # relax app armor for nfs kernel server #echo "aa-complain nfsd" >> /mnt/setup-chroot.sh #create swap space, too if necessary #sendemail -t to@example.com -m "Here is the file." -a attachmentFile echo "mkdir \"/home/${admin}/.ssh\"" >> /mnt/setup-chroot.sh echo "ssh-keygen -b 4096 -t rsa -q -f \"/home/${admin}/.ssh/id_rsa\" -N '$rootpassword'" >> /mnt/setup-chroot.sh echo "cat /home/${admin}/.ssh/id_rsa.pub > /home/${admin}/.ssh/authorized_keys" >> /mnt/setup-chroot.sh #echo "chmod 600 \"/home/${admin}/.ssh/id_rsa\"" >> /mnt/setup-chroot.sh echo "chown -R ${admin}:${admin} \"/home/${admin}\"/.ssh" >> /mnt/setup-chroot.sh echo "HOME=\"/root\"" >> /mnt/setup-chroot.sh echo "HOSTNAME=\"$hostname\"" >> /mnt/setup-chroot.sh echo "echo \"FromLineOverride=YES\" > /etc/ssmtp/ssmtp.conf" >> /mnt/setup-chroot.sh echo "echo \"root=admin\" >> /etc/ssmtp/ssmtp.conf" >> /mnt/setup-chroot.sh echo "echo \"hostname=${fqdn}\" >> /etc/ssmtp/ssmtp.conf" >> /mnt/setup-chroot.sh echo "echo \"AuthUser=${email}\" >> /etc/ssmtp/ssmtp.conf" >> /mnt/setup-chroot.sh echo "echo \"AuthPass=${emailpassword}\" >> /etc/ssmtp/ssmtp.conf" >> /mnt/setup-chroot.sh echo "echo \"mailhub=${smtp}\" >> /etc/ssmtp/ssmtp.conf" >> /mnt/setup-chroot.sh echo "echo \"UseSTARTTLS=YES\" >> /etc/ssmtp/ssmtp.conf" >> /mnt/setup-chroot.sh echo "echo \"\"" >> /mnt/setup-chroot.sh echo "echo \"Sending SSH key via e-mail...\"" >> /mnt/setup-chroot.sh if [ "$networktype" = "dhcp" ]; then connection=`hostname -I` else connection="$address" fi # --content-filename=\"${hostname}.ssh.key\" --content-name=\"${hostname}.ssh.key\" echo "(echo \"Server available at $connection\"; cat \"/home/${admin}/.ssh/id_rsa\") | mail -s \"$hostname SSH key\" -A \"/home/${admin}/.ssh/id_rsa\" -r \"${email}\" \"${admins}\"" >> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh echo "exit 0" >> /mnt/setup-chroot.sh errors=`chmod +x /mnt/setup-chroot.sh 2>&1 1>/dev/null` if ! [ "$?" = "0" ]; then echo "Failed to set execution permission on chroot script - $errors" exit 45 fi chroot /mnt /setup-chroot.sh if ! [ "$?" = "0" ]; then exit $? fi echo "" echo "Writing network interfaces file..." macaddr=$(echo $hostname|md5sum|sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/') mkdir -p /mnt/etc/network && mkdir -p /mnt/etc/network/interfaces.d echo "auto lo br0" > /mnt/etc/network/interfaces.d/br0 echo "iface lo inet loopback" >> /mnt/etc/network/interfaces.d/br0 niclist="" for nic in "$nics"; do echo "iface ${nic} inet manual" >> /mnt/etc/network/interfaces.d/br0 niclist="$niclist $nic" done if [ "$networktype" = "dhcp" ]; then echo "iface br0 inet dhcp" >> /mnt/etc/network/interfaces.d/br0 else echo "iface br0 inet static" >> /mnt/etc/network/interfaces.d/br0 echo " address $address" >> /mnt/etc/network/interfaces.d/br0 echo " netmask $subnet" >> /mnt/etc/network/interfaces.d/br0 echo " gateway $gateway" >> /mnt/etc/network/interfaces.d/br0 sed -ir "s/^#DNS=.*/DNS=${dns1}/g" /mnt/etc/systemd/resolved.conf if ! [ -z "$dns2" ]; then sed -ir "s/^#FallbackDNS=.*/FallbackDNS=${dns2}/g" /mnt/etc/systemd/resolved.conf ; fi fi #echo " bridge_hw $macaddr" >> /mnt/etc/network/interfaces.d/br0 echo " dns-nameservers 127.0.0.53" >> /mnt/etc/network/interfaces.d/br0 echo " bridge_waitport 0" >> /mnt/etc/network/interfaces.d/br0 echo " bridge_fd 0" >> /mnt/etc/network/interfaces.d/br0 echo " bridge_ports${niclist}" >> /mnt/etc/network/interfaces.d/br0 echo " bridge_stp on" >> /mnt/etc/network/interfaces.d/br0 echo "source-directory /etc/network/interfaces.d" > /mnt/etc/network/interfaces echo "Done." echo "echo \"\"" >> /mnt/setup-chroot.sh echo "echo \"Enabling UFW and apparmor on boot...\"" >> /mnt/setup-chroot.sh #echo "errors=\$(systemctl enable ufw 2>&1 1>/dev/null && systemctl enable apparmor 2>&1 1>/dev/null && systemctl enable sendmail 2>&1 1>/dev/null)" >> /mnt/setup-chroot.sh echo 'if ! [ "$?" = "0" ]; then '>> /mnt/setup-chroot.sh echo ' echo "Failed to enable UFW - $errors"' >> /mnt/setup-chroot.sh echo " exit 1">> /mnt/setup-chroot.sh echo "fi">> /mnt/setup-chroot.sh echo "echo \"Done.\"" >> /mnt/setup-chroot.sh echo "systemctl unmask cron 2>/dev/null 1>/dev/null; systemctl enable cron 2>/dev/null 1>/dev/null" >> /mnt/setup-chroot.sh #crontab -l > mycron #echo new cron into cron file #echo "00 09 * * 1-5 echo hello" >> mycron #install new cron file #crontab mycron #rm mycron # add the firewall rule for SSH, but there may already be an exception for this, test the network in the live environment echo "" echo "Opening SSH port on firewall..." sed -ir 's/### RULES ###/### RULES ###\n-A ufw-user-input -i br0 -p tcp --dport 22 -j ACCEPT/g' /mnt/etc/ufw/user.rules 2>&1 1>/dev/null echo "Done." # commented out for debugging echo "" echo "Clearing chroot configuration script..." rm /mnt/setup-chroot.sh echo "Done." echo "#! /bin/bash" > /mnt/zfshealth.sh echo "problems=0; emailSubject=\"\`hostname\` - ZFS pool - HEALTH check\"; emailMessage=\"\"" >> /mnt/zfshealth.sh echo "condition=\$(/sbin/zpool status | egrep -i '(DEGRADED|FAULTED|OFFLINE|UNAVAIL|REMOVED|FAIL|DESTROYED|corrupt|cannot|unrecover)')" >> /mnt/zfshealth.sh echo "if [ \"\${condition}\" ]; then emailSubject=\"\$emailSubject - fault\"; problems=1; fi" >> /mnt/zfshealth.sh echo "maxCapacity=80" >> /mnt/zfshealth.sh echo "if [ \${problems} -eq 0 ]; then" >> /mnt/zfshealth.sh echo " capacity=\$(/sbin/zpool list -H -o capacity)" >> /mnt/zfshealth.sh echo " for line in \${capacity//%/}" >> /mnt/zfshealth.sh echo " do" >> /mnt/zfshealth.sh echo " if [ \$line -ge \$maxCapacity ]; then emailSubject=\"\$emailSubject - Capacity Exceeded\"; problems=1; fi" >> /mnt/zfshealth.sh echo " done" >> /mnt/zfshealth.sh echo "fi" >> /mnt/zfshealth.sh echo "if [ \${problems} -eq 0 ]; then" >> /mnt/zfshealth.sh echo " errors=\$(/sbin/zpool status | grep ONLINE | grep -v state | awk '{print $3 $4 $5}' | grep -v 000)" >> /mnt/zfshealth.sh echo " if [ \"\${errors}\" ]; then emailSubject=\"\$emailSubject - Drive Errors\"; problems=1; fi" >> /mnt/zfshealth.sh echo "fi" >> /mnt/zfshealth.sh echo "scrubExpire=691200" >> /mnt/zfshealth.sh echo "if [ \${problems} -eq 0 ]; then" >> /mnt/zfshealth.sh echo " currentDate=\$(date +%s)" >> /mnt/zfshealth.sh echo " zfsVolumes=\$(/sbin/zpool list -H -o name)" >> /mnt/zfshealth.sh echo " for volume in \${zfsVolumes}" >> /mnt/zfshealth.sh echo " do" >> /mnt/zfshealth.sh echo " if [ \$(/sbin/zpool status \$volume | egrep -c \"none requested\") -ge 1 ]; then echo \"ERROR: You need to run \\\"zpool scrub \$volume\\\" before this script can monitor the scrub expiration time.\"; break; fi" >> /mnt/zfshealth.sh echo " if [ \$(/sbin/zpool status \$volume | egrep -c \"scrub in progress|resilver\") -ge 1 ]; then break; fi" >> /mnt/zfshealth.sh echo " scrubRawDate=\$(/sbin/zpool status \$volume | grep scrub | awk '{print \$15 \$12 \$13}')" >> /mnt/zfshealth.sh echo " scrubDate=\$(date -j -f '%Y%b%e-%H%M%S' \$scrubRawDate'-000000' +%s)" >> /mnt/zfshealth.sh echo " if [ \$((\$currentDate - \$scrubDate)) -ge \$scrubExpire ]; then" >> /mnt/zfshealth.sh echo " if [ \${problems} -eq 0 ]; then emailSubject=\"\$emailSubject - Scrub Time Expired. Scrub Needed on Volume(s)\"; fi" >> /mnt/zfshealth.sh echo " problems=1" >> /mnt/zfshealth.sh echo " emailMessage=\"\${emailMessage}Pool: \$volume needs scrub \n\"" >> /mnt/zfshealth.sh echo " fi" >> /mnt/zfshealth.sh echo " done" >> /mnt/zfshealth.sh echo "fi" >> /mnt/zfshealth.sh echo "echo -e \"\$emailMessage \n\n\n \`/sbin/zpool list\` \n\n\n \`/sbin/zpool status\`\" | mail -r \"${email}\" -s \"\$emailSubject\" \"${admins}\"" >> /mnt/zfshealth.sh echo "if [ \"\$problems\" -ne 0 ]; then logger \$emailSubject; fi" >> /mnt/zfshealth.sh echo "echo \"0 0 * * 1 /zfshealth.sh\" | crontab" >> /mnt/zfshealth.sh chmod +x /mnt/zfshealth.sh echo "" echo "Unmounting chroot mounts..." mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | xargs -i{} umount -lf {} echo "Done." echo "" echo "Exporting zpools..." errors=`zpool export -a 2>&1 1>/dev/null` if ! [ "$?" = "0" ]; then echo "Couldn't export mounted zpools - $errors" exit 8 fi echo "Done." echo "Congratulations! The install was successful. Please reboot and set your boot device using UEFI in the BIOS." exit 0 #sed -i -r "s/(^|[^#y])(compress)/\1#\2/" "$file"