Minimal Ubuntu Install
Overview
This document discusses the how and why of creating a minimal Ubuntu Linux 24.04 (Noble Numbat) installation (referred to as MSR Ubuntu).
The goals of this lightly-customized Ubuntu are:
- Remove Ubuntu-specific technologies to make the user experience more broadly applicable to other Linux distributions.
- Increase the user's control over, knowledge of, and responsibility for the system and how it works.
- Maintain compatibility with standard Ubuntu, which is the best-supported Linux distribution for ROS 2.
Disclaimer
This document attempts to relay knowledge gleaned from experimenting and reverse-engineering parts of Ubuntu and its install process, as there is not (to my knowledge) and up-to-date tutorial explaining the process in detail. Therefore, it may contain factual errors.
This document also contains my opinions (particularly about packages that I would or would not include) in a minimal distribution. While I make a good attempt to explain the reasoning for and against each decision, the choices made are ultimately based on my experience and personal preferences. Reasonable people may come to different conclusions.
Setup
- These instructions are adapted from Ubuntu LiveCD Customization
- All commands are assumed to be run in order from a working directory. It is recommended that this directory starts out empty.
Working Copy of LiveCD
Download the CD image.
- Rather than the latest released image we use the pending daily image to ensure that files downloaded via debootstrap are from the same update as the files on the CD image.
wget https://cdimage.ubuntu.com/noble/daily-live/pending/noble-desktop-amd64.iso wget https://cdimage.ubuntu.com/noble/daily-live/pending/SHA256SUMS wget https://cdimage.ubuntu.com/noble/daily-live/pending/SHA256SUMS.gpg
Verify the image: How To Verify Ubuntu
# Retrieve And Verify The Keys (only do this once) gpg --keyid-format long --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x46181433FBB75451 0xD94AA3F0EFE21092 gpg --keyid-format long --list-keys --with-fingerprint 0x46181433FBB75451 0xD94AA3F0EFE21092 # Ensure that the output shows the following: #pub dsa1024/46181433FBB75451 2004-12-30 [SC] # Key fingerprint = C598 6B4F 1257 FFA8 6632 CBA7 4618 1433 FBB7 5451 #uid Ubuntu CD Image Automatic Signing Key <cdimage@ubuntu.com> # #pub rsa4096/D94AA3F0EFE21092 2012-05-11 [SC] # Key fingerprint = 8439 38DF 228D 22F7 B374 2BC0 D94A A3F0 EFE2 1092 #uid Ubuntu CD Image Automatic Signing Key (2012) <cdimage@ubuntu.com> # Verify the iso gpg --keyid-format long --verify SHA256SUMS.gpg SHA256SUMS # You should see "gpg: Good Signature from "Ubuntu CD ..."
Mount the iso image to a loopback device:
# Setup loopback device, and store the device in loopdev variable export loopdev=$(sudo losetup --show -Pf noble-desktop-amd64.iso) # Mount the iso mount point and mount the iso mkdir isomnt sudo mount ${loopdev}p1 isomnt
Copy the image, so that we can modify it (we can't change it in-place because .iso filesystems are read-only) and remove unneeded files
cp -a isomnt extracted # Remove the files we don't need sudo rm extracted/casper/*.{de,en,es,fr,it,no-languages,pt,ru,zh}.* sudo rm extracted/casper/*secureboot* sudo rm extracted/casper/*filesystem*
To reconstruct the filesystem we need the boot code from the Master Boot Record and EFI partition.
- The MBR is the first sector (512 bytes) of the disk and the first 446 bytes of that constitute the boot code.
- The EFI partition is the second partition on the ISO file
# Copy the MBR dd bs=1 count=446 if=noble-desktop-amd64.iso of=mbr.img # Copy the EFI partition sudo cp ${loopdev}p2 EFI.img
Setup the image to install a custom disk image, rather than one of the provided images:
# Overrite the install-sources.yaml cat << EOF | sudo tee extracted/casper/install-sources.yaml - default: false description: en: Minimal Ubuntu for NUMSR. id: ubuntu-desktop-minimal locale_support: langpack name: en: Ubuntu (minimized) size: 0 path: msr.squashfs type: fsimage-layered variant: minimal EOF
The System Image
These instructions discuss how to create the msr.squashfs
filesystem that will be installed by subiquity (the Ubuntu Installer).
- The
msr.squashfs
system is extracted to the harddrive and provides most of the starting packages for the new system - To create this partition, we download packages from the internet. If these packages end up not being from the same exact release/update as the packages on the CD image, problems can ensue when doing an offline installation.
- Therefore, this step and the above step should be done at similar times.
- Another potential workaround is to actually bootstrap packages from the CD rather than the internet, however not all bootstrap packages are actually archived on the CD. Theoretically, you could create your own Ubuntu mirror on the CD that has all packages needed for the image and installation.
First we create the base filesystem. make sure you have debootstrap
installed=.
# Bootstrap the system sudo debootstrap --arch=amd64 --variant=minbase \ --include=\ adduser,\ apt,\ apt-utils,\ bash-completion,\ console-setup,\ debconf,\ debconf-i18n,\ e2fsprogs,\ efibootmgr,\ grub-efi-amd64,\ grub-efi-amd64-signed,\ init,\ initramfs-tools,\ iproute2,\ iputils-ping,\ kbd,\ kmod,\ language-selector-common,\ less,\ linux-image-generic,\ locales,\ lsb-release,\ mawk,\ mount,\ netbase,\ passwd,\ procps,\ python3,\ sensible-utils,\ shim-signed,\ systemd-resolved,\ sudo,\ tzdata,\ ubuntu-keyring,\ udev,\ vim-tiny,\ whiptail,\ rsyslog,\ zstd \ noble msr_image # Create a file that prioritizes the numsr-robotics repository # This means that packages here will supersede other packages even if they # are an older version of the package # We also prevent the installation of netplan.io to prevent it's accidental installation. # If our unpatched network-manager co-exists on a system with netplan.io, changes # made in network-manager won't be synced with netplan cat << EOF | sudo tee msr_image/etc/apt/preferences.d/numsr-apt-preferences Package: * Pin: release o=LP-PPA-numsr-robotics Pin-Priority: 1020 Package: apport cloud-init netplan.io ubuntu-pro-client unattended-upgrades whoopsie Pin: release * Pin-Priority: -1 EOF
Next, we prepare to enter the filesystem as chroot, allowing us to start using the files here as if they were in our root directory.
sudo mount none -t proc msr_image/proc/ sudo mount none -t sysfs msr_image/sys/ sudo mount none -t devpts msr_image/dev/pts sudo mount none -t tmpfs msr_image/tmp sudo mount none -t tmpfs msr_image/run # Make sure we can resolve hostnames in the chroot sudo mkdir -p msr_image/run/systemd/resolve sudo cp /etc/resolv.conf msr_image/run/systemd/resolve/stub-resolv.conf sudo chroot msr_image
The following commands take place inside the chroot
# Install some improtant packages apt update apt install --no-install-recommends -y software-properties-common # Add all ubuntu distribution components add-apt-repository -y universe add-apt-repository -y restricted add-apt-repository -y multiverse # Add the ppa. # Many websites online say that add-apt-repository should not be used anymore, but we've come # Full circle and now we should use add-apt-repository again! add-apt-repository ppa:numsr/robotics -y # Install the customized packages. # Due to the pin we setup in the previous step, packages that are shipped with ubuntu # will be overriden apt install --no-install-recommends -y \ network-manager \ wpasupplicant \ uncloud-init # Make a network manager connection profile for eduroam # The end user will have to modify this, but it will be # Easier if most of the settings are already theire nmcli --offline con add type wifi \ con-name eduroam \ autoconnect no \ ssid eduroam \ 802-1x.eap peap \ 802-1x.identity NETID@northwestern.edu \ 802-1x.phase2-autheap mschapv2 \ wifi-sec.auth-alg open \ wifi-sec.key-mgmt wpa-eap \ > /etc/NetworkManager/system-connections/eduroam.nmconnection chmod 600 /etc/NetworkManager/system-connections/eduroam.nmconnection # Disable phased updates echo "APT::Get::Never-Include-Phased-Updates true;" > /etc/apt/apt.conf.d/99-Phased_Updates # exit the chroot exit
Finally we need to cleanup the chroot
sudo umount msr_image/proc sudo umount msr_image/sys sudo umount msr_image/dev/pts sudo umount msr_image/tmp sudo umount msr_image/run
Make the Minimal Squashfs
We now need to compress the filesystem image and add it to the install CD
- Make sure you have
squashfs-tools
installed
Add the installable filesystem to the iso
# Make the squashfs filesystem from the chroot environment # Warning, there should not be an existing msr.squashfs present: rm msr.squashfs sudo mksquashfs msr_image msr.squashfs -comp xz # Copy squashfs to casper sudo cp msr.squashfs extracted/casper
Make the Desktop Squashfs
We can make an install ISO with msr.squashfs
as the deployed filesystem. This will be
a minimal Ubuntu system with network-manager
and a user can therefore connect to the network (wirelessly if needed)
and install other software. However, the full Ubuntu experience comes with an out-of-the-box Desktop environment,
and in this section we will provide that to the install ISO user, as an option.
First, add an entry for a new squashfs:
# Append the install-sources.yaml cat << EOF | sudo tee -a extracted/casper/install-sources.yaml - default: true description: en: A minimal Ubuntu Desktop for NUMSR. id: ubuntu-desktop locale_support: langpack name: en: Ubuntu Desktop (NUMSR) size: 0 path: msr.desktop.squashfs type: fsimage-layered variant: minimal EOF
The goal is to make a new squashfs based off msr.squashfs
without duplicating the files in msr.squashfs
.
For more details see Using Squashfs
- Make some new directories:
mkdir msr_desktop msr_desktop.work msr_desktop.upper msr_image.mnt
msr_image.mnt
is wheremsr.squashfs
will be mounted read-onlymsr_desktop
is a directory where we will modify the combined filesystemsmsr_desktop.upper
contains the files that are inmsr_desktop
but not inmsr_image.mnt
msr_desktop.work
is the working directory for overlayfs
Mount the overlay (assumes
fuse-overlayfs
is installed):sudo mount -t squashfs msr.squashfs msr_image.mnt -o loop sudo mount -t overlay \ -o lowerdir=msr_image.mnt,upperdir=msr_desktop.upper,workdir=msr_desktop.work \ overlay msr_desktop
Mount all the filesystems needed for
chroot
and enter itsudo mount none -t proc msr_desktop/proc/ sudo mount none -t sysfs msr_desktop/sys/ sudo mount none -t devpts msr_desktop/dev/pts sudo mount none -t tmpfs msr_desktop/tmp sudo mount none -t tmpfs msr_desktop/run # Make sure we can resolve hostnames in the chroot sudo mkdir -p msr_desktop/run/systemd/resolve sudo cp /etc/resolv.conf msr_desktop/run/systemd/resolve/stub-resolv.conf sudo chroot msr_desktop
- Install all the desktop files: this is where you customize the installation, but my recommendations are in Desktop Setup.
- Exit the
chroot
Unmount the filesystems needed for the chroot:
sudo umount msr_desktop/proc sudo umount msr_desktop/sys sudo umount msr_desktop/dev/pts sudo umount msr_desktop/tmp sudo umount msr_desktop/run
- Make the squashfs of the overlayed filesystem:
sudo mksquashfs msr_desktop.upper msr.desktop.squashfs -comp xz
- Copy the squashfs to the iso:
sudo cp msr.desktop.squashfs extracted/casper
- Unmount the overlay
sudo umount msr_desktop
- Unmount the underlay
sudo umount msr_image.mnt
Update the Live Squashfs
- The live squashfs (
minimal.standard.live.squashfs
) contains files that are available on the Live cd but not necessarily on the installed system - We will add two utilities:
clonezilla
, which enables cloning harddrives anddebootstrap
which enables doing a bare-bones minimal installation. Extract the squashfs filesystems:
sudo unsquashfs extracted/casper/minimal.squashfs && mv squashfs-root minimal.root sudo unsquashfs extracted/casper/minimal.standard.squashfs && mv squashfs-root minimal.standard.root sudo unsquashfs extracted/casper/minimal.standard.live.squashfs && mv squashfs-root minimal.standard.live.root
Setup the overlays:
mkdir minimal_standard.work minimal_standard.mnt # mount standard on top of live into minimal_standard.mnt sudo mount -t overlay \ -o lowerdir=minimal.root,upperdir=minimal.standard.root,workdir=minimal_standard.work \ overlay minimal_standard.mnt # minimal_standard.mnt now contains the merged contents of minimal.root and minimal.standard.root mkdir minimal_standard_live.work minimal_standard_live.mnt sudo mount -t overlay \ -o lowerdir=minimal_standard.mnt,upperdir=minimal.standard.live.root,workdir=minimal_standard_live.work \ overlay minimal_standard_live.mnt # minimal_standard_live.mnt is where we make modifications. The changes that only happened in the top layer will be in =minimal.standard.live.root=
Mount all the filesystems needed for
chroot
and enter itsudo mount none -t proc minimal_standard_live.mnt/proc/ sudo mount none -t sysfs minimal_standard_live.mnt/sys/ sudo mount none -t devpts minimal_standard_live.mnt/dev/pts sudo mount none -t tmpfs minimal_standard_live.mnt/tmp sudo mount none -t tmpfs minimal_standard_live.mnt/run # Make sure we can resolve hostnames in the chroot sudo mkdir -p minimal_standard_live.mnt/run/systemd/resolve sudo cp /etc/resolv.conf minimal_standard_live.mnt/run/systemd/resolve/stub-resolv.conf sudo chroot minimal_standard_live.mnt
apt install -y clonezilla debootstrap
- Exit the
chroot
withexit
Unmount the filesystems needed for the chroot:
sudo umount minimal_standard_live.mnt/proc sudo umount minimal_standard_live.mnt/sys sudo umount minimal_standard_live.mnt/dev/pts sudo umount minimal_standard_live.mnt/tmp sudo umount minimal_standard_live.mnt/run
- Make the squashfs of the overlayed filesystem:
sudo mksquashfs minimal.standard.live.root minimal.standard.live.squashfs -comp xz
- Move the squashfs to the iso:
mv minimal.standard.live.squashfs extracted/casper
Unmount everything:
sudo umount minimal_standard_live.mnt sudo umount minimal_standard.mnt
Recreate the ISO
# Re-create the iso. This will create a .iso file called msr.iso # WARNING! you must remove any existing msr.iso before running this command or it will fail sudo xorriso -outdev msr.iso \ -map extracted / -- \ -volid "Ubuntu 24.04 MSR" \ -boot_image grub grub2_mbr=mbr.img \ -boot_image any partition_table=on \ -boot_image any partition_cyl_align=off \ -boot_image any partition_offset=16 \ -boot_image any mbr_force_bootable=on \ -append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b EFI.img \ -boot_image any appended_part_as=gpt \ -boot_image any iso_mbr_part_type=a2a0d0ebe5b9334487c068b6b72699c7 \ -boot_image any cat_path='/boot.catalog' \ -boot_image grub bin_path='/boot/grub/i386-pc/eltorito.img' \ -boot_image any platform_id=0x00 \ -boot_image any emul_type=no_emulation \ -boot_image any load_size=2048 \ -boot_image any boot_info_table=on \ -boot_image grub grub2_boot_info=on \ -boot_image any next \ -boot_image any efi_path=--interval:appended_partition_2:all:: \ -boot_image any platform_id=0xef \ -boot_image any emul_type=no_emulation \ -boot_image any load_size=full # The above command came from reading the options to build the original .iso which can be done via # sudo xoriso -indev ubuntu-desktop-24.04.iso -report_el_torrito cmd
Testing the Image in a Virtual Machine
- During development, it is helpful to run the image in a virtual machine, in order to test it.
- Install the open-source UEFI firmware for qemu:
sudo apt install ovmf
- Install the qemu emulator
sudo apt install qemu-system-x86
- Copy the UEFI firmware:
cp /usr/share/OVMF/OVMF_CODE_4M.fd .
- Create the hardisk:
qemu-img create -f qcow2 test.img 20G
- Run the emulator and boot the install cd (
enable-kvm
is optional but makes things faster)
qemu-system-x86_64 -drive if=pflash,format=raw,file=./OVMF_CODE_4M.fd -cdrom msr.iso -drive file=test.img -m 20G -enable-kvm -cpu host -smp 8
Structure of the Installation Image
The official Ubuntu Install Image is an iso0660 formatted disk image designed to be booted from either a CD or an external hard-drive. It enables users to test a Live Ubuntu 24.04 system and then do the installation.
The first sector of the iso image is the Master Boot Record (mbr). The first 446 bytes of the mbr is the boot code.
casper
The /casper
directory contains various squashfs
images that are either extracted as part of the LiveCD environment or the installation environment.
- Essentially
minimal.en.live.squashfs
is the livecd - It seems like there is some hierarchy to the naming, whereas minimal.standard depends on minimal, for example.
- I think these filesystems are extracted and overlayed somehow but I am not sure (if you know let me know!)
- The kernel and initrd are also in /casper.
- The
/initrd
can be extracted withunmkinitramfs
. When its loaded the/init
script is run. - Confusingly the
initramfs
is the replacement for theinitrd
, but it is still contained in a file called initrd! - The initrd and kernel are specified as part of the bootloader in
/boot/grub/grub.cfg
- The
- The
/casper/install-sources.yaml
file tells the installation what variants of ubuntu to install.- For example, eliminating the second option removes the option for an extended ubuntu install when running the installer
- Not quite sure how this maps however, have not fully tried.
- Much of the content here is actually not needed when making a specific install
- For example the langpacks. These are used to construct the name of the squashfs image, based off the base name, to install the desired squashfs.
- For our purposes, we won't use language packs and just use a single squashfs that should be extracted.
- The subiquity installer sets up configuration for curtin, the program that actually does the installation, based off of answers to questions.
curtin
partitions the disks, extracts the squashfs to the disk (seeding the system), and then installs the kernel, the bootloader, and some other packages- It also generates locales, which is shwy some language packages are needed in the base image.
- It does not setup a user account. Instead it sets up Ubuntu cloud-init to setup the user account on first boot
- The curtin installer itself is inside a snap. To get to this snap
- unsquash the minimal.squashfs filesystem in casper
- Within that filesystem go to
/var/lib/snapd/snaps/ubuntu-bootstrap.snap
- A snap is just as squash-fs filesystem, so unsquash that.
- You now have access to modifying/replacing curtin, which gives you ultimate flexibility
ISO disk file is a read-only disk format that contains a live Ubuntu 24.04 system and the subiquity install system. https://releases.ubuntu.com/noble/ubuntu-24.04-desktop-amd64.iso
Structure of the Live CD
Logs for the subiquity installer are stored in /var/log/installer
. Looking at these logs is particularly helpful if the installer fails,
to figure out why it failed.
Exploring Packages
- https://packages.ubuntu.com is a one-stop shop for exploring all the packages on any Ubuntu distribution.
- The apt-rdepends package is incredibly useful for recursively exploring package dependencies for a distribution:
apt-rdepends package
shows all packagespackage
depends on, recursivelyapt-rdepends -r package
shows all package that depend on a package. It is used to verify what packages may be uninstallable if a given package that is usually on an Ubuntu system is removed.apt-file
also provides a useful interface for getting information about packagesapt-policy
can help you determine what version of a package is installed and what versions are available.
The Base System
The base system consists of
- The bootstrap: the bare minimal set of packages required to install other packages
- Minimal Userspace: utilities required to login and connect to the internet
- Desktop: the graphical user interface
Bootstrap
An Ubuntu system can be "bootstrapped" using the debootstrap
tool.
To see the most basic packages for an Ubuntu userspace (mainly only useful for installing other packages) invoke:
debootstrap --arch=amd64 --variant=minbase --print-debs noble <directory_name>
.
MSR Ubuntu will contain all the minbase
packages.
A system with just the bootstrap is essentially useless: all it has is the packages necessary for installing more packages.
Bootloader and Kernel
- The
Ubuntu
install CD will install the bootloader files and kernel if they are not provided. - However, these packages are not included on the CD, so this will necessitate an internet install
- To ensure a repeatable experience, it makes sense to install the following packages via
debootstrap
- Bootloader:
efibootmgr
,grub-efi-amd64
,grub-efi-amd64-signed
,shim-signed
. - Kernel:
linux-image-generic
,initramfs-tools
- We rely on dependency resolution to bring in the necessary dependencies of the above packages.
- Bootloader:
- We also install
zstd
, a compression tool. This allows the setup to compress theinitramfs
withzstd
instead ofgzip
, which is a better compression algorithm.
Minimal Ubuntu Userspace
Ubuntu defines a ubuntu-minimal package, which forms the basis of the minimal packages we will install.
However ubuntu-minimal
depends on some packages that we do not want, and does not contain others that are essential for
a minimal desktop.
With the tools of the minimal userspace installed, you can log in, connect to the internet, and install more packages. Of course, you will need to do this all at a console, as there is no graphical user interface (GUI) or desktop.
Ubuntu Minimal
The ubuntu-minimal
package is a meta-package that no other packages depend on. Since we won't have all the packages in ubuntu-minimal
we
will not install it. Instead we will manually pick and install the dependencies of ubuntu-minimal
that we want.
Netplan
Netplan (package: netplan.io
) is method for configuring Linux networks using YAML files and is part of ubuntu-minimal
.
Overall, this package is being removed because it is mainly only used on Ubuntu and makes debugging networking more difficult.
- Reasons for Keeping Netplan
- Ubuntu created Netplan to unify network configuration between NetworkManager and systemd-networkd (the only two supported backends as of 2024).
- Netplan reads a YAML configuration file and translates that into a configuration used by whichever backend is chosen.
- Netplan does not yet have wide adoption outside Ubuntu (although it can be used in Debian and the default for Debian Cloud.
- On desktop Ubuntu, the use of netplan is transparent because configurations of netplan and NetworkManager are bi-directionally synchronized.
- This means, in theory, you can use NetworkManager commands and not worry about netplan or netplan configuration and not worry about NetworkManager
- It is the default on all versions of Ubuntu and is difficult to remove due to packages that depend on it.
- Reasons for Removing Netplan
- I have not encountered a use-case where I need a unified configuration between NetworkManager and systemd-networkd
- If the network setup is complicated or the computer is used in different networking environments (e.g., it is a laptop) I use NetworkManager
- If the network setup is simple I use NetworkManager too.
- If I ever couldn't use NetworkManager (maybe it's too big and complicated), I'd use systemd-networkd.
- It is hard to imagine a situation where I would need to setup a network on multiple machines where one machine used NetworkManager, the other used
systemd-networkd
, and the setup was so complicated that having a single configuration file would be beneficial.
- Everything that netplan can do, NetworkManager can do (except read a YAML configuration file).
- There are network setups that
netplan
can not accomplish or that it can only accomplish when using the NetworkManager backend. - With
netplan
there are now two systems to worry about (when there used to be only one):- When debugging problems, you often need to understand how netplan configuration maps to NetworkManager or
systemd-networkd
configuration. - You need to worry about the two systems being out of sync (either through bugs or user error).
- When debugging problems, you often need to understand how netplan configuration maps to NetworkManager or
- Skills learned with NetworkManager transfer to other Linux distributions much more readily than learning about netplan
- As a result, there are far more resources online with guidance on how to use NetworkManager. No need to stick with only Ubuntu-based help.
- The numsr ppa contains a replacement
network-manager
package that reverses the Ubuntu-specific patches that synchronize it withnetplan
- I also removed Debian/Ubuntu specific configuration of network-manager that allowed systems to mix its use with the
old network management system
ifupdown
. This change is consistent with the goal of having only one network configuration to use, learn, and debug when something goes wrong.
- I also removed Debian/Ubuntu specific configuration of network-manager that allowed systems to mix its use with the
old network management system
- I have not encountered a use-case where I need a unified configuration between NetworkManager and systemd-networkd
Ubuntu Pro Client
Ubuntu Pro is a paid version of Ubuntu (although it is free in certain cases) with additional updates and support. We will not use Ubuntu Pro and therefore do not need this package.
- Reasons for Keeping
- There are some packages (particularly meta packages) that depend on on
ubuntu-pro-client
. - Canonical (the company behind Ubuntu) needs to make money somehow.
- Ubuntu Pro does appear to have some useful features (for example they provide a pre-compiled realtime Linux kernel).
- There are some packages (particularly meta packages) that depend on on
- Reasons for Removing
- We do not use its features.
- It is related to things that will (lightly and respectfully) nag you about getting Ubuntu Pro
- There are a few solutions for the packages that depend on
ubuntu-pro-client
- Don't install those packages (none of them are necessary)
- Install a dummy package that does nothing but satisfies the dependency. Assume that most (if not all) programs that depend on
ubuntu-pro-client
mostly function even without it. - Block installation of
ubuntu-pro-client
in/etc/apt/preferences.d
. This is the option this installation uses, but if you ever need to undo it, just edit the preference.
Cloud-init
Cloud-init is Ubuntu's method of provisioning containers (and other cloud computers) using YAML configuration files. In Ubuntu 24.04, they also use cloud-init as part of the desktop.
- Reasons for Using Cloud Init
- It is the default for Ubuntu 24.04
- It is hard to replace because it does essential tasks (such as creating the user account) on the first boot
- Reasons for Removing Cloud Init
- We are not provisioning cloud-servers, we are making a single laptop computer
- It runs on every boot, even though in our case it only does work on the first boot
- The tasks it appears to be doing, in the role it plays in the Desktop, can be easily accomplished in a simpler way
- It brings in a lot of dependencies that are not necessary.
- It is an Ubuntu-specific technology.
Additional Packages
language-selector-common
is used bycurtin
(I don't know exactly what it does but it seems to setup languagesnetwork-manager
(from the nu-msr ppa) is used to configure networkingsoftware-properties-common
tools for managing apt repositoriessystemd-resolved
is used by NetworkManager for resolving DNS queries- I also add a configuration file
/etc/NetworkManager/system-connections
that makes it easier to connect toeduroam
WiFi networks
Blocked packages
To avoid accidentally installing certain packages that are unwanted,
the installation blocks them using /etc/apt/preferences.d/numsr-apt-preferences
.
The packages that are blocked are:
apport
Ubuntu-specific core dump utility (other Linux usessystemd-coredump
)cloud-init
netplan.io
ubuntu-pro-client
unattended-upgrades
whoopsie
Additional Package Options
Phased Updates are disabled, ensuring that we are all on more-similar Ubuntu versions.
- From man 5 apt_preferences setting Never-Include_Phased-Updates prevents our machines from getting them.
Desktop
Technically from the minimal system you can install whatever desktop environment that you would like. However, in the spirit of making the install experience as close to stock-ubuntu as possible, I install the same desktop system (minus a few things) that you would expect.
The goal here is not a minimal desktop,rather it is a desktop that closely matches what is standard in Ubuntu, just without parts that conflict with the rest of the mission of this installation (e.g., removing auto update, not using snaps, etc).
It is possible, after installation, to install your own desktop environment or build from scratch upon the minimal base.
The apt install
command below installs most of the packages from ubuntu-desktop-minimal
except for:
Required
Packages that are NOT included
ca-certificates
(already installed)software-properties-gtk
(we manage software via the commandline and it has undesirable dependencies)ubuntu-release-upgrader-gtk
(we do not want to ever upgrade the release).update-manager
(we manage updates via the command-line)update-notifier
(do not want to be nagged about updating)apport-gtk
(we don't use apport. It can be useful for crash dumps but it is Ubuntu only and thesystemd-coredump
is more widely supported on Linux)avahi-daemon
(mDNS is handled bysystemd-resolvd
via NetworkManager, so this is redundant and causes confusion)firefox
(we want a non-snap version provided by Mozilla directly)language-selector-common
(already installed) \libglib2.0-bin
(already installed) \network-manager-*
(network-manager is part of the minimal system).xkb-data
(already installed)
Recommended
- Lots of the suggested packages are there as "just in case your computer has X hardware".
- I have culled these partially based on what hardware is available on the Sys76 Adder4 laptop
Packages that are NOT included
gamemode
(this is a daemon that lets applications use it, but does not seem to be running. if anything needs it they will bring it in as a dependency)gnome-initial-setup
(the installer already has setup gnome)libpam-fprintd
(laptop does not have a finger print reader)package-kit
(we manage packages from the commandline)printer-driver-*
(if needed install the required package)pcmciautils
(our laptops don't have pcmcialibproxy1-plugin-gsettings
(we do not uselibproxy
)libproxy1-plugin-networkmanager
(we do not uselibproxy
)snapd
(we do not use snaps)ubuntu-report
(do not want to send telemetry to Canonical, Linux should be telemetry free!)whoopsie
(do not want pop-ups asking us to report errors to Ubuntu when developing our own software that may crash frequently!)
Additional Packages
Since the move to snaps, there are no mainstream web-browsers that are regular apt
packages.
We will install firefox
from the Official Mozila APT Repository
dbus-x11
: when installing thesystem76-driver
part of themkinitcpio
process seems to want it.
The Commands in the Chroot
The command should be run in the chroot
when creating the squashfs.
- To determine what was already installed, I ran this command without
-y
and looked at theapt
output - Packages like
whoopsie
andapport
are in the recommended list but will not be installed due to the pin we set up earlier.
apt update apt install -y \ alsa-base \ alsa-utils \ anacron \ at-spi2-core \ bc \ dbus-x11 \ dmz-cursor-theme \ fontconfig \ fonts-dejavu-core \ foomatic-db-compressed-ppds \ gdm3 \ ghostscript \ gnome-control-center \ gnome-menus \ gnome-session-canberra \ gnome-settings-daemon \ gnome-shell \ gnome-shell-extension-appindicator \ gnome-shell-extension-desktop-icons-ng \ gnome-shell-extension-ubuntu-dock \ gnome-shell-extension-ubuntu-tiling-assistant \ gstreamer1.0-alsa \ gstreamer1.0-packagekit \ gstreamer1.0-plugins-base-apps \ inputattach \ language-selector-gnome \ libatk-adaptor \ libnotify-bin \ libsasl2-modules \ libu2f-udev \ nautilus \ openprinting-ppds \ pipewire-pulse \ printer-driver-pnm2ppa \ rfkill \ spice-vdagent \ ubuntu-drivers-common \ ubuntu-session \ ubuntu-settings \ unzip \ wireless-tools \ wireplumber \ xdg-user-dirs \ xdg-user-dirs-gtk \ xorg \ yelp \ zenity \ zip \ appstream \ apt-config-icons-hidpi \ baobab \ bluez \ bluez-cups \ cups \ cups-bsd \ cups-client \ cups-filters \ dirmngr \ eog \ evince \ fonts-liberation \ fonts-noto-cjk \ fonts-noto-color-emoji \ fonts-noto-core \ fonts-ubuntu \ fwupd \ fwupd-signed \ gir1.2-gmenu-3.0 \ gnome-accessibility-themes \ gnome-bluetooth-sendto \ gnome-calculator \ gnome-characters \ gnome-clocks \ gnome-disk-utility \ gnome-font-viewer \ gnome-keyring \ gnome-logs \ gnome-power-manager \ gnome-remote-desktop \ gnome-system-monitor \ gnome-terminal \ gnome-text-editor \ gpg-agent \ gsettings-ubuntu-schemas \ gvfs-fuse \ hplip \ ibus \ ibus-gtk \ ibus-gtk3 \ ibus-table \ im-config \ kerneloops \ laptop-detect \ libnss-mdns \ libpam-gnome-keyring \ libpam-sss \ libspa-0.2-bluetooth \ libwmf0.2-7-gtk \ memtest86+ \ mousetweaks \ nautilus-sendto \ orca \ plymouth-theme-spinner \ policykit-desktop-privileges \ seahorse \ speech-dispatcher \ systemd-oomd \ ubuntu-docs \ ubuntu-wallpapers \ xcursor-themes \ xdg-desktop-portal-gnome \ xdg-utils \ yaru-theme-gnome-shell \ yaru-theme-gtk \ yaru-theme-icon \ yaru-theme-sound
We will install Firefox from the Mozilla apt repository (adapted from Mozilla Documentation:
# Get mozilla's signing key wget -q https://packages.mozilla.org/apt/repo-signing-key.gpg -O /etc/apt/keyrings/packages.mozilla.org.asc # Verify that it's fingerprint is 35BAA0B33E9EB396F59CA838C0BA5CE6DC6315A3 gpg -n -q --import --import-options import-show /etc/apt/keyrings/packages.mozilla.org.asc echo "deb [signed-by=/etc/apt/keyrings/packages.mozilla.org.asc] https://packages.mozilla.org/apt mozilla main" > /etc/apt/sources.list.d/mozilla.list # Ensure this firefox takes precedence over the fake apt package cat << EOF > /etc/apt/preferences.d/mozilla Package: * Pin: origin packages.mozilla.org Pin-Priority: 1000 EOF apt update apt install firefox
Updating the Install ISO
- The instructions for updating the ISO are below
- An explanation of the install iso is after the instructions
- Before you begin: the version of packages from
debootstrap
must match that version of packages on the installation media or the install will fail. This means if you downloaded - These instructions are a beta version.
Writing The ISO To a USB Drive:
- See Archlinux USB Flash
- 1. Use
lsblk
to find the name of the flash drive and ensure that it is not mounted- I like to
sudo chown <user>:<user> name/of/flashdrive
so I can't accidentally overwrite the wrong drive dd bs=4M if=msr.iso of=/dev/<path_to_device> conv=fsync oflag=direct status=progress
- I like to
MSR PPA
The following steps should be done from Ubuntu LTS
How To Make A PPA
- Sign up for a launchpad.net account
- Create an OpenPGP key:
gpg --full-gen-key
- See the keys with
gpg --list-keys
- Send your key to the Ubuntu keyserver:
gpg --send-keys --keyserver keyserver.ubuntu.com <keyid>
- Wait 10 minutes for the server to update
- In your launchpad profile, add the pgp key (use
gpg --fingerprint
to get the fingerprint you needed) - Assuming your email is not setup with
gpg
, copy the encrypted message to a file and decrypt withgpg -d
, then follow the instructions. - While logged into launchpad, assign (or affirm) the Code of Conduct
References
How To Rebuild a Debian Package
- Make sure the
pgp
keys are setup on the system you are building the package on. - Install the
devscripts
package Create
/etc/apt/sources.list.d/ubuntu-src.sources to let =apt
know where to get source packages from.Types: deb-src URIs: http://archive.ubuntu.com/ubuntu/ Suites: noble noble-updates noble-backports Components: main universe restricted multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
sudo apt update
apt build-dep <packagename>
installs the build dependencies- Create a working directory
<workdir>
andcd <workdir>
. apt source <packagename>
downloads the source package to<workdir>
.- The debian build process likes to spew and refer to files in the parent directory.
- To help with this it makes sense to copy the workdir when issuing a new
debuild
command.
- To help with this it makes sense to copy the workdir when issuing a new
- The package download should have created a directory with the upstream package name and version
<package>
. Enter this directory - Most debian packages use the Quilt patch management system to manage patches
- Use
quilt push -a
to make sure the package is up-to-date - You can also track things as patches using quilt if you would like:
quilt new patchname.patch
creates a new patchquilt add filename
adds a file to the patchset. This must be done prior to editing the file- When done editing use
quilt refresh
to apply the patch.
- Use
- Edit
debian/changelog
, adding a new entry for yourself outlining the changes you made- Be sure to boost the version number in the changelog.
- If you have just made changing to the packaging, change the debian version (the part after the
-
) - Appending a
~<N>
makes the package be considered less new than the version without the~<N>
appended. - Name and email address should likely be consistent with the pgp key you use to sign the ppa.
- These packages are very finicky about the version naming scheme, and various items have different semantic meanings. For my purpose, incrementing the revision number seems to work best.
- The
debian/control
has information about package dependencies - When ready to build run
debuild -k<your-pgp-key-id> -b
(from a new<workspace>
directory)- You may wish to install and test the package.
- When ready to upload to the ppa run:
debuild -k<your-pgp-key-id> -S -sa
- If the source built successfully upload the packages using
dput ppa: <package_name>.changes
(according to the instructions on the ppa page). - Refresh your ppa homepage. It may take a little while. If the build failed, you will get an email with some diagnostic information.
- There is no need to keep track of your changes in git: once uploaded to launchpad you can see the source and your changes to it by downloading the source package.
- Essentially, your changes are being tracked in launchpad. This is fine for changes to the packaging itself, but if you are changing source code you likely want to make the changes in a fork or even submit them to the upstream project.
Git and quilt
Quilt is used in debian packages to keep track of "upstream debian changes" and the source code version. I like to fork a package and make changes in the fork. I then use "git format-patch <commit>" to turn the commits to HEAD from <commit> into a patchset In the original debain package (say it's version 2.44), I then use "quilt import" on each patch created by git format-patch. Now the debian source package contains the patches made against the upstream version to debianize it, but meanwhile all my code is in git Quilt environment variable QUILT_PATCHES=debian/patches should be set
RT Kernel
- Get RT Kernel sources (must get via git to make the debian source package) git clone https://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-stable-rt.git/ CHeckout the latest rt branch
- Make menu config and setup the kernel.
- I made a custom version based on the config available in /boot/config
- The kernel is designed for x86 systems and removes support for a lot of legacy hardwaree tc
- It's nto fully minimal as it tries to stay close to ubuntu defaults
- In kernel source tree: make menuconfig
- To build a debian package: make deb-pkg
- Test this by installing it
- To prepare for the ppa
- Use make srcdeb-pkg to make the source package
- This creates a gzip of the package directory.
- The original source is the orig.tar.gz file
- What we need to do is
- Extract the orig.tar.gz file to a file that matches the name of what you actually want to call the package
- Unpack the source package to a new directory
- tar czvf name_of_package.orig.tar.gz source_dir
- This creates the original tarball
- Extract the source tarball into the extracted source directory
- Edit control and changelog to set the version and the package name that you want
- debuild -k<KEYID> -S -sa to build the source package that can be uploaded to the ppa