├── postinst
└── collectd.conf
├── postinst.sh
├── install.sh
├── README.md
└── preseed.cfg
/postinst/collectd.conf:
--------------------------------------------------------------------------------
1 | LoadPlugin "cpu"
2 | LoadPlugin "memory"
3 | LoadPlugin "interface"
4 | LoadPlugin "disk"
5 | LoadPlugin "df"
6 |
7 | LoadPlugin "network"
8 |
9 |
10 | SecurityLevel "Encrypt"
11 | Username: "foo"
12 | Password: "bar"
13 |
14 |
15 |
--------------------------------------------------------------------------------
/postinst.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # This script is run by debian installer using preseed/late_command
4 | # directive, see preseed.cfg
5 |
6 | # Setup console, remove timeout on boot.
7 | sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="console=ttyS0"/g; s/TIMEOUT=5/TIMEOUT=0/g' /etc/default/grub
8 | update-grub
9 |
10 | # Members of `sudo` group are not asked for password.
11 | sed -i 's/%sudo\tALL=(ALL:ALL) ALL/%sudo\tALL=(ALL:ALL) NOPASSWD:ALL/g' /etc/sudoers
12 |
13 | # Empty message of the day.
14 | echo -n > /etc/motd
15 |
16 | # Unpack postinst tarball.
17 | tar -x -v -z -C/tmp -f /tmp/postinst.tar.gz
18 |
19 | # Install SSH key for pin.
20 | mkdir -m700 /home/pin/.ssh
21 | cat /tmp/postinst/authorized_keys > /home/pin/.ssh/authorized_keys
22 | chown -R pin:pin /home/pin/.ssh
23 |
24 | # Install collectd and config.
25 | #apt-get install -y collectd-core
26 | #cp /tmp/postinst/collectd.conf /etc/collectd/
27 |
28 | # Remove some non-essential packages.
29 | DEBIAN_FRONTEND=noninteractive apt-get purge -y nano laptop-detect tasksel dictionaries-common emacsen-common iamerican ibritish ienglish-common ispell wamerican intel-microcode iucode-tool discover discover-data libdiscover2 libusb-1.0-0
30 |
31 | # Set domain name in hosts file
32 | #sed -i 's/127.0.1.1\t\([a-z]*\).*/127.0.1.1\t\1\.dp\-net\.com\t\1/' /etc/hosts
33 |
34 | # Avoid using DHCP-server provided domain name.
35 | #sed -i 's/#supersede.*/supersede domain-name "dp-net.com";/' /etc/dhcp/dhclient.conf
36 |
37 | # Do not install recommended packages by default.
38 | cat > /etc/apt/apt.conf.d/01norecommend << EOF
39 | APT::Install-Recommends "0";
40 | APT::Install-Suggests "0";
41 | EOF
42 |
43 | # Make "reboot" command work.
44 | apt-get install -y python3 dbus
45 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | # Create debian VM as a KVM guest using virt-install in fully
4 | # automated way based on preseed.cfg
5 |
6 | # Domain is necessary to avoid debian installer to
7 | # require manual domain entry during the install.
8 | DOMAIN=`/bin/hostname -d` # Use domain of the host system
9 | #DOMAIN="dp-net.com" # Alternatively, hardcode domain
10 | # NB: See postinst.sh for ability to override domain received from
11 | # DHCP during the install.
12 |
13 | GITHUB_USERNAME='your-github-username'
14 |
15 | DIST_URL="http://ftp.debian.org/debian/dists/bookworm/main/installer-amd64/"
16 | LINUX_VARIANT="debiantesting"
17 | # NB: Also see preseed.cfg for debian mirror hostname.
18 |
19 | if [ $# -lt 1 ]
20 | then
21 | cat < [MAC_ADDRESS]"
23 |
24 | GUEST_NAME used as guest hostname, name of the VM and image file name
25 | MAC_ADDRESS allows to use specific MAC on the network, this is helpful
26 | when DHCP server expects your guest to have predefined MAC
27 |
28 | Examples:
29 |
30 | $0 backend 52:54:00:bf:b3:86 # create guest named "backend" with given MAC
31 |
32 | $0 wow # create guest named "wow" with random MAC
33 | EOF
34 | exit 1
35 | fi
36 |
37 | MAC="RANDOM"
38 | if [ $# -eq 2 ]
39 | then
40 | MAC=$2
41 | fi
42 |
43 | # Fetch SSH key from github.
44 | wget -q https://github.com/${GITHUB_USERNAME}.keys -O postinst/authorized_keys
45 |
46 | # Create tarball with some stuff we would like to install into the system.
47 | tar cvfz postinst.tar.gz postinst
48 |
49 | virt-install \
50 | --connect=qemu:///system \
51 | --name=${1} \
52 | --ram=1024 \
53 | --vcpus=2 \
54 | --disk size=16,path=/var/lib/libvirt/images/${1}.img,bus=virtio,cache=none \
55 | --initrd-inject=preseed.cfg \
56 | --initrd-inject=postinst.sh \
57 | --initrd-inject=postinst.tar.gz \
58 | --location ${DIST_URL} \
59 | --os-variant ${LINUX_VARIANT} \
60 | --virt-type=kvm \
61 | --controller usb,model=none \
62 | --graphics none \
63 | --noautoconsole \
64 | --network bridge=br0,mac=${MAC},model=virtio \
65 | --extra-args="auto=true hostname="${1}" domain="${DOMAIN}" console=tty0 console=ttyS0,115200n8 serial"
66 |
67 | rm postinst.tar.gz
68 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Debian Bookworm unattended VM guest installer
2 |
3 | Simple script that uses **virt-install** and configures Debian installer
4 | for unattended installation and custom configuration using **preseed**
5 | config in order to create freshly installed Debian KVM guest.
6 |
7 | ```
8 | Usage: ./install.sh [MAC_ADDRESS]
9 |
10 | GUEST_NAME used as guest hostname, name of the VM and image file name
11 | MAC_ADDRESS allows to use specific MAC on the network, this is helpful
12 | when DHCP server expects your guest to have predefined MAC
13 | ```
14 |
15 | Guest OS is minimal no-GUI Debian installation configured with serial console
16 | for ability to `virsh console `, and OpenSSH server with your SSH
17 | key or/and password pre-configured.
18 |
19 | It is easy to change the script to add any extra packages and
20 | configuration files during unattended installation. The main point of
21 | sharing this script is to provide an example of unattended Debian VM
22 | creation or a base for your own script.
23 |
24 | Prerequisites
25 | -------------
26 | ```
27 | apt-get install wget virtinst libvirt-daemon-system qemu-system-x86 qemu-utils
28 | ```
29 |
30 | Things to check before the first use
31 | ------------------------------------
32 | * Set your login name and full name in `preseed.cfg`, update your GitHub name
33 | in `install.sh` in order to install your SSH key for authentication by guest.
34 | If you want to use different SSH key, not the one from GitHub, just put
35 | `authorized_keys` to `preseed` directory and remove `wget` command that
36 | fetches key from GitHub.
37 | Update your login name in `postinst.sh`, where SSH key is installed.
38 | * It's worth considering to enable password authentication in `preseed.cfg`
39 | at least during first run so you could `virsh console ` in case
40 | network connection in guest does not come up with DHCP or IP of the guest
41 | is unclear.
42 | * Check RAM size and disk size for the guest in arguments to `virst-install` in
43 | `install.sh` and modify them as needed.
44 | * Add `apt-get install -y ` or whatever you want to `postinst.sh`
45 | and any configuration files you want to add to the guest into `postinst`
46 | directory.
47 |
48 | Network configuration
49 | ---------------------
50 | Script works with bridged network, guests use DHCP and show up in local network.
51 | In case you want something else, replace `br0` in arguments to virt-install
52 | in `install.sh`.
53 |
54 | Before setting bridged network up:
55 | ```
56 | apt-get install brigde-utils
57 | ```
58 |
59 | Example of network configuration in `/etc/network/interfaces`:
60 | ```
61 | auto lo
62 | iface lo inet loopback
63 |
64 | auto br0
65 | iface br0 inet dhcp
66 | bridge_hw eth0
67 | bridge_ports eth0
68 | bridge_stp off
69 | bridge_fd 1
70 | bridge_maxage 12
71 | ```
72 |
73 | More Info
74 | ---------
75 | * https://www.debian.org/releases/stable/example-preseed.txt
76 |
--------------------------------------------------------------------------------
/preseed.cfg:
--------------------------------------------------------------------------------
1 | # Preconfiguration file for jessie.
2 | # For more details see https://www.debian.org/releases/jessie/example-preseed.txt
3 | d-i debian-installer/locale string en_US
4 | d-i keyboard-configuration/xkb-keymap select us
5 |
6 | # Choose an network interface that has link if possible.
7 | d-i netcfg/choose_interface select auto
8 |
9 | # Disable that annoying WEP key dialog.
10 | d-i netcfg/wireless_wep string
11 |
12 | # Mirror settings.
13 | d-i mirror/country string manual
14 | d-i mirror/http/hostname string ftp.nl.debian.org
15 | d-i mirror/http/directory string /debian
16 | d-i mirror/http/proxy string
17 |
18 | # Root account setup. You can set password in plain-text or pre-encrypted.
19 | d-i passwd/root-login boolean false
20 | #d-i passwd/root-password password 98e1c23d2a5a2
21 | #d-i passwd/root-password-again password 98e1c23d2a5a2
22 | #d-i passwd/root-password-crypted password $6$1LCVFshS/kbYVg$M1QS1ZJ3.E7NkAD8sqkqhqExA2HWQ5/iDE.l23Xbr89Z7hTg/jUuBMyrYzANLmRybYcH8Smcy.yGDKMAX3okd0 # Use `mkpasswd -m sha-512` to generate password hash.
23 |
24 | # User account setup.
25 | #d-i passwd/make-user boolean false
26 | d-i passwd/user-fullname string Dmitri Popov
27 | d-i passwd/username string pin
28 | #d-i passwd/user-password password 236e95cd3901553
29 | #d-i passwd/user-password-again password 236e95cd3901553
30 | #d-i passwd/user-password-crypted password $6$dU9we2Mm$Btq1Tk1WkFx3/8YsXWbZr13m56uv0PabJKxk5teKAImLLQhtniOURXuOVLmbiBl0O3iS6xQBctNIc9Dn5b3vR.
31 | # Password login is disabled.
32 | d-i passwd/user-password-crypted password !
33 |
34 | # Controls whether or not the hardware clock is set to UTC.
35 | d-i clock-setup/utc boolean true
36 | # See the contents of /usr/share/zoneinfo/ for valid values.
37 | d-i time/zone string Europe/Berlin
38 | # Controls whether to use NTP to set the clock during the install.
39 | d-i clock-setup/ntp boolean true
40 |
41 | # Simple non-LVM, all files in one partition.
42 | # For more examples see https://www.debian.org/releases/jessie/example-preseed.txt
43 | d-i partman-auto/method string regular
44 | d-i partman-auto/choose_recipe select atomic
45 | d-i partman-partitioning/confirm_write_new_label boolean true
46 | d-i partman/choose_partition select finish
47 | d-i partman/confirm boolean true
48 | d-i partman/confirm_nooverwrite boolean true
49 |
50 | # Do not install recommended packages by default.
51 | d-i base-installer/install-recommends boolean false
52 | tasksel tasksel/first multiselect
53 |
54 | # Individual additional packages to install.
55 | # ACPI packages are needed for `virsh shutdown ` to work.
56 | d-i pkgsel/include string openssh-server ca-certificates acpid acpi-support-base
57 | popularity-contest popularity-contest/participate boolean false
58 |
59 | # Bootloader installation.
60 | d-i grub-installer/bootdev string /dev/vda
61 |
62 | # Run postinst.sh in /target just before the install finishes.
63 | d-i preseed/late_command string cp postinst.sh postinst.tar.gz /target/tmp/ && chmod 755 /target/tmp/postinst.sh && in-target /tmp/postinst.sh
64 |
65 | # Avoid that last message about the install being complete.
66 | d-i finish-install/reboot_in_progress note
67 |
--------------------------------------------------------------------------------