Ubuntu ISO with preseed.cfg generation script
#!/bin/bash
## FORSTWOOF UBUNTU PRESEED :: BUILD SCRIPT
# Quit on first error
set -e
# Temporary directory for the build
TMP="/var/tmp/ubuntu-build"
# Cleanup function
cleanup () {
echo "Cleaning up"
umount "${TMP}/files" || true
umount "${TMP}/mnt" || true
rm -r "${TMP}"
}
# Clean up on SIGINT
trap "cleanup" INT
# Get the script's running directory
SCRDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Directory from where script was started
CURDIR="$(pwd)"
# Preseed file
SEED="${SCRDIR}/preseed.cfg"
# Source and destination files
SRC="${1}"
DST="${2}"
echo "Performing file presence checks"
# Check if the source file exists
[ -f "${SRC}" ] || {
echo "The source file does not exist!"
exit 1
}
# Check if the source file is of an appropriate type
TYPE=$(file "${SRC}" | tail -c 16)
[ "${TYPE}" != "x86 boot sector" ] && {
echo "The source file is not a valid bootable ISO file!"
exit 3
}
# Check if the preseed file exists
[ -f "${SEED}" ] || {
echo "The preseed file does not exist!"
exit 2
}
# Check if the destination file exists and offer to delete it
[ -e "${DST}" ] && {
echo -n "The destination file already exists! Do you want to remove it? [y/N] "
read ANS
([ "${ANS}" == "y" ] || [ "${ANS}" == "Y" ]) || {
echo "Build cancelled."
exit 4
}
rm -r "${DST}"
}
# Create the temporary directory
echo "Creating a temporary directory"
[ -e "${TMP}" ] && cleanup
mkdir "${TMP}"
# Mount the source ISO image
echo "Mounting the source image"
mkdir "${TMP}/mnt"
mount -o ro "${SRC}" "${TMP}/mnt"
# Create an overlay file system
echo "Creating an overlay file system"
mkdir "${TMP}/files"
mkdir "${TMP}/overlay"
mkdir "${TMP}/work"
mount -t overlayfs -o lowerdir="${TMP}/mnt",upperdir="${TMP}/overlay",workdir="${TMP}/work" overlayfs "${TMP}/files"
# Enable serial console for EFI boot entries
echo "Enabling serial console for EFI boot entries (grub)"
cat <<EOF >"${TMP}/files/boot/grub/grub.cfg"
serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
terminal_input console serial
terminal_output console serial
menuentry "Install Ubuntu Server (automated)" {
linux /install/vmlinuz file=/cdrom/preseed/ubuntu-server.seed text console=ttyS0,115200n8 ---
initrd /install/initrd.gz
}
menuentry "Check disc for defects" {
linux /install/vmlinuz MENU=/bin/cdrom-checker-menu text console=ttyS0,115200n8 ---
initrd /install/initrd.gz
}
menuentry "Rescue a broken system" {
linux /install/vmlinuz rescue/enable=true text console=ttyS0,115200n8 ---
initrd /install/initrd.gz
}
EOF
# Enable serial console for legacy boot entries
echo "Enabling serial console for legacy boot entries (syslinux)"
cat <<EOF >"${TMP}/isolinux.cfg"
serial 0 115200 0x003
EOF
cat "${TMP}/files/isolinux/isolinux.cfg" >>"${TMP}/isolinux.cfg"
sed -i 's/default vesamenu.c32//g' "${TMP}/isolinux.cfg"
sed -i 's/ui gfxboot bootlogo//g' "${TMP}/isolinux.cfg"
mv "${TMP}/isolinux.cfg" "${TMP}/files/isolinux/isolinux.cfg"
sed -i 's/---/console=ttyS0,115200n8 ---/g' "${TMP}/files/isolinux/txt.cfg"
# Rebuilding initrd
echo "Rebuilding initrd for CD booting"
mkdir "${TMP}/initrd"
cd "${TMP}/initrd"
gzip -d < "${TMP}/files/install/initrd.gz" | cpio --extract --make-directories --no-absolute-filenames --quiet
rm "${TMP}/files/install/initrd.gz"
cp "${SEED}" "${TMP}/initrd"
find . | cpio -H newc --create --quiet | gzip -9 > "${TMP}/files/install/initrd.gz"
echo "Rebuilding initrd for network booting"
rm -r *
ARCH=$(ls "${TMP}/files/install/netboot/ubuntu-installer")
gzip -d < "${TMP}/files/install/netboot/ubuntu-installer/${ARCH}/initrd.gz" | cpio --extract --make-directories --no-absolute-filenames --quiet
rm "${TMP}/files/install/netboot/ubuntu-installer/${ARCH}/initrd.gz"
cp "${SEED}" "${TMP}/initrd"
find . | cpio -H newc --create --quiet | gzip -9 > "${TMP}/files/install/netboot/ubuntu-installer/${ARCH}/initrd.gz"
rm -r "${TMP}/initrd"
# Recreate the md5sum.txt file
echo "Calculating MD5 checksums for the image"
cd "${TMP}/files"
md5sum -b $(find -type f) > md5sum.txt
OPTS=""
[ -f "${TMP}/files/boot/grub/efi.img" ] && OPTS="-eltorito-alt-boot -e boot/grub/efi.img -no-emul-boot"
# Build the ISO image
echo "Building the new ISO image"
cd "${CURDIR}"
mkisofs -r -V "UBUNTUSEED" \
-cache-inodes \
-J -l -b isolinux/isolinux.bin \
-c isolinux/boot.cat -no-emul-boot \
-boot-load-size 4 -boot-info-table \
${OPTS} \
-input-charset utf-8 -quiet \
-o "${DST}" "${TMP}/files"
# Clean up the mess
cleanup
#!/bin/bash
## FORSTWOOF UBUNTU PRESEED :: INSTALLATION SCRIPT
# Will do everything in temporary files
cd /var/tmp
# Set global locale
echo LC_ALL=\"en_US.UTF-8\" >> /etc/default/locale
# Point apt proxy to local cacher
cat <<EOF >/etc/apt/apt.conf.d/01proxy
Acquire::http::Proxy "http://beaver:3142";
EOF
# Enable automatic updates of all packages
rm /etc/apt/apt.conf.d/20auto-upgrades
cat <<EOF >/etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
"\${distro_id}:\${distro_codename}-security";
"\${distro_id}:\${distro_codename}-updates";
"\${distro_id}:\${distro_codename}-proposed";
"\${distro_id}:\${distro_codename}-backports";
};
Unattended-Upgrade::Package-Blacklist {
};
Unattended-Upgrade::Remove-Unused-Dependencies "true";
EOF
cat <<EOF >/etc/apt/apt.conf.d/10periodic
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
EOF
# Install all updates
apt-get -y update && \
apt-get -y dist-upgrade
apt-get -y autoremove
apt-get -y autoclean
apt-get -y purge $(dpkg --get-selections | grep deinstall | awk '{print $1}')
# Add ForstWoof certificate authority
curl -Lso /usr/local/share/ca-certificates/ForstWoof.crt https://forstwoof.ru/ca/root.crt
update-ca-certificates
mkdir -p /etc/ssl/forstwoof
for name in root server client proxy
do
for ext in crl crt
do
[[ "${name}" = "root" ]] && [[ "${ext}" = "crt" ]] && ln -s /usr/local/share/ca-certificates/ForstWoof.crt /etc/ssl/forstwoof/root.crt && continue
curl -Ls https://forstwoof.ru/ca/${name}.${ext} -o /etc/ssl/forstwoof/${name}.${ext}
done
done
cat <<EOF >/etc/cron.weekly/forstwoof-crl
#!/bin/sh
for name in root server client
do
wget https://forstwoof.ru/ca/${name}.crl -O /etc/ssl/forstwoof/${name}.crl
done
EOF
chmod +x /etc/cron.weekly/forstwoof-crl
# ZSH GRML configuration
curl -Lso /etc/zsh/zshrc http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
curl -Lso /etc/skel/.zshrc http://git.grml.org/f/grml-etc-core/etc/skel/.zshrc
cp /etc/skel/.zshrc /root/.zshrc
chsh -s /usr/bin/zsh
# OpenSSH server configuration
rm /etc/ssh/ssh_host_*
declare -A keytypes=(\
["ed25519"]="256" \
["ecdsa"]="521" \
["rsa"]="4096")
for type in ${!keytypes[@]}
do
KEYPATH="/etc/ssh/ssh_host_${type}_key"
ssh-keygen -q -t ${type} -b ${keytypes["$type"]} -C "" -N "" -f ${KEYPATH}
done
cat <<EOF >/etc/ssh/sshd_config
Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_rsa_key
SyslogFacility AUTH
LogLevel INFO
LoginGraceTime 60
AllowUsers root
PermitRootLogin yes
UsePAM yes
PermitEmptyPasswords no
UsePrivilegeSeparation yes
StrictModes yes
IgnoreRhosts yes
PubkeyAuthentication yes
HostbasedAuthentication no
ChallengeResponseAuthentication no
PasswordAuthentication no
X11Forwarding no
PrintMotd no
PrintLastLog yes
TCPKeepAlive no
MaxStartups 4
Compression yes
ClientAliveCountMax 5
ClientAliveInterval 30
IPQoS cs4 8
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
EOF
mkdir -p /root/.ssh
cat <<EOFEOFEOFEOF >/root/.ssh/authorized_keys
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAF1LO9QOys7ybGjoo40mZZfLUnztBcSBKk3m1lRGyxK6k5Hnb5HW/QpUT3uCdsaKJ9NrYmLlZjwkykxDSv4YqKReQFjNwfhPNo2DG3ah0AiCrvpmsvzh4FM6exiE1WQCMlQ40wJDhXnihbVYTKx7D2BJE4GopBWZ1X9QzhkUlHfkq3S+w== Shark
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBADTeo8BOL7Th3mdYqpxDwVbMt6OFHPtXocQddkFzG8bKZITSLZfGvmzzQAg9wWi7n8LPRYARgGZnlUMN2M1fmckOwCMwD1NyyIfK2jqzpD21VFsIabSbWXXwhSz+IPIVhemyXKOPNF9Tpkxqhava5xKNBQwEiHesCuiXvROc1F7UMzrtA== Cougar
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAEy7loXboS2HxhP2c8nLsf68qsdpD7aCuD+Wly+CtHw+zBS9uSxZiYWfp5k210lS4bDkV5JO2VDlKcANLWY9M265wEeX4DD39WsjAyBfpEZajqRStselXrRNYlhtH7GDpx9RZJvHFtOzROXvZrpposbaeybjt5ZyMmPq+7Q6n9L6L6IbA== Dingo
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKc56H2wFTSZxJHNgd66R4Ld6jEYLq4J9D4ZoqJQylYgTPJ4ITkeafp5msdcF1za8DZwThPr964c4LfNwVT/bQQHhzFr/Yxg2c4PDKyUSM0iV7wMixUCArxTaOoyOKA6YiH6Rn1M8mQVM4rqt0GqcAbeVqKdaqsWbDtxbcc8KpxwHNs6r5xxWp/jI1Y/enY5Vtt0La5DVfIfWmGzEfLxGJtZI7izfdToLsNDxBCpZa/xi9bshvBULFToIbrP4WsVrtac05H08n0pHV6eFwBlEJPzJsenx7sHOxhCipAN7sKe6qJrDyJL22PfQgYhOMQ4AlBvKDg6McD54Zep+p0VUB5U0+z7HylTEhswg6IORfslSiwEfrJen7DdDO2xEJlk6XFl0Dby2T6njppXhRu2Ra1HSuYGKbkYk+356oRHi+x9hIG0YNoAgLQjgKNQo+kFnywHNGuw6krUmN3qjctnNBe921a42UY3NenhmzN6UdkqXYJEpMyKSvh1XI2I5RPzQoIHAm4pl3YG70CP7Wg3XB+t3o5TeVvuT1PeLG8eUsVryQSs1C3UH2pPF2raI3URKwLmXr2XZukeLz6kPrXg0ky4yUDpY/emesKFaNtquUC0daMXttBtfED7t9a/rL/Zy/8HkrivajG9yrEgNy16pW2aHaF4P87aoE3aM94GKQOQ== Penguin
EOFEOFEOFEOF
# Sysctl configuration
cat <<EOF >/etc/sysctl.conf
net.core.default_qdisc = fq_codel
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.force_igmp_version = 2
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.secure_redirects = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_ecn = 1
net.ipv4.tcp_rfc1337 = 1
net.ipv4.tcp_syncookies = 1
net.ipv6.conf.all.accept_source_route = 0
vm.swappiness = 0
EOF
# Template network configuration
cat <<EOF >>/etc/network/interfaces
#iface ens192 inet static
# address 192.168.1.X
# netmask 24
# gateway 192.168.1.1
# dns-nameservers 192.168.1.5 2002:d58d:9aaa:1::5
# dns-search lan.forstwoof.ru
# mtu 9000
#iface ens192 inet6 static
# address 2002:d58d:9aaa:1::X
# netmask 64
# gateway 2002:d58d:9aaa:1::1
EOF
# Enable log compression
sed -i 's/#compress/compress/' /etc/logrotate.conf
# Tweak initramfs generation
sed -i 's/COMPRESS=gzip/COMPRESS=xz/' /etc/initramfs-tools/initramfs.conf
sed -i 's/MODULES=most/MODULES=dep/' /etc/initramfs-tools/initramfs.conf
update-initramfs -u -k all
# Enable kexec reboots
sed -i 's/LOAD_KEXEC=false/LOAD_KEXEC=true/' /etc/default/kexec
# open-vm-tools logging tweak
cat <<EOF >/etc/vmware-tools/tools.conf
[logging]
vmsvc.level=error
EOF
# Remote syslog server
cat <<EOF >/etc/rsyslog.d/10-remote.conf
*.notice @beaver:514
## FORSTWOOF UBUNTU PRESEED :: DEBIAN PRESEED FILE
# Localization
d-i debian-installer/language string en_US:en
d-i debian-installer/country string RU
d-i debian-installer/locale select en_US.UTF-8
d-i localechooser/preferred-locale en_US.UTF-8
# Keyboard
d-i console-setup/ask_detect boolean false
d-i keyboard-configuration/layoutcode string ru
d-i keyboard-configuration/toggle select Alt+Shift
# Networking
d-i netcfg/choose_interface select auto
d-i netcfg/get_domain string lan.forstwoof.ru
# Mirror
d-i mirror/protocol select http
d-i mirror/country string manual
d-i mirror/http/hostname string mirror.yandex.ru
d-i mirror/http/directory string /ubuntu
d-i mirror/http/proxy string
# Clock and time
d-i clock-setup/utc boolean true
d-i time/zone string Europe/Moscow
d-i clock-setup/ntp boolean true
d-i clock-setup/ntp-server string kangaroo
# Partitioning
d-i partman-auto/disk string /dev/sda
d-i partman-auto/method string regular
d-i partman-auto/expert_recipe string \
custom-ext4 :: \
50 50 50 free \
$iflabel{ gpt } \
$reusemethod{ } \
method{ efi } \
format{ } \
. \
256 256 256 linux-swap \
method{ swap } \
format{ } \
. \
2000 10000 -1 ext4 \
method{ format } \
format{ } \
use_filesystem{ } \
filesystem{ ext4 } \
mountpoint{ / } \
label{ System } \
options/noatime{ noatime } \
.
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
# Base system installation
d-i base-installer/initramfs-tools/driver-policy select most
d-i live-installer/mode select normal
d-i base-installer/kernel/image string linux-image-generic
# Account setup
d-i passwd/shadow boolean true
d-i passwd/root-login boolean true
d-i passwd/make-user boolean false
# Package management
d-i apt-setup/restricted boolean true
d-i apt-setup/universe boolean true
d-i apt-setup/multiverse boolean true
d-i apt-setup/backports boolean true
d-i apt-setup/use_mirror boolean true
d-i apt-setup/services-select-ubuntu multiselect security, partner
d-i apt-setup/security_host string mirror.yandex.ru
d-i apt-setup/security_path string /ubuntu
# Packages
tasksel tasksel/first multiselect server, openssh-server
d-i pkgsel/include string kexec-tools open-vm-tools rng-tools zsh nano
d-i pkgsel/upgrade select full-upgrade
d-i pkgsel/update-policy select unattended-upgrades
popularity-contest popularity-contest/participate boolean true
# Boot loader
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean false
d-i debian-installer/add-kernel-opts string text console=tty0 console=ttyS0,115200n8
# kexec should handle reboots
kexec-tools kexec-tools/load_kexec boolean true
# Finishing up the installation
d-i finish-install/reboot_in_progress note
# Post-install script to do all the remaining work
d-i preseed/late_command string \
wget http://beaver/ubuntu/install.sh -O /target/var/tmp/install.sh && \
chmod +x /target/var/tmp/install.sh && \
in-target /bin/bash /var/tmp/install.sh && \
rm /target/var/tmp/install.sh
#!/bin/sh
## FORSTWOOF UBUNTU PRESEED :: UPDATE SCRIPT
apt-get -y update && \
apt-get -y dist-upgrade
apt-get -y autoremove
apt-get -y autoclean
apt-get -y purge $(dpkg --get-selections | grep deinstall | awk '{print $1}')