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 |
---|---|
System | Distribution independent |
Software | No specific software needed |
Other | None |
Conventions | # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command $ – requires given linux-commands to be executed as a regular non-privileged user |
Introduction
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 --mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
With the 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 $releasever
and $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 --url
option.
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
The 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 --install
option.
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:
- rootpw
- user
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:
rootpw --lock
Next, we added a non-privileged user to the system, via the
user
command, using the --groups
, --name
, --password
, --iscrypted
and --gecos
options:
user --groups=wheel --name=tux --password=$6$fz9G6LVJIRHXk39j$IKgBBqkj9RQBWz8MylDWwViuREVTCIBwuxLEAeY0A6yniK2FIWBZDr9lH5YbUBidmBtqKR5CLA0h9AigOucCT/ --iscrypted --gecos="tux"
The --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 sudo
.
The --password
and --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 /etc/passwd
file:
tux:x:1000:1000:tux:/home/tux:/bin/bash
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
, keyboard
and timezone
.
The lang
directive sets both the language to use during the installation, and the system language. It takes the language id as argument:
lang en_US.UTF-8
The keyboard
directive is used to set the system keyboard layout. You can see we used two options: --vckeymap
and --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
With the --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 ignoredisk
command:
ignoredisk --only-use=/dev/vda
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
--drives
option, or as we did in the example, do the inverse, and pass the list of the accessible disks as argument to the --only-use
option.
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
:
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).
The --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
:
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.
The --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.
The --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).
The --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
With the 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.
Bootloader installation
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 --location
and --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 /dev/vda
drive.
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 %end
tag:
%packages @workstation-product-environment -gnome-boxes %end
In this example, you can see we explicitly included the
@workstation-product-environment
package group (a group is identified by a @
in front of the name), and we excluded the gnome-boxes
package 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: %pre
and %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 test.ks
):

Conclusions
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 %pre
and %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.