Installation of Debian 12 UEFI on USB stick using 'debootstrap'

Requirements

Warning: all data on the USB stick will be destroyed during the installation!

In this guide the installation is performed on 32 GiB USB stick. Change the size of your partitions accordingly to your USB stick's maximum capacity.

Preparation

Install 'debootstrap'.

sudo apt update
sudo apt upgrade -y
sudo apt install debootstrap

Connect an USB stick to a computer.

Find the device name.

sudo dmesg

Read through the last entries of 'dmesg' output. In my case, the lines 'usb 2-5: New USB device found', 'usb 2-5: Product: Flash Drive' and '[sdb] 62656641 512-byte logical blocks: (32.1 GB/29.9 GiB)' indicate that the USB stick is identified as /dev/sdb.

Warning: if you select the wrong device during installation, all the data on that device will be destroyed.

Run 'lsblk' to list all avaliable devices.

lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda           8:0    0 953.9G  0 disk
├─sda1        8:1    0   560M  0 part /boot/efi
├─sda2        8:2    0     4G  0 part [SWAP]
├─sda3        8:3    0   120G  0 part /
└─sda4        8:4    0 829.3G  0 part /home
sdb           8:16   1  29.9G  0 disk
└─sdb1        8:17   1  29.9G  0 part

My USB stick has single partition formatted as FAT32 by manufacturer. The USB stick will be repartitioned and all data on the partition along with partition table will be lost.

Warning: if you select the wrong device during the installation, all the data on that device will be destroyed.

Partitioning the USB stick

Make sure you are working with the correct device! Use 'su -l' command to switch user to root.

su -l
cd /

Check your $PATH variable.

echo "$PATH" | tr ':' '\n'

If it lacks '/sbin' and '/usr/sbin', add them (bash syntax).

declare -x PATH="$PATH:/sbin:/usr/sbin"

Use 'gdisk' to partition the device.

gdisk /dev/sdb

On 'gdisk' prompt type 'o' and press 'Enter' to create a new empty GUID partition table (GPT).

Type 'n' to create a new partiton, press 'Enter' on prompts to select partiton number and the first sector. For last sector type '+560M'. If the boot partition will be smaller than 560 mebibytes, some buggy UEFI firmware may fail to read the contents of boot partition. Type 'ef00' in the 'Hex code or GUID' prompt to change the type of partition to the 'EFI system partition' type. You can always press 't' to change the partition's type code, if you've accidentally chosen a wrong partition type.

Type 'n' to create a new partition, press 'Enter' on prompts to select partiton number and the first sector. For last sector type '+1500M'. Type '8200' in the 'Hex code or GUID' prompt to change the type of partition to the 'Linux swap' type. It is important to have a swap partition on Linux system. Without swap, if the kernel runs out of memory, it will kill random process to free the memory. Depending on the process, the system may crash resulting in data loss.

Type 'n' to create a new partition, press 'Enter' on prompts to select partiton number and the first sector. For last sector type '+18G'. Type '8300' in the 'Hex code or GUID' prompt to change the type of partition to the 'Linux filesystem' type.

Type 'n' to create a new partiton, press 'Enter' on prompts to select partiton number, the first sector and the last sector. Type '0700' in the 'Hex code or GUID' prompt to change the type of partition to the 'Microsoft basic data' type. This partition will have size around 9.9 GiB and will be formatted as FAT32 filesystem; any foreign operating system will be able to mount this partition allowing you to use this USB stick as a regular USB flash drive on operating systems such as 'Microsoft Windows' and 'MacOS'.

Type 'p' to view the full partition table, type 'i' to view detailed information on each individual partition. It is advisable to save that information into a text file, for you to be able to restore partitions manually if partition table gets damaged in the future.

Type 'w' and press 'Enter' to save partition table and exit 'gdisk'.

An automatic backup of the partition table can be performed with this command:

sgdisk -b usbBackup.gpt /dev/sdb

To restore the partition table from 'usbBackup.gpt' file, run 'gdisk /dev/sdb', press 'r' to enter 'recovery and transformation' menu, then press 'l' to load partition data from 'usbBackup.gpt' file. Type 'w' to save partition table.

Run 'lsblk' to list all avaliable devices.

lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda           8:0    0 953.9G  0 disk
├─sda1        8:1    0   560M  0 part /boot/efi
├─sda2        8:2    0     4G  0 part [SWAP]
├─sda3        8:3    0   120G  0 part /
└─sda4        8:4    0 829.3G  0 part /home
sdb           8:16   1  29.9G  0 disk
├─sdb1        8:17   1   560M  0 part
├─sdb2        8:18   1   1.5G  0 part
├─sdb3        8:19   1    18G  0 part
└─sdb4        8:20   1   9.9G  0 part

Formatting the USB stick

EFI partition must have FAT32 filesystem. Make sure to specity '-F 32' parameter to 'mkfs.fat' or it may automatically choose FAT16 filesystem. Some UEFI systems are unable to boot from EFI partition formatted as FAT16. Use '-n' to set the volume name (label) to be able to easily identify it later. For FAT32 partition labels must be no longer than 11 characters and contain only uppercase letters.

mkfs.fat -F 32 -n 'USBBOOT' /dev/sdb1

Format /dev/sdb2 as swap. '-L' parameter sets the label of the partition.

mkswap -L 'USBSWAP' /dev/sdb2

Format /dev/sdb3 as ext4 filesystem. '-L' parameter sets the label of the partition.

mkfs.ext4 -L 'USBROOT' /dev/sdb3

Format /dev/sdb4 as FAT32 filesystem. '-n' parameter sets the label of the partition. For FAT32 partition labels must be no longer than 11 characters and contain only uppercase letters.

mkfs.fat -F 32 -n 'USBSTORE' /dev/sdb4

Run 'blkid' with 'grep' to check newly created and formatted partitions.

blkid | grep 'sdb'

Mounting the USB stick's partitions

Mount the /dev/sdb3 partition on /mnt using 'mount' command.

mount /dev/sdb3 /mnt

Create the /mnt/boot/efi directories using 'mkdir -p' command.

mkdir -p /mnt/boot/efi

Mount the /dev/sdb1 partition on /mnt/boot/efi using 'mount' command.

mount /dev/sdb1 /mnt/boot/efi

Create the /mnt/store directory using 'mkdir' command.

mkdir /mnt/store

Mount the /dev/sdb4 partition on /mnt/store using 'mount' command.

mount /dev/sdb4 /mnt/store

Installation of Debian 12 on the USB stick

Temporarily move swap space from the device on which you are currently booted to the USB stick to not interfere with the installation of the new system.

Change the swap space accordingly to your devices, in my case they are /dev/sda2 and /dev/sdb2.

swapon /dev/sdb2
swapoff /dev/sda2

Run 'lsblk' ensure everything is done correctly.

lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda           8:0    0 953.9G  0 disk
├─sda1        8:1    0   560M  0 part /boot/efi
├─sda2        8:2    0     4G  0 part
├─sda3        8:3    0   120G  0 part /
└─sda4        8:4    0 829.3G  0 part /home
sdb           8:16   1  29.9G  0 disk
├─sdb1        8:17   1   560M  0 part /mnt/boot/efi
├─sdb2        8:18   1   1.5G  0 part [SWAP]
├─sdb3        8:19   1    18G  0 part /mnt
└─sdb4        8:20   1   9.9G  0 part /mnt/store

Install Debian 12 system on /mnt using 'debootstrap'. 'bookworm' is the codename of Debian 12. The process will take some time, so be patient.

debootstrap bookworm /mnt

If your current installation was performed without Internet connection from a 'Live DVD', you will need to add online sources to your /etc/apt/sources.list to be able to update.

Example of Debian 12/Bookworm (stable) /etc/apt/sources.list containing only free software:

deb http://deb.debian.org/debian bookworm main
deb http://deb.debian.org/debian-security/ bookworm-security main
deb http://deb.debian.org/debian bookworm-updates main

Example of Debian 12/Bookworm (stable) /etc/apt/sources.list containing free software and proprietary firmware:

deb http://deb.debian.org/debian bookworm main non-free-firmware
deb http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main non-free-firmware

Example of Debian 12/Bookworm (stable) /etc/apt/sources.list containing free software, proprietary firmware and proprietary software:

deb http://deb.debian.org/debian bookworm main non-free-firmware contrib non-free
deb http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware contrib non-free
deb http://deb.debian.org/debian bookworm-updates main non-free-firmware contrib non-free

If you are currently running Debian 12, copy your /etc/apt/sources.list to /mnt/etc/apt/ directory using 'cp'.

cp /etc/apt/sources.list /mnt/etc/apt/

If you are currently running Debian 10, or Debian 11, create /mnt/etc/apt/sources.list file with the contents from the appropriate listing above.

If you are planning to use desktop environment based on the GTK toolkit, you will need to install and use 'qt5ct' program (after you install the desktop environment) to be able to change appearance of programs based on the Qt toolkit such as 'VLC media player', 'KchmViewer' and 'ghostwriter'. For the 'qt5ct' program to be able to work, this line must be present in /mnt/etc/environment file: 'QT_QPA_PLATFORMTHEME=qt5ct'. This line will only affect desktop environments not based on Qt toolkit and will have no effect on those based on Qt toolkit such as 'KDE' and 'LXQt'.

Edit /mnt/etc/environment file by adding 'QT_QPA_PLATFORMTHEME=qt5ct' line to the list of existing variables (if any).

nano /mnt/etc/environment

Example of /mnt/etc/environment:

QT_QPA_PLATFORMTHEME=qt5ct

Copy /etc/fstab to /mnt/etc/ and edit it changing UUIDs to those listed by your 'blkid' command. Add 'noatime' to increase the lifespan of the USB stick.

cp /etc/fstab /mnt/etc/
blkid | grep 'sdb'
nano /mnt/etc/fstab

If you are using 'vim' text editor, there is a convenient way to import the ouput of 'blkid' into the /mnt/etc/fstab file to be able to copy UUIDs from that output and then edit /mnt/etc/fstab: open /mnt/etc/fstab, create an empty line at the bottom of the file, move to that line, while in normal mode type ':' to enter command mode, then type:

.!blkid | grep 'sdb'

Example of /mnt/etc/fstab:

UUID=8b2e7df4-9c48-d452-f5ef-6aa664a8a853 / ext4 noatime,errors=remount-ro 0 1
UUID=6621-56E3 /boot/efi vfat noatime,umask=0077 0 1
UUID=edbd6535-6e5c-4c23-7611-88fc64a8a7e3 none swap sw 0 0
UUID=4959-2E62 /store vfat nosuid,nodev,noexec,noatime,fmask=111,dmask=000 0 2
/dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0

Set the hostname by editing /mnt/etc/hostname. It must contain one line with one word in it. Default is 'debian'. Then add your hostname to /mnt/etc/hosts.

nano /mnt/etc/hostname
nano /mnt/etc/hosts

Example of /mnt/etc/hostname:

yourhostname

Example of /mnt/etc/hosts:

127.0.0.1	localhost
127.0.1.1	yourhostname
::1		localhost ip6-localhost ip6-loopback
ff02::1		ip6-allnodes
ff02::2		ip6-allrouters

Create /mnt/etc/papersize file to set the default printer paper size for your region. It must contain one line with either 'letter', or 'a4' word in it. Default is 'letter'.

nano /mnt/etc/papersize

Example of /mnt/etc/papersize:

a4

Copy /etc/resolv.conf to /mnt/etc/ to have Internet connection while being in chrooted environment.

cp /etc/resolv.conf /mnt/etc/

Edit /mnt/etc/security/limits.conf to disable core dumps. Unless you are software developer and/or willing to debug the core files, there is no reason for the system to generate those files when programs crash.

nano /mnt/etc/security/limits.conf

Scroll down below the line '#<domain> <type> <item> <value>' and add the following:

* soft core 0
* hard core 0
root soft core 0
root hard core 0

Mount virtual filesystems on /mnt.

mount -v --bind /dev /mnt/dev
mount -vt devpts /dev/pts /mnt/dev/pts
mount -vt proc /proc /mnt/proc
mount -vt sysfs /sys /mnt/sys
mount -vt tmpfs /run /mnt/run

Changing root into USB stick

Use 'chroot' command to change root into /mnt, which is the / filesystem of USB stick.

chroot /mnt

Check your $PATH variable.

echo "$PATH" | tr ':' '\n'

If it lacks '/sbin' and '/usr/sbin', add them (bash syntax).

declare -x PATH="$PATH:/sbin:/usr/sbin"

Set password for user 'root' using 'passwd' command.

passwd

Update and upgrade the system using 'apt'.

apt update
apt upgrade -y

Install locales.

apt install locales

Select your locale settings by running 'dpkg-reconfigure locales' command.

dpkg-reconfigure locales

Select your time zome settings by running 'dpkg-reconfigure tzdata' command.

dpkg-reconfigure tzdata

Install Linux kernel, sudo, network-manager.

apt install linux-image-amd64 sudo network-manager

You can obtain the UUID of your swap partition by using 'grep' and 'cut' commands:

grep 'sw[[:blank:]]' /etc/fstab | cut -c '6-41'

If it looks correct, create /etc/initramfs-tools/conf.d/resume file with sting 'RESUME=UUID=' and UUID of your swap partition by redirecting the output of 'printf' command into /etc/initramfs-tools/conf.d/resume file:

> /etc/initramfs-tools/conf.d/resume printf 'RESUME=%s\n' "$(grep 'sw[[:blank:]]' /etc/fstab | cut -c '-41')"

Example of /etc/initramfs-tools/conf.d/resume:

RESUME=UUID=edbd6535-6e5c-4c23-7611-88fc64a8a7e3

Install 'grub2' bootloader.

apt install grub-efi-amd64

Open /etc/default/grub file and remove 'quiet' from 'GRUB_CMDLINE_LINUX_DEFAULT' line to be able to see kernel messages during system boot. Then uncomment 'GRUB_DISABLE_OS_PROBER=false' line by removing '#' symbol from the beginning of the line to allow 'grub2' to detect other operating systems installed on the computer. Read the commentary above that line explaining why it is disabled by default in Debian 12.

nano /etc/default/grub

Example of modified 'GRUB_CMDLINE_LINUX_DEFAULT' line:

GRUB_CMDLINE_LINUX_DEFAULT=""

Example of modified 'GRUB_DISABLE_OS_PROBER=false' line:

GRUB_DISABLE_OS_PROBER=false

Update bootloader's configuration.

grub-install --target=x86_64-efi --force-extra-removable /dev/sdb
update-initramfs -u
update-grub

The '--force-extra-removable' parameter is required to make removable USB drive bootable. It will create /boot/efi/EFI/BOOT/ directory with files bootx64.efi, fbx64.efi, grub.cfg, grubx64.efi in it. The UEFI firmware will look for /boot/efi/EFI/BOOT/bootx64.efi file on the removable media during the boot process of the computer.

You will need to reinstall 'grub2' with '--force-extra-removable' parameter after every kernel upgrade to update the /boot/efi/EFI/BOOT/ directory.

grub-install --target=x86_64-efi --force-extra-removable /dev/sdb
update-initramfs -u
update-grub

On some cheap motherboards it is possible that UEFI firmware will only boot from /boot/efi/EFI/MICROSOFT/BOOT/bootmgfw.efi, which is a location of Windows boot manager. In that case you need to copy contents of /boot/efi/EFI/BOOT/ to /boot/efi/EFI/MICROSOFT/BOOT/ and rename bootx64.efi to bootmgfw.efi. The FAT32 filesystem is case-insensitive, in your case it may be /boot/efi/efi/boot/, BOOTX64.EFI, or any combination of the above. If your motherboard boots only from /boot/efi/EFI/MICROSOFT/BOOT/bootmgfw.efi file, you will have to repeat this procedure every time the kernel gets upgraded.

mkdir -p /boot/efi/EFI/MICROSOFT/BOOT/
cd /boot/efi/EFI/MICROSOFT/BOOT/
cp /boot/efi/EFI/BOOT/* ./
cp bootx64.efi bootmgfw.efi
cd /

Install the 'X11' graphical server and client.

apt install xorg

Install login manager and desktop environment.

apt install lightdm xfce4 xfce4-goodies xfce4-power-manager gvfs-backends gvfs-fuse qt5ct

Install other packages:

apt install cups-bsd printer-driver-cups-pdf dc bc groff gawk vim-gtk3 htop mupdf firefox-esr libreoffice gimp

If you are using Debian 12 and got a prompt to enter root's password while installing 'printer-driver-cups-pdf', press 'ENTER' instead of typing root's password. You will have to reinstall some packages later, when you'll boot from the USB stick. Refer to 'Troubleshooting' section at the bottom of this guide on how to reinstall packages.

Add user with administrative priviledges using 'useradd' command (user must be a member of the 'sudo' group to be able to use 'sudo' command), set user's password using 'passwd' command.

useradd -mG cdrom,floppy,sudo,audio,dip,video,plugdev,netdev,lpadmin,scanner -s /usr/bin/bash -c 'Name' username
passwd username

Exit chrooted environment using 'exit' command.

exit

Unmount the /mnt

Change swap space back to your drive currently running the operating system. In my case it's /dev/sda2.

swapon /dev/sda2
swapoff /dev/sdb2

Unmount the virtual filesystems.

umount /mnt/run
umount /mnt/sys
umount /mnt/proc
umount /mnt/dev/pts
umount /mnt/dev

Unmount physical filesystems.

umount /mnt/boot/efi/
umount /mnt/store
umount /mnt

Exit from root's shell.

exit

Booting from USB stick

Read you motherboard's manual to find which key will launch the 'Boot menu' during system boot. Usually it's 'F8' or 'F12'.

Reboot your computer, during boot sequence in the beginning rapidly press the boot key ('F8' in my case) to launch the 'Boot menu'. Using arrow keys on the keyboard, navigate to your USB device menu entry. If you have 'Legacy mode' enabled, select the entry with 'UEFI:' text in it. If everything was done correctly, you'll be booting into Debian 12 that is located on your USB stick.

Troubleshooting

• If the graphical login manager did not lauch, press 'Ctrl+Alt+F1', or 'Ctrl+Alt+F2' keys to launch text console, login as 'root', enable and start 'lightdm' using 'systemctl' command.

systemctl enable lightdm
systemctl start lightdm

Reboot using 'reboot' command.

reboot

• If you are using Debian 12 you may experience some errors while installing packages in chrooted environment. In Debian 12 some activity is forbidden in chrooted environment due to security reasons. You will have to reinstall problematic packages using 'sudo apt reinstall' command after you have been booted from the USB stick.

sudo apt reinstall linux-image-amd64 pkexec policykit-1 polkitd cups-bsd printer-driver-cups-pdf

• On a freshly installed Debian 12 system look at '/var/log/boot.log' right after the boot process is complete by using 'sed' and 'date' commands.

sudo sed -n "/$(date '+%a %b %d %H')/,\$p" /var/log/boot.log | less -r

If there is no output, change the '%H' to numeric value of previous hour (double-digit 24-hour format).

Example of the same command with explicitly set hour value:

sudo sed -n "/$(date '+%a %b %d 03')/,\$p" /var/log/boot.log | less -r

If this error is present:

[FAILED] Failed to start logrotate.service - Rotate log files.
See 'systemctl status logrotate.service' for details.

Enable 'logrotate.service' by using 'systemctl' command.

sudo systemctl daemon-reload
sudo systemctl start logrotate

Check the status of 'logrotate.service'.

systemctl status logrotate.service