Kickstart is an automatic installation method natively available on those distributions which uses the Anaconda installer: Red Hat Enterprise Linux (and its clones) and Fedora. It can also be used to install Ubuntu, actually, but in that context it acts as a layer of compatibility to the debian-native preseeding method. With Kickstart we can perform unattended, customizable and reproducible installations.
In this tutorial we learn the basics of Kickstart, and we see how to perform an unattended installation of a Fedora Workstation system.
In this tutorial you will learn:
- How to perform unattended installations using Kickstart
- How to write a Kickstart file
- How to pass a Kickstart file to the Anaconda installer
|Category||Requirements, Conventions or Software Version Used|
|Software||No specific software needed|
|Conventions||# – requires given linux-commands to be executed with root privileges either directly as a root user or by use of
When we perform a Kickstart installation, instead of interactively answering to the system installer questions about the various aspects of the installation process, we pass a series of command/instructions in the so called Kickstart file. In it, we define what partitions layout we want to use, what locale and timezone to use for the new system, what packages should be installed, etc.
The best way to learn how to write a Kickstart file is to start from a real-world example, and analyze the various sections and commands used in it. For the sake of this tutorial we will take a look at a Kickstart file which can be used to install a Fedora Workstation system. Here it is in its entirety:
url --mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch repo --name=rpmfusion-free --mirrorlist=https://mirrors.rpmfusion.org/metalink?repo=free-fedora-$releasever&arch=$basearch rootpw --lock user --groups=wheel --name=tux --password=$6$fz9G6LVJIRHXk39j$IKgBBqkj9RQBWz8MylDWwViuREVTCIBwuxLEAeY0A6yniK2FIWBZDr9lH5YbUBidmBtqKR5CLA0h9AigOucCT/ --iscrypted --gecos="tux" lang en_US.UTF-8 keyboard --vckeymap=us --xlayouts=us timezone Europe/Rome --utc network --hostname=linuxconfig --device=eth0 --bootproto=dhcp --noipv6 --activate --onboot=yes xconfig --startxonboot ignoredisk --only-use=/dev/vda clearpart --all --initlabel --drives=vda part /boot/efi --fstype=efi --ondisk=/dev/vda --size=550 --fsoptions="umask=0077,shortname=winnt" part /boot --fstype=ext2 --ondisk=/dev/vda --size=1024 part pv.0 --fstype=lvmpv --ondisk=/dev/vda --grow volgroup linuxconfig_vg pv.0 logvol / --fstype=ext4 --vgname=linuxconfig_vg --name=root_lv --size=15360 logvol /home --fstype=ext4 --vgname=linuxconfig_vg --name=home_lv --percent=95 bootloader --location=mbr --boot-drive=/dev/vda %packages @workstation-product-environment -gnome-boxes %end
Setting the installation source
In the kickstart file above, as a first thing, we defined the installation source. The installation source can be either “local” (a cdrom, for example) or remote, (an installation tree), accessed via one of the supported protocols, such as ftp or http. The latter is exactly what we used in the example:
url command we specified we want to use a remote installation source. We passed the URL of the file containing the list of the available mirrors as argument to the
--mirrorlist option. The
$basearch variables in the URL are expanded respectively to the Fedora version (e.g. 37) and the system architecture. As an alternative, we could use a specific mirror directly, by passing its URL as argument to the
Using additional repositories during the installation
The second line in the kickstart file we used in the example is the following:
repo --name=rpmfusion-free --mirrorlist=https://mirrors.rpmfusion.org/metalink?repo=free-fedora-$releasever&arch=$basearch
repo command is optional: it is used to specify additional repositories to be used during the installation. In the example we added the RPMFusion repository as a software source; it contains packages which, for a reason or another, are not available in the official Fedora repositories, such as VLC, for example. We used the mandatory
--name option to specify the repository ID and,
--mirrorlist to specify the URL of the file containing a list of the repository mirrors.
A repository defined as we did in the example would only be available during the installation: to enable it also on the installed system we need to add the
Another interesting option we may want to use when specifying an additional repository is
--cost. The option takes an integer as a value, and is used to define the installation priority. This is useful when a package is available from more than one software source: a lower cost means an higher priority.
Managing system users
In the example above we used two commands to manage users in the newly installed system:
The first command.
rootpw is mandatory: it is used to setup the password of the root user. In this case, we passed the
--lock option to the command, which, as you can imagine, is used to lock the password, in order to disable direct root login:
Next, we added a non-privileged user to the system, via the
usercommand, using the
user --groups=wheel --name=tux --password=$6$fz9G6LVJIRHXk39j$IKgBBqkj9RQBWz8MylDWwViuREVTCIBwuxLEAeY0A6yniK2FIWBZDr9lH5YbUBidmBtqKR5CLA0h9AigOucCT/ --iscrypted --gecos="tux"
--name option is used to specify the account username and is required. The
--groups option, instead, accepts a comma-separated list of the groups the user should be member of. In this case we made the user part of the
wheel group, in order to make it able to escalate privileges using
--iscrypted options are related. The former is used to provide the user password, the latter to specify it should be assumed to be already encrypted (the opposite of this option is
--plaintext). Using an already encrypted password is useful in case we need to somehow share the Kickstart file or putting it under version control. There are various methods we can encrypt a password and obtain the string to place in the file. One option is to use the
pwkickstart utility; it takes a password as argument and returns its md5, sha256 and sha512 encrypted versions (the latter is the one we want):
$ pwkickstart mypassword $1$shCWoE7t$eY546wqr/rrsaUugnvBbs0 $5$pmMb0I1fhyddIHJV$y9lmRW02wpSTxNzAoEh4qljlPBD1jCXulLDgTyvq1v9 $6$77bw2sxFQAU3Ejtw$DBj5IKCU3pw3sAH.XdGCalwqdIH/Nss7NVMnc6a9CbJyevo8BVPU3DFquqQvSzloQVjgfo0Z0YUSDDaZ.z.Tl1
The last option we used is
--gecos: it is needed to provide additional user information such as his/her real name. Those information are stored in the fifth field of each line in the
Locale, keyboard and timezone settings
Another, very important part of the system configuration/installation is the localization. In the example we used three directives to setup the system language, the keyboard layout and the system timezone; they are respectively:
lang directive sets both the language to use during the installation, and the system language. It takes the language id as argument:
keyboard directive is used to set the system keyboard layout. You can see we used two options:
--xlayouts, passing “us” as argument to both:
keyboard –vckeymap=us –xlayouts=us
The former is used to set the console keymap, the latter to set the keyboard layout for the graphical server. Finally, with the
timezone directive we set the system timezone:
timezone Europe/Rome --utc
--utc option we specified that the system clock is set to UTC.
Disk partitioning and bootloader installation
Disk partitioning is probably the most crucial aspect of a system installation. Using the Kickstart file in the example results in the creation of two standard partitions (the EFI partition, and a dedicated “boot” partition), and the installation of the rest of the system on a LVM (Logical Volume Manager) layout. As a first thing, we used the
This command is used as a safety measure, to specify what disks the anaconda installer has access to. We can implement two strategies here: either pass the comma-separated list of excluded drives as argument to the
--drivesoption, or as we did in the example, do the inverse, and pass the list of the accessible disks as argument to the
What we did in the example, was basically allowing the installer to access only the
/dev/vda disk. In this case we identified the disk with the name assigned to the kernel, since it is the only one available. On a real-world scenario, it is preferable to use unique identifiers such as UUID or PATH, instead, since they are predictable (the kernel assigns device names in detection order).
Wiping existing partitions
The next command we used is
clearpart --all --initlabel --drives=vda
This command is used to wipe all existing partitions from the specified disk(s), before the new ones are created. With the
--all options we specified we want to wipe all existing partitions (by using
--linux, instead, we would have instructed the installer to remove only “linux” partitions).
--initlabel option is used to initialize the disk with a MBR or GPT partition label, depending on the architecture and the way we booted the installer (UEFI or BIOS). Finally,
--drives is used to specify on what drives the partitions should be cleared.
Creating partitions and the LVM setup
As a next step, we defined the actual partitions and logical volumes. Since we want to install the system in UEFI mode, with a GPT partition schema, we need to create an EFI partition. The command used to create a standard partition is
part /boot/efi --fstype=efi --ondisk=/dev/vda --size=550 --fsoptions="umask=0077,shortname=winnt"
The first argument passed to the command is the mountpoint of the partition that will be created. It can either be an actual filesystem path, or some “special” value like “swap” (used for swap partitions), or
pv.<id>for LVM physical volumes.
--fstype option is used to specify the filesystem that should be created on the partition. In this case “efi” is not the filesystem type per-se, but tells the system we want to create an EFI partition.
--ondisk option is used to specify on which disk the partition should be created. Here we used
/dev/vda (to re-use an existing partition
--onpart is used, instead).
--size option is used to specify the minimum partition size in MiB. Finally,
--fsoptions takes a comma separated list of mount options which is copied into the /etc/fstab file.
The second partition we created is the boot partition:
part /boot --fstype=ext2 --ondisk=/dev/vda --size=1024
The use of a separate boot partition and the ext2 filesystem on it is really not necessary, since GRUB supports both LVM and ext4, it’s just the force of habit. Next, we defined the partition to be used as LVM physical volume. Here you can notice we used
lvmpv as filesystem type, and the
--grow option: with it we specify that the partition should take all the available space:
part pv.0 --fstype=lvmpv --ondisk=/dev/vda --grow
volgroup command we created an LVM volume group. This directive takes the volume group name as first argument, and the physical volumes to be added to it as the second:
volgroup linuxconfig_vg pv.0
After the volume group, we created the logical volumes with the
logvol command. This commands works similarly to
part, but accepts some additional options, as for example
--vgname which is needed to specify the volume group the logical volume belongs to, and
--percent which can be used to specify the size of the logical volume as a percentage of the available space.
Finally, we used the
bootloader command, which is needed to configure how and where the bootloader is installed:
bootloader --location=mbr --boot-drive=/dev/vda
Here we used the
--boot-drive options to specify that the bootloader should be installed in the mbr (actually in the EFI partition on UEFI installed systems), of the
Specifying the package list
By using Kickstart, we can specify, in detail, the packages which should be installed in the new system, and those which should be excluded. We list packages inside the
%packages section, one per line. The section must be closed with the
%packages @workstation-product-environment -gnome-boxes %end
In this example, you can see we explicitly included the
@workstation-product-environmentpackage group (a group is identified by a
@in front of the name), and we excluded the
gnome-boxespackage by placing the
-sign before its name.
The %pre and %post sections
Let’s talk about two sections we didn’t use in our example:
%post: these sections inside a Kickstart file can be very useful, since in them we can perform custom actions using one of the available scripting language on the system (Bash is the default). Both sections must be closed with an
%end tag, but are executed in different stages of the installation. The
%pre section is executed before the installation begins, just after the Kickstart file has been parsed; the
%post section, instead, is executed after the installation is complete. The commands we execute in it, run in the installed system, in chroot.
Passing the Kickstart file to the installer
Once our Kickstart file is ready, we must tell the installer where to find it. We do this via the
inst.ks boot option. We can, for example, make the Kickstart file available online, than point the installer to it as we did below (we saved the file as
In this tutorial we learned the Kickstart basics. We saw how to use the appropriate commands to set the installation source, add extra repositories, set the system locale and define a partition layout. We also saw how to specify what packages should be installed and talked about the
%post sections which can be used to script custom actions, performed before the installation starts, and after it is completed, respectively. Finally, we saw an example of how to pass the Kickstart file to the Anaconda installer. For the complete list of Kickstart commands please take a look at the official documentation.