Pull to refresh

Introducing into calamares bootloader

Reading time13 min


Sometimes all of us need to make a graphical installer for one's own linux distro. It goes without saying that you are able to use a distro-specific installer like Anaconda for RedHat-based or DebianInstaller for debian-based. On the other hand Calamares is a graphical installer which is not aligned with only one package manager.

I want to share my experience how to make a universal install solution with GUI. I did not find any complete article about it, hence, I reinvented the wheel.

In this article I will show the following things:

  • how-to build Calamares from the source
  • how-to install Calamares in the system (be careful, it should be a live system)
  • how-to install arch-based distro
  • how to make branding of your installer

I will use stripped configs with only required options.

Building from the source

There are 2 parts of calamares:

  • calamares (main program to install any linux) — mandatory
  • calamares-extension (pack of files for branding) — optional

Calamares is a cmake-project based on QT. Therefore, general build and install are simple:

# create dir for this work
rm -rf calamares
mkdir -p calamares
cd calamares
# download sources from github
wget https://github.com/calamares/calamares/releases/download/v3.2.49.1/calamares-
# untar it
tar xvpf calamares-
cd calamares-
mkdir build
cd build

Looks like instructions can be used to build calamares-extension, thus I skip them.

But I prefer to create pacman package to store an already built package and use it whenever I want. I wrote PKGBUILD file for calamares and calamares-extensions.

Calamares PKGBUILD for arch

# Maintainer: Alexey Soname "boozlachu" 

pkgdesc='Universal linux distro graphical installer'
depends=('binutils' 'fakeroot' 'gcc' 'boost' 'patch' 'qt5-tools' 'yaml-cpp' 'ack' 'kpmcore' 'qt5-location' 'icu' 'qt5-declarative' 'qt5-translations' 'qt5-xmlpatterns' 'kiconthemes' 'kservice' 'kio' 'kparts' 'cmake' 'autoconf' 'automake' 'bison' 'flex' 'git' 'libtool' 'm4' 'make' 'extra-cmake-modules' 'appstream-qt' 'squashfs-tools' 'fish' 'libpwquality' 'python3' 'python-qt.py' 'python-qtpy' 'qt5-webengine' 'python-pip')

prepare() {
  cd $pkgname-$pkgver
  # apply patch from the source array (should be a pacman feature)
  local filename
  for filename in "${source[@]}"; do
    if [[ "$filename" =~ \.patch$ ]]; then
      echo "Applying patch ${filename##*/}"
      patch -p1 -N -i "$srcdir/${filename##*/}"
#   :
  PIP_CONFIG_FILE=/dev/null pip install --isolated --root="$pkgdir" --ignore-installed --no-deps pylint

build() {
    cd $pkgname-$pkgver
    mkdir build
    cd build

package() {
cd $pkgname-$pkgver/build
  make DESTDIR="$pkgdir/" install

Calamares-extensions PKGBUILD for arch

# Maintainer: Alexey Soname "boozlachu" 

pkgdesc='Calamares Branding and Module Examples'
depends=('binutils' 'fakeroot' 'gcc' 'boost' 'patch' 'qt5-tools' 'yaml-cpp' 'ack' 'kpmcore' 'qt5-location' 'icu' 'qt5-declarative' 'qt5-translations' 'qt5-xmlpatterns' 'kiconthemes' 'kservice' 'kio' 'kparts' 'cmake' 'autoconf' 'automake' 'bison' 'flex' 'git' 'libtool' 'm4' 'make' 'extra-cmake-modules' 'appstream-qt' 'squashfs-tools' 'fish' 'libpwquality' 'python3' 'python-qt.py' 'python-qtpy' 'qt5-webengine' 'python-pip')

prepare() {
  cd $pkgname-$pkgver
  # apply patch from the source array (should be a pacman feature)
  local filename
  for filename in "${source[@]}"; do
    if [[ "$filename" =~ \.patch$ ]]; then
      echo "Applying patch ${filename##*/}"
      patch -p1 -N -i "$srcdir/${filename##*/}"
  PIP_CONFIG_FILE=/dev/null pip install --isolated --root="$pkgdir" --ignore-installed --no-deps pylint

build() {
    cd $pkgname-$pkgver
    mkdir build
    cd build

package() {
  cd $pkgname-$pkgver/build
  make DESTDIR="$pkgdir/" install

And now you are able to build both packages via makepkg:

alexey@comp:~/test/calamares$ makepkg --syncdeps

You must run this command in the directory with PKGBUILD file and from a non-privileged user. Definitely it's a simplified example, you need to view more in the arch linux manual (see the links in the end).


There are 2 general ways to install calamares:

  • using included scripts+
  • using package

Via pacman package (Arch linux)

Ok, to install both packages (built in the previous step) you can use packman:

pacman -U ./calamares- --noconfirm
pacman -U ./calamares-extensions-1.2.1-1-x86_64.pkg.tar.zst --overwrite '*' --noconfirm

Argument "--overwrite '*'" is needed because both packages have+ default branding files.

Via included script

I have not used this way but you can read more here


There are 3 general parts of Calamares configuring:

  • settings.conf, major config
  • module-specific configs
  • branding (optional)

Ok, now we have built calamares, installed in our live system. Consequently, we must write configs for it.

First config for using is /etc/calamares/settings.conf. This file stores major settings and a list of used modules in a proper order.

There are dozens of available modules. Besides, everyone is free to write own modules. Every module performs some jobs. Good practice is to put configs for them into /etc/calamares/modules/:

alexey@comp:~$ tree /etc/calamares/modules/
├── bootloader.conf
├── displaymanager.conf
├── finished.conf
├── fstab.conf
├── initcpio.conf
├── initramfs.conf
├── locale.conf
├── machineid.conf
├── mhwdcfg.conf
├── mount.conf
├── packages.conf
├── partition.conf
├── postcfg.conf
├── services-systemd.conf
├── shellprocess.conf
├── unpackfs.conf
├── users.conf
└── welcome.conf

General settings

Now I will write a general config file /etc/calamares/settings.conf. First of all, I will add required modules. There are 2 parts of their sequence (and also 2 types of modules, some of them hybrid):

  • show — these modules show something to user, they are used for interaction with a user
  • exec — these modules do some jobs as soon as the install config is ready.

My /etc/calamares/settings.conf is:

modules-search: [ local ]
- show:
  - welcome
  - locale
  - keyboard
  - partition
  - users
  - summary
- exec:
  - partition
  - mount
  - unpackfs
  - packages
  - machineid
  - fstab
  - locale
  - keyboard
  - localecfg
  - initcpiocfg
  - initcpio
  - users
  - displaymanager
  - networkcfg
  - hwclock
  - services-systemd
  - bootloader
  - umount
- show:
  - finished
branding: boozelinux
prompt-install: false
dont-chroot: false
oem-setup: false
disable-cancel: false
disable-cancel-during-exec: false
hide-back-and-next-during-exec: false
quit-at-end: false

I will use basic config which will do simple things (SHOW part):

  • show a welcome screen (module welcome)
  • ask user about locale and timezone (module locale)
  • ask user what keyboard layout will be used (module keyboard)
  • set disk partitioning (module partition )
  • set users (module users)
  • show summary install settings (module summary)

And then calamares will install my linux (EXEC part), I will elaborate on this part later. Short descriptions are:

  • partition the disk
  • mount disk in future mode (like they will mount in future boot of your system), including /proc /sys /run /dev and others
  • unpack files from squashfs to disk
  • install packages inside future system
  • create machine-id and other random data inside future system
  • create fstab
  • set locale
  • set keyboard preferences
  • create initcpio config and run mkinitcpio
  • setup users
  • configure display managers
  • setup network
  • set hardware clock
  • setup systemd-services
  • configure and install bootloader
  • umount all in future filesystem

And last part is setting of some variables (more information in calamares git):

branding: boozelinux — use branding files from "boozelinux" directory

prompt-install: false — don’t ask user "Are you sure?" before each exec module

Don’t-chroot: false — don't use chroot to execute all target environment commands

oem-setup: false — don't use preconfigured install (I want to interact with a user)

disable-cancel: false — show DISABLE button

disable-cancel-during-exec: false — show DISABLE button after start of installation process

hide-back-and-next-during-exec: false — show BACK button after start of
installation process

quit-at-end: false — show finished-screen (with results of installation)

Complete instructions for ALL modules can be found here. To read the manual for each module please open *.conf file in even module dir. For example, open
'https://github.com/calamares/calamares/blob/calamares/src/modules/mount/mount.conf' to read module 'mount' config.

Branding (optional)

First of all, I will setup branding. You can skip this part but you will need to make some amendments in your settings.txt. Full guide is provided here: here: Calamares branding guide

Your directory with branding must be placed in /usr/share/calamares/branding, I will use /usr/share/calamares/branding/boozelinux. All next files will be placed inside this dir.

├── boozelinux1.png
├── boozelinux2.png
├── boozelinux3.png
├── boozelinux4.png
├── boozelinux5.png
├── Boozlachu.png
├── branding.desc
├── ImageSlide.qml
└── show.qml

0 directories, 9 files


This file stores settings of you calamares theme:

# show be equal to name of branding directory
componentName:  boozelinux
# There are different style of welcome screen, use simple default
welcomeStyleCalamares:   false
# I want to scale logo
welcomeExpandingLogo:   true
# type if window, I dont want to use fullscreen
windowExpanding:    normal
# Position of window
windowPlacement: center

# Type of panel left (which is showing progress)
sidebar: widget
# Placement of navigation panel
navigation: widget
# This string is used to write windows labels,headers and different texts.
    productName:         Boozelinux
    shortProductName:    Boozelinux
    version:             2021.12
    shortVersion:        2021.12
    versionedName:       Boozlechu GNU/Linux 2021.12 LTS "Smiling dragon"
    shortVersionedName:  BoozleLinux 2021.12
    bootloaderEntryName: Boozelinux
    productUrl:          https://github.com/skif-web/
    # link on button "support"
    supportUrl:          https://github.com/skif-web//wiki
    # link on button "suppKnown issues"
    knownIssuesUrl:      https://github.com/skif-web//issues
    # link on button "Release notes"
    releaseNotesUrl:     https://github.com/skif-web//news/

    # logo in windows header
    productIcon:         "Boozlachu.png"
    # logo in sidebar
    productLogo:         "Boozlachu.png"

# Colors used in window
   sidebarBackground:    "#292F34"
   sidebarText:          "#FFFFFF"
   sidebarTextSelect:    "#292F34"
   sidebarTextHighlight: "#D35400"

# Slideshow is showed during install process. I use external file to make it
slideshow:               "show.qml"

# Version of calamares API, I use modern version
slideshowAPI: 2


import QtQuick 2.0  // Basic QML
import calamares.slideshow 1.0  // Calamares slideshow: Presentation
import io.calamares.ui 1.0  // Calamares internals: Branding

    id: presentation

    Timer {
        // Interval between pictures
        interval: 3000
        running: presentation.activatedInCalamares
        repeat: true
        onTriggered: presentation.goToNextSlide()

    function onActivate() { }
    function onLeave() { }

    Rectangle {
        id: mybackground
        anchors.fill: parent
        color: Branding.styleString(Branding.SidebarBackground)
        z: -1

    // list of slides
    ImageSlide {
        src: "boozelinux1.png"

    ImageSlide {
        src: "boozelinux2.png"

    ImageSlide {
        src: "boozelinux3.png"

    ImageSlide {
        src: "boozelinux4.png"

    ImageSlide {
        src: "boozelinux5.png"

I did it from the examples, compiling different files. The cherry-picking part is:

  • interval: 3000 — change slides every 3 sec
  • ImageSlide — every new slide is described in its own parts


This file defines the setting for pictures inside slideshow, called from previous file. I changed only 2 options: width and height:

import QtQuick 2.5

Item {
    id: imageslide

    visible: false
    anchors.fill: parent

    property bool isSlide: true;
    property string notes;

    property string src;

    Image {
        id: image
        source: src
        width: 600
        height: 300
        anchors.centerIn: parent


All pictures are in png format:

  • Boozlachu.png — a logo in slidebar and in a windows header
  • boozelinux{1-5}.png — pictures for slideshow

Some screenshots

Modules’ descriptions and configs

Eventually we have 2 of 3 parts of configuring: mandatory config and branding. Now we must write modules-specific configs.

These custom configs must be placed inside /etc/calamares/modules/ directory.

├── bootloader.conf
├── displaymanager.conf
├── finished.conf
├── fstab.conf
├── initcpio.conf
├── initramfs.conf
├── locale.conf
├── machineid.conf
├── mhwdcfg.conf
├── mount.conf
├── packages.conf
├── partition.conf
├── postcfg.conf
├── services-systemd.conf
├── shellprocess.conf
├── unpackfs.conf
├── users.conf
└── welcome.conf

0 directories, 18 files

I will describe modules config in call-order.


These modules are used to interact with a user.

Module welcome

This module shows welcome-screen, information will be read from the branding file.

# show or not buttons "support/issues/etc"
# links stored in branding.desc
showSupportUrl:         true
showKnownIssuesUrl:     true
showReleaseNotesUrl:    true

# check hardware requirements
    requiredStorage:    7.9
    requiredRam:        1.0
    internetCheckUrl:   https://manjaro.org
      - storage
      - ram
      - power
      - internet
      - root
#   if broken, installer show error screen and prevent install
      - storage
      - ram
      - root
#  Try to set language if internet available
    style:  "json"
    url:    "https://ipapi.co/json"
    selector: "country"

module locale

This module helps to select a timezone, a system language and locale settings like numbers/date formats.

localeGenPath: /etc/locale.gen
    style:  "json"
    url:    "https://ipapi.co/json"
    selector: "timezone"

module keyboard

This module setups a keyboard. I have not written config for it, default settings are ok.

module partition

This module allows to change disk partitioning. You are able to set some default settings for it.

efiSystemPartition:     "/boot/efi"
    - none      # Create no swap, use no swap
    - small     # Up to 4GB
    - suspend   # At least main memory size
    - file      # To swap file instead of partition
alwaysShowPartitionLabels: true
# There are four options: erase, replace, alongside, manual),
# the default is "none".
initialPartitioningChoice: erase
initialSwapChoice: none
defaultFileSystemType:  "ext4"
availableFileSystemTypes:  ["ext4","btrfs","f2fs","xfs"]

module users

This module is used to setup users in future system.

    - lp
    - network
    - power
    - sys
    - wheel
autologinGroup:  autologin
doAutologin:     false
sudoersGroup:    wheel
setRootPassword: true
doReusePassword: false
availableShells: /bin/bash, /bin/zsh
avatarFilePath:  ~/.face
userShell:       /bin/bash

module summary

This module shows settings of future install after all choices are made. I have not written custom config for it, default is ok.

module finished

This module is used to show install results.

# show "reboot" check
restartNowEnabled: true
# dont's check it by default
restartNowChecked: false
# command for reboot
restartNowCommand: "systemctl reboot"


These modules never interact with a user. They are workers that install your system. You will see slideshow during their work.

module partition

This module provides partitioning: creates partition table and partitions, formats them, etc.

module mount

# Mount needed inside future filesystem, it's preparation to chroot. 
# Filesystem listed in future fstab will be mounted automatically.

    - device: proc
      fs: proc
      mountPoint: /proc
    - device: sys
      fs: sysfs
      mountPoint: /sys
    - device: /dev
      mountPoint: /dev
      options: bind
    - device: tmpfs
      fs: tmpfs
      mountPoint: /run
    - device: /run/udev
      mountPoint: /run/udev
      options: bind

# only if it's UEFI system
    - device: efivarfs
      fs: efivarfs
      mountPoint: /sys/firmware/efi/efivars

module unpackfs

This module unpacks initial filesystem from squashfs. You can use multiple files.

# select package manager
backend: pacman
# allow to install without Internet
skip_if_no_internet: false
# update package database like "pacman -Sy" inside target system
update_db: true
# update packages inside target system
update_system: true
# number of retries if failure happen.
    num_retries: 0
# --disable-download-timeout for pacman
    disable_download_timeout: false
# pacman --needed argument
    needed_only: true
# packages for install
- install:
    - xfce4
    - vim
    - grub
    - wget
    - nano
    - bash

module machineid

This module setups any required random data.

# /etc/machine-i
systemd: true
# /var/lib/dbus/machine-id
dbus: true
# Whether /var/lib/dbus/machine-id should be a symlink to /etc/machine-id
dbus-symlink: true

module fstab

This module creates fstab in the target system.

# default mountpoints settings
    default: defaults,noatime
    btrfs: defaults
    btrfs_swap: defaults

# for uefi part
efiMountOptions: umask=0077

# if SSD detected
    btrfs: discard=async,ssd
# for crypttab (if LUKS used)
crypttabOptions: luks

module localecfg

This module configures locales. Default config is ok.

module initcpiocfg

This module creates mkinitcpio.conf inside the target system.

module initcpio

This module runs mkinitcpio command.

# name of kernel preset
kernel: linux

module displaymanager

This module setups display managers. I prefer to use lightdm.

  - lightdm

basicSetup: true

module networkcfg

This module setups network configuration

module hwclock

This module sets hardware clock.

module services-systemd

This module can enable/disable services/timers and targets. Besides you are able to set default target.

    - name: avahi-daemon
      mandatory: false

    - name: bluetooth
      mandatory: false

    - name: cronie
      mandatory: false

    - name: ModemManager
      mandatory: false

    - name: NetworkManager
      mandatory: true

    - name: cups
      mandatory: true

    - name: tlp
      mandatory: false

    - name: haveged
      mandatory: false

    - name: ufw
      mandatory: false

    - name: apparmor
      mandatory: false

    - name: snapd.apparmor
      mandatory: false

    - name: snapd
      mandatory: false

    - name: fstrim.timer
      mandatory: false

    - name: pkgfile-update.timer
      mandatory: false

    - name: lightdm
      mandatory: true

    - name: "graphical"
      mandatory: true

    - name: pacman-init
      mandatory: false

module bootloader

This module setups bootloader. Different loaders are in support. I like to use grub.

efiBootLoader: "grub"
kernel: "/vmlinuz-5.13-x86_64"
img: "/initramfs-5.13-x86_64.img"
fallback: "/initramfs-5.13-x86_64-fallback.img"
timeout: "10"
kernelLine: ", with linux513"
fallbackKernelLine: ", with linux513 (fallback initramfs)"
grubInstall: "grub-install"
grubMkconfig: "grub-mkconfig"
grubCfg: "/boot/grub/grub.cfg"
grubProbe: "grub-probe"
efiBootMgr: "efibootmgr"
installEFIFallback: true

module umount

This module umounts everything inside target filesystem.

shellprocess (not used but interesting)

I never use this module, but probably someone will. It provides shell commands run inside the target system.


Currently I am sure that Calamares may be used to install different linux distros including your own made. Some things look crazy but everything comes to be unclouded and consistent if you are eager to read documentation and out-if-box config.

1) Calamares main page
1) Arch creating packages
1) Calamares quick deployment script
1) Calamares settings.txt example and guide
1) Full describes of calamares modules
1) Calamares branding guide
1) Calamares module descriptions