Hello, recently I tried installing Fedora 42 on a virtual machine without the installer, mostly to see if it was possible, and also to see if it would be possible to run Fedora on a bcachefs root partition (which the Fedora installer, Anaconda, does not allow, for a very good reason). I decided to write the procedure down and publish it here in case anyone else needs it.
Notice that this procedure is rather advanced and not recommended. If you do this, don’t expect support from the community or from the people who make Fedora.
First, you’ll need to boot the Fedora live ISO and open a terminal, then create the partitions however you’d like. I decided to go with systemd-boot because configuring grub is rather complex. I also decided to not use a separate /boot
partition for simplicity.
Let’s say your newly created root partition is on /dev/sda1 and the EFI partition on /dev/sda2. To install systemd-boot, run these commands from a root shell on the live OS:
mkdir -p /new_system/esp
mount /dev/sda2 /new_system/esp
mkdir -p /new_system/esp/sd-boot/
dnf install systemd-boot-unsigned
cp /usr/lib/systemd/boot/efi/systemd-bootx64.efi /new_system/esp/sd-boot/
efibootmgr -c -d /dev/sda -p 2 -l "\sd-boot\systemd-bootx64.efi" -L "fedora sd-boot"
This will install systemd-boot. Now, let’s install the system itself:
mkdir -p /new_system/root
mount /dev/sda1 /new_system/root
rsync \
-pogAXtlHrDx \
--stats \
--info=flist2,name,progress2 \
--no-inc-recursive \
--exclude /dev/ \
--exclude /proc/
--exclude '/tmp/*' \
--exclude /sys/ \
--exclude /run/ \
--exclude '/boot/*rescue*' \
--exclude /boot/loader/ \
--exclude /boot/efi/ \
--exclude /etc/machine-id \
--exclude /etc/machine-info \
/run/rootfsbase/ \
/new_system/root
Those arguments to rsync are taken from the installer’s source code.
Now that we have the files on our root partition, we still need to do a bit of configuration:
- Give our install a machine-id
- Give our install a hostname
- Installing the kernel
- Configuring the bootloader
- Setting up fstab
- Adding a user to log in
Before we can do all that, it would be good to enter “inside” our root partition:
umount /new_system/esp
mount /dev/sda2 /new_system/root/boot/efi
cd /new_system/root
systemd-nspawn
All other configuration commands will be run inside the systemd-nspawn container.
To setup the machine-id:
head -c 16 /dev/urandom | od -A n -t x1 | sed 's/ //g' > /etc/machine-id
To setup a hostname:
echo $HOSTNAME > /etc/hostname
Replacing $HOSTNAME with your preferred hostname.
Installing the kernel with systemd-boot is a bit harder because you have to tell kernel-install to not use /boot. I opted to not use UKIs in this case. Edit /etc/kernel/install.conf (creating it if it does not exist) and add:
layout=bls
BOOT_ROOT=/boot/efi
Now we need to find out the UUID of the root and efi partitions. Outside the systemd-nspawn container, run on the live OS shell lsblk -o UUID,MOUNTPOINTS,NAME
. The root partition is mounted at /new_system/root and the efi partition at /new_system/root/boot/efi if you’ve followed the steps so far.
Then write to /etc/kernel/cmdline
inside the systemd-nspawn container:
root=UUID=$ROOT_PART_UUID ro
Replacing $ROOT_PART_UUID with the root partition UUID. If you’d like to make any changes to the kernel parameters or the dracut config, the time is now. If you want to change the kernel parameters, edit the /etc/kernel/cmdline
file.
Then after making any modifications you’d like to the dracut configuration and kernel cmdline, run:
rm -rf /boot/loader
kernel-install add -v
If it all went well, the folder /boot/efi/loader/entries
should contain a file. I decided to also configure systemd-boot to always show its menu:
echo "timeout 5" > /boot/efi/loader/loader.conf
Now setting up fstab. Adding this to /etc/fstab
should work well:
UUID=$ROOT_PART_UUID / $ROOT_PART_TYPE x-systemd.device-timeout=0 0 0
UUID=$EFI_PART_UUID /boot/efi vfat umask=0077,shortname=winnt 0 2
Replacing $ROOT_PART_UUID with the root partition UUID, $EFI_PART_UUID with the efi partition UUID, and $ROOT_PART_TYPE with the root partition type (say ext4, btrfs ou bcachefs).
Then we’ll need to setup a user. Inside the systemd-nspawn container, run:
useradd -U -G wheel fedora-user
passwd fedora-user
Replacing fedora-user
with your username. The last command will prompt you to create a password for your account.
Now restart and use your new Fedora system, installed by yourself!
Why do this?
Well, I did this mostly to try to learn how the system works, and to see if it was possible to install Fedora on a bcachefs root partition. The simple answer is that it works only if you add “enforcing=0” to the kernel command line and remove the “-X” in the rsync arguments, because bcachefs does not support SELinux. You’ll also need to add the “bcachefs” kernel driver to the initrd by adjusting the dracut config.
Installing Fedora this way also allows you to more easily pick your preferred bootloader, it can be systemd-boot or even something lesser known such as rEFInd.
It is also worth noting that the web UI installer supports installing to custom mountpoints. Simply mount whatever filesystems you want and they’ll show up on the installer under a “Use custom mount point” options. Note however that it will refuse to install onto unsupported filesystems.
Also, many of the adjusts that are possible by doing this are also possible by running the installer normally, then opening a shell, mounting the new system and making whatever tweaks you’d like. You can also try writing a custom Kickstart file for the Fedora installer.
This will only work on the non-immutable Fedora distros (i.e. not Atomic Desktops).
I was partially inspired to do this because of similar guides for Windows, whose installer enforces many rather arbitrary requirements and for me at least, has a tendency to quite simply not detect your disks. However, I’d like to note that the Fedora installer has always worked rather well for me, correctly detecting my disks and supporting many advanced configurations while also being simple to use. I’d highly recommend Fedora over any hacky way to install Windows.