Safe in-place upgrade to a slim Debian stretch running i3

Debian Stretch was released last month, so it is time to upgrade my laptop. I’m an i3 window manager user. Previously my procedure was to backup /home, reinstall using the network installer (I don’t like apt-get dist-upgrade, I like to start clean) and tick the “Debian Desktop Environment … GNOME” checkbox and after the installer was done, install i3 and the rest of my tools.

While I use some of the tools from Gnome, like gnome-terminal, network manager, nautilus and Eye of Gnome, I do not really need the complete Gnome desktop environment and 100s of software packages that come with it. This time I want a basic system with only the tools I need. And I want to upgrade in-place without losing my Debian jessie install.

Some notes about the installation:

  • It’s a Lenovo Thinkpad T450s
  • I currently have 2 partitions: 1 for /boot and the other is encrypted with luks
  • The encrypted partition contains 3 logical volumes for /, /home and swap
  • A 4th lv (logical volume) will be created for the new root partition for Debian stretch
  • The new lv will be BTRFS formatted and I’ll use a BTRFS subvolume to be able to create snapshots of it
  • The minimal required software will be installed to run the i3 window manager, including some tools I regularly use.

Let’s prepare the root volume:

VG=bento # my lvm2 volume group is called bento
LV=stretch # the new lv will be called stretch
LABEL=stretch # label for btrfs

lvcreate -L10G -n $LV $VG
mkfs.btrfs -L $LABEL /dev/$VG/$LV

mkdir /mnt/$LV
mount /dev/$VG/$LV /mnt/$LV
cd /mnt/$LV
# create the root subvolume
btrfs subvolume create @
cd -
umount /mnt/$LV
# mount the subvolume instead
mount -o subvol=/@ /dev/$VG/$LV /mnt/$LV

The boot partition (/boot) will be reused/shared between the current Debian jessie install and the new stretch install. Because I still use Debian jessie daily for my work, I still want to be able to boot jessie as a fallback. To see what happens to /boot/grub and especially /boot/grub/grub.cfg I will make a git repository in /boot/grub.

cd /boot/grub
git init
git add -A .
git commit -am 'grub at the time jessie was still installed'

Let’s start with the install:

/usr/sbin/debootstrap --include udev,openssh-server,linux-image-amd64 stretch /mnt/$LV http://deb.debian.org/debian/

# the new system needs to know about the encrypted partition, so copy crypttab
cp /etc/crypttab /mnt/$LV/etc/crypttab

# configure /mnt/$LV/etc/fstab
# example contents (replace $UUID with the uuid of /boot, replace $LABEL with the btrfs label)
UUID=$UUID /boot ext4 defaults 0 2
LABEL=$LABEL / btrfs subvol=/@,defaults,noatime 0 0
LABEL=$LABEL /btrfs-root btrfs subvol=/,defaults,noatime 0 0
# optionally add the existing mountpoint for /home

# The root of the BTRFS filesystem is mounted at `/btrfs-root`. From here we can manage the subvolumes and snapshots
mkdir /mnt/$LV/btrfs-root

# chroot into the new system
mount -o bind /boot /mnt/$LV/boot/
mount -o bind /dev /mnt/$LV/dev/
mount -t proc proc /mnt/$LV/proc
mount -t sysfs sys /mnt/$LV/sys
chroot /mnt/$LV

# set a root password
passwd
# create a normal user account
adduser pommi

# we do not want recommended packages to be installed automatically
echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/00InstallRecommends

# stable and security updates
cat > /etc/apt/sources.list <<EOT
deb http://deb.debian.org/debian stretch main contrib non-free
deb http://deb.debian.org/debian stretch-updates main contrib non-free
deb http://security.debian.org/ stretch/updates main contrib non-free
EOT
apt-get update
apt-get upgrade

# install some basics
apt-get install cryptsetup lvm2 locales busybox less grub-pc git vim-nox initramfs-tools btrfs-progs

# starting on Debian Buster also install
apt-get install cryptsetup-initramfs

# set the default locale (to for example en_US.UTF-8)
dpkg-reconfigure locales

# set the timezone
dpkg-reconfigure tzdata

The basics are done. Now install the Desktop Environment. To graphically login after booting I chose lightdm, which is a lightweight display manager. Gnome comes with gdm (Gnome Display Manager), but that installs ~87 another software packages I don’t want.

# suckless-tools for dmenu, x11-xserver-utils for xrandr
apt-get install lightdm i3 i3status suckless-tools xserver-xorg x11-xserver-utils

# networking, including wifi, gnome-keyring to store wifi passwords
apt-get install network-manager-gnome firmware-iwlwifi firmware-linux gnome-keyring

# and a terminal and a browser
apt-get install gnome-terminal firefox-esr

The system is now ready. Let’s check the changes in /boot/grub before we reboot.

cd /boot/grub
git status
git diff
# commit the changes
git add -A .
git commit -m 'after installing stretch'

In my case I had (at least) 2 kernels present in /boot. An active one for jessie (/vmlinuz-3.16.0-4-amd64) and a new one for stretch (/vmlinuz-4.9.0-3-amd64). When update-grub was executed from stretch just now, it changed all the grub menu items to boot into the new stretch system (every “linux” line now contains: root=/dev/mapper/$VG-$LV). To be able to still boot to jessie, I revert the changes for the “linux” lines that are supposed to boot the jessie system (/vmlinuz-3.16.0-4-amd64 kernels).

For example, change this:

linux /vmlinuz-3.16.0-4-amd64 root=/dev/mapper/bento-stretch ro quiet

back to (“root” is my current root lv):

linux /vmlinuz-3.16.0-4-amd64 root=/dev/mapper/bento-root ro quiet

And commit the result:

git add grub.cfg
git commit -m 'boot jessie with the old kernel'

Time to reboot to stretch

# exit the chroot
exit
umount /mnt/$LV/sys
umount /mnt/$LV/proc
umount /mnt/$LV/dev/
umount /mnt/$LV/boot/
umount /mnt/$LV
reboot

Lightdm will start and show you a login screen. Login using the normal user you just created an i3 will start.

Additional software and configuration

Lock screen (Ctrl+Alt+l and after 5 minutes):

apt-get install i3lock xautolock
echo 'exec xautolock -time 5 -locker i3lock' >> .config/i3/config
echo 'bindsym Control+$alt+l exec xautolock -locknow' >> .config/i3/config

Start Network Manager Applet on startup

echo 'exec --no-startup-id nm-applet' >> .config/i3/config

Open urls from gnome-terminal in firefox:

apt-get install xdg-utils
xdg-settings get default-web-browser
xdg-settings set default-web-browser firefox-esr.desktop

Comments