I once struggled through a Linux From Scratch installation, many years ago when I first became seriously interested in Linux. I spent days, even weeks, trying to get everything compiled and working. I don’t remember if I ever fully succeeded, although I certainly learnt a lot — even if most of what I learnt was pointless arcana that is mostly obsolete now.
Eventually I decided it should be possible to automate all these repetitive steps for building packages, which led me to Gentoo. For several years I was a happy user of Gentoo, then later Exherbo. Neither Gentoo nor Exherbo have an installer, leaving the user to create filesystems and bootstrap the installation themselves by hand. So I’ve had plenty of practice at installing Linux distros the hard way.
These days the appeal of tweaking every package’s build options and compiling my own kernel has dwindled, and I run Fedora instead. Anaconda, the Fedora installer, is far from perfect; but given the outrageous number of possible configurations and edge cases it is expected to deal with, it does a remarkable job. And in recent releases it has been improving too, with a new UI and more flexible storage configuration.
Nevertheless, when I got my new work laptop I decided to try installing Fedora without using Anaconda, as an experiment. Let’s call it “Fedora From Scratch”.
Start by booting a Fedora live CD or live DVD of your choice. I used a Fedora
20 Beta XFCE Live DVD, dd
’ed to a USB flash drive. With EFI you can just plug
it in and pick it from the boot menu. You could also boot Anaconda over the
network and drop to a shell using Ctrl+Alt+F2. Anything that has filesystem
utilities and yum
should work.
The first step is to partition your disks and create filesystems.
In the past I have built towering monstrosities of LVM upon LUKS upon mdraid upon GPT. There is a setup like that running in my workstation, with four hard disks and one SSD, all of varying sizes, speeds, and ages. But this is just a little laptop with a single solid-state disk, so I opted for a relatively simple configuration. The partition table is GPT (necessary for EFI booting). I created a 512MB “EFI System Partition”, and in the rest of the space I created a LUKS volume with an XFS volume on top.
If you’re following along, this is where you set up whatever crazy disk configuration your heart desires. You’re limited only by your imagination! …and by what Dracut knows how to handle.
Once everything is set up, mount it all in a directory which will become your
installed system. Here I used /mnt/local
.
gdisk /dev/sda
cryptsetup luksFormat /dev/sda2
cryptsetup luksOpen /dev/sda2 luks-1b5a6440-34ff-4469-b625-45d9ad9dc6ae
mkfs.xfs -L dill-fedora /dev/mapper/luks-1b5a6440-34ff-4469-b625-45d9ad9dc6ae
mkfs.vfat -n EFI /dev/sda1
mkdir /mnt/local
mount LABEL=dill-fedora /mnt/local
mkdir /mnt/local/boot
mount LABEL=EFI /mnt/local/boot
One important gotcha, which I discovered the hard way: when you open the LUKS
volume now, you must use the same name you will use later in the installed
system. The reason is that Dracut uses the currently mapped name for the LUKS
volume when it generates the initrams. Here I used luks-$UUID
which is the
convention used by Anaconda.
Next, use yum
to populate your new filesystem. dnf
works too.
yum --releasever=20 --installroot=/mnt/local groupinstall core
Now you can enter the chroot to finish configuring things.
cp /etc/resolv.conf /mnt/local/etc/
mount -t sysfs none /mnt/local/sys
mount -t proc none /mnt/local/proc
mount -t efivarfs none /mnt/local/sys/firmware/efi/efivars
mount -o bind /dev /mnt/local/dev
chroot /mnt/local /bin/bash
The following steps are all done from the chroot’ed shell. Configure your filesystems, hostname, and root password.
cat >/etc/crypttab <<EOF
luks-1b5a6440-34ff-4469-b625-45d9ad9dc6ae UUID=1b5a6440-34ff-4469-b625-45d9ad9dc6ae
EOF
cat >/etc/fstab <<EOF
LABEL=EFI /boot auto defaults 0 2
LABEL=dill-fedora / auto defaults,noatime,nodiratime 0 1
EOF
echo dill.djc.id.au >/etc/hostname
passwd
With EFI firmware, a “boot loader” in the traditional sense is not needed. You could boot your kernel directly if you wanted. Gummiboot is a “boot manager”, which means you can boot it and it will show a menu allowing you to pick a kernel or other operating system. I highly recommend it because it’s very simple and just works.
yum install efibootmgr gummiboot
gummiboot install
Lastly, install a kernel and any other packages necessary for your storage
configuration. Here I am installing cryptsetup
for the LUKS volume and
xfsprogs
for the XFS volume.
It’s important that these packages are installed before the kernel (or in the
same RPM transaction). The kernel package has a %posttrans
scriptlet which
uses Dracut to build an initramfs image, and if Dracut cannot find the programs
it needs for mounting and checking your filesystems (in this case, cryptsetup
and fsck.xfs
) then they will be silently skipped from the initramfs,
leaving you with an unbootable system.
yum install kernel cryptsetup xfsprogs
After the kernel has been installed, you will find a boot loader configuration
has been written to /boot/loader/entries
(according to the new systemd boot
loader spec).
The file will be named after the automatically generated machine ID for your
new installation.
vi /boot/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.11.10-301.fc20.x86_64.conf
The kernel options in this file are copied from the currently running kernel,
so there will be some irrelevant options from the live DVD such as
BOOT_IMAGE=
. Delete all that, and add the two options you need to boot your
newly installed system: ro
and root=
. If you like Plymouth, you can also
add quiet rhgb
to get a boot animation. If you have trouble getting the
system to boot, you can add rd.debug rd.shell
instead to debug problems in
the initramfs.
options ro root=LABEL=dill-fedora
I also noticed that some SELinux labels are not set correctly in the installed system. I’m not sure of the reason for this, maybe the SELinux policy doesn’t take effect while chroot’ed? So you will need to trigger a relabel on reboot.
touch /.autorelabel
Now you’re ready to reboot. If all goes well you should have a working minimal Fedora installation, occuping less than 700MB of disk space, and a getty login prompt. Log in, set up the clock, and start installing your favourite packages.
yum install chrony
timedatectl set-timezone Australia/Brisbane
yum install vim bash-completion ...
Overall I was surprised at how easy this was. Yum does all the hard work with
its --installroot
option. Almost everything just worked. By far the most
painful part was getting Dracut to generate a working initramfs. The problem is
exacerbated by how difficult and time-consuming it can be to debug problems in
early boot. The two most important gotchas I found with Dracut are described
above: it’s sensitive to the state of the system at the time the initramfs is
generated, and if some programs are missing it silently omits functionality
from the initramfs image.
Going through this process by hand made me realise that Anaconda is not much more than a complicated storage configuration utility, plus a rudimentary yum frontend. In future I will probably do all my Fedora installations this way, since I find it easier to just set up the filesystems by hand than to tell Anaconda how I want it done.