Create Debian 12 (Bookworm) KVM Guest From Cloud Image
Table of Contents
About
This tutorial will show you how to install Debian 12 on your KVM server through the use of one of the official Debian cloud images.
Similar Posts
- Debian 12 Cloud Init Docker Server
- Create Ubuntu 22.04 KVM Guest From Cloud
- Create Debian 11 (Bullseye) KVM Guest From Cloud Image
Steps
Download The Cloud Image
Download the Debian 12 cloud Image:
wget https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2
sudo mv -i debian-12-generic-amd64.qcow2 \
debian-12.qcow2
genericcloud
image, but found that I could not get it to run
cloud-init (which I needed in order to configure my user/password), so I ended up using the
generic
image which is the same except it includes some hardware drivers as noted
here.
Install Packages
We need to ensure we have cloud-utils and whois packages for later.
sudo apt update && sudo apt install cloud-utils whois -y
cloud-utils
package is required for us to be able to run the cloud-localds
command, which allows us to create the cloud init ISO image later. It also allows us to validate
our cloud-init configuration. The whois
allows us to be able to run mkpasswd
command later
if we want to use it to generate the hashed version of our password for the cloud-init
configuration. This was the command for Debian 10. Your distro may have a different name for the
required packages.
Pick A Name
First, pick a name for your new VPS. I always create a "template" guest, from which I then just clone it in future to create the other guests, so I am going to call it template-debian-12.
VM_NAME="template-debian-12"
Optional - Increase Disk Size
The qcow2 image we pulled down was for a very small virtual machine that will quickly run out of space if you start using it for anything. I would recommend increasing the disk size to whatever you want for the VM. In this case I'm setting 20 GB.
DESIRED_SIZE=20G
sudo qemu-img resize \
debian-12.qcow2 \
$DESIRED_SIZE
Create Cloud Config File
I found lots of people had cloud-config files and it was frustrating trying to mix/match them and issues with hashing my password. I also didn't like having to be careful with making sure not to break the required YAML formatting/indentation etc. In the end I created a PHP script that I could easily tweak in order to generate my cloud-config.cfg file using some simple settings I defined at the top.
Download the script (which can also be found in the appendix).
wget https://files.programster.org/tutorials/cloud-init/create-debian-12-kvm-guest-from-cloud-image/generate.php
Fill in the settings at the top of the script as appropriate. E.g. the section outlined below:
<?php
# Fill in these settings as appropriate to you.
# Set the hostname for the guest.
$hostname = "template-debian-12";
# Specify your username and password
$username = "debian";
$password = "debian";
# Set a random salt string here for password hashing
$randomSaltString = 'setARandomStringHere';
# Specify the public keys of the private-keys you wish to login with.
$sshPublicKeys = [
'ssh-rsa AAAAB3Nz...',
];
##### End of settings. Do not edit below this line #######
##########################################################
Then run the script to generate your cloud-init.cfg
file:
php generate.php
autoinstall
. This appears to be related to automated
installation, and may be ubuntu-specific. Either way, cloud-init just ignores that key, and we
don't need it at all anyway.
debian
user that I do not need or wish to have.
cloud-init schema --config-file cloud-init.cfg
the validate your generated cloud init config file.
Create The Cloud Init ISO File
Create the ISO file from the cloud config file we just created:
sudo cloud-localds \
cloud-init.iso \
cloud-init.cfg
Create The Guest
Now you can finally run the command to create the guest:
sudo virt-install \
--name $VM_NAME \
--memory 1024 \
--disk /path/to/debian-12.qcow2,device=disk,bus=virtio \
--disk /path/to/cloud-init.iso,device=cdrom \
--os-variant debian10 \
--virt-type kvm \
--graphics none \
--network network=default,model=virtio \
--import
debian10
because my Debian 10 KVM does not have debian12
in the list outputted from running sudo osinfo-query os
(which I could only run after installing the libosinfo-bin
package).
Login
After running the previous command, you will be taken to the login screen in the console, which
you can log in with the username root
. You will not be prompted for a password.
Now you really need to manually create your account username, and set a strong random password for the root user.
Exit Console
If you need to get out of the console just press ctrl
+ ]
.
Cleanup
After that, it's probably a good idea to cleanup so raw passwords aren't lying around.
sudo rm /var/lib/libvirt/images/$VM_NAME/cloud-init.iso \
&& sudo rm /var/lib/libvirt/images/$VM_NAME/cloud-init.cfg
Debugging / Tips
Changing Network Settings
One of the first things I wanted to do is change the network settings to remove the restriction to a certain static MAC address, which prevents networking working on cloned guests, as they get a new, different MAC address.. This can be done by editing the netplan file at:
/etc/netplan/50-cloud-init.yaml
Clones Getting Same DHCP IP
Debian 12 has switched to using the machine ID concept for identifying itself to your DHCP server. This means that if you create a clone and don't reset the machine ID, then both guests will identify the same, and be provided the same IP address by the DHCP server. To resolve this, reset your machine ID when you create a clone:
sudo truncate -s 0 /etc/machine-id
Then reboot. Your server will generate a new replacement machine ID on the next boot.
Hostname And Hosts File
It appears that setting the hostname in the cloud-init config will set the hostname that the
machine will boot as. However, it will may not add the entry to the /etc/hosts
file, so you may
wish to do this quickly to prevent your machine taking unnecessarily long when performing some
operations. Alternatively, you may figure out how to update the cloud-init.cfg file to update
the hosts file correctly using the
Etc hosts module.
SSH Not Working
If you find that openssh isn't working, you may need to run the following command to get your server to generate its host key so that you can SSH into the server. More info here.
sudo dpkg-reconfigure openssh-server
I would also suggest checking that you are happy with your /etc/ssh/sshd_config
file's settings.
Set Timezone
Another thing that you may wish to do is set the timezone:
sudo dpkg-reconfigure tzdata
References
- The Urban Penguin - Using Cloud Images in KVM
- Serverfault - How to change default user (ubuntu) via CloudInit on AWS
- Gitlab - Add "generic", "genericcloud", and "nocloud" debian 10 images
- zhimin-wen.medium.com - Provision a VM with Cloud Image and Cloud-init
- Proxmox Forum - cloud-init unable to run on Debian 11 cloud image
Appendix
Cloud Config Generator PHP Script
Below is a copy of the PHP script I use to create the cloud-init config file, just in case it disappears from the hosted location etc.
<?php
# Fill in these settings as appropriate to you.
# Set the hostname for the guest.
$hostname = "template-debian-12";
# Specify your username and password
$username = "debian";
$password = "debian";
# Set a random salt string here for password hashing
$randomSaltString = 'setARandomStringHere';
# Specify the public keys of the private-keys you wish to login with.
$sshPublicKeys = [
'ssh-rsa AAAAB3Nz...',
];
##### End of settings. Do not edit below this line #######
##########################################################
# Need to hash passwords this way
$hashedPassword = crypt($password, '$6$rounds=4096$' . $randomSaltString . '$');
# Cloud-init users and groups documentation: https://bit.ly/3XFhEM0
$mainUser = [
'name' => $username,
# This will set the password even if the user already exists. If you don't want to allow overwriting an
# existing user password, use 'passwd' instead
'hashed_passwd' => $hashedPassword,
# Allow the user to run sudo commands without a password.
'sudo' => 'ALL=(ALL) NOPASSWD:ALL',
# Add the user to groups if you wish
#'groups' => [],
'shell' => "/bin/bash",
# Specify the lock password, which specifies whether the user can log in to the terminal with a password
# (not to be confused with ssh_pwauth, which is for SSH connections).
# Debian 12 likes the older lock-passwd instead of lock_passwd it appears.
'lock-passwd' => false, # old versions are lock-passwd, new versions are lock_passwd
'ssh_authorized_keys' => $sshPublicKeys,
];
$users = [
$mainUser
];
$config = [
'hostname' => $hostname,
# Set this to true if you wish for cloud-init to set the /etc/hosts file on every boot.
# THis would set the new hostname.
# https://cloudinit.readthedocs.io/en/latest/reference/modules.html#update-etc-hosts
'manage_etc_hosts' => false,
# Allow password authentication for SSH.
'ssh_pwauth' => false,
# disable root login
'disable_root' => true,
'users' => $users,
];
$content = '#cloud-config' . PHP_EOL;
// create the yaml content, removing the optional YAML start/end dividers that nobody appears to use.
$yamlContent = yaml_emit($config);
$lines = explode(PHP_EOL, $yamlContent);
unset($lines[0]);
unset($lines[count($lines)-1]);
$content = $content . implode(PHP_EOL, $lines);
file_put_contents('cloud-init.cfg', $content);
First published: 24th June 2023