Skip to content

Instantly share code, notes, and snippets.

@raphendyr
Last active May 13, 2025 19:21
Show Gist options
  • Save raphendyr/0e96f9b4f1d675be30715e9eb6bbb6b1 to your computer and use it in GitHub Desktop.
Save raphendyr/0e96f9b4f1d675be30715e9eb6bbb6b1 to your computer and use it in GitHub Desktop.
Instructions on installing Debian manually with full control. Desktop, laptop or VM.

Installing Linux

This gist is my notebook about how to setup Linux machine to my liking. The setup assumes full disk encryption.

Due to partitioning and encryption, I have come to conclude I need to do this manually. However, I'm happy to remove parts of the this page, as long as there is better way to do it.

Please note that Debian and Arch Linux have more comprehensive guides.

Installing Linux

Live environment

Grap a live linux with the preferred flavour and boot it.

Debian Live: https://www.debian.org/CD/live/

Arch Linux live: https://archlinux.org/download/

Enable SSH for VM and KVM over IP

Debian

sudo -i # if not root
apt update
apt install openssh-server
# add password for Debian live user
passwd user

Connect to it

ssh <ip-address> -l user -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
# in the server over the ssh
sudo -i
Fix link MTU if wrong
# find route mtu
ip route
# set link mtu
ip link set <dev> mtu <mtu>
ifdown <dev> ; ifup <dev>

Arch Linux

TODO

Prepare Storage

1. Prepare

Create a memory storage for secure files.

mkdir -p /prepare
mount -t tmpfs none /prepare

Install packages.

Debian

apt update
apt install -y cryptsetup gdisk dosfstools
apt install -y mdadm # if you are going to use raid

Arch Linux

TODO

Stop all RAIDs, if those were autodetected.

mdadm --stop --scan

Change the Live Linux's hostname to the target

hostnamectl # status
hostnamectl set-hostname <name>

2. Ensure you have correct devices

fdisk -l /dev/sd? /dev/nvme?n?

If you will do RAID, start partition from the smaller device (SSD/NVMe have tiny size differences).

4. Partition disks (use GPT)

The root partition is for OS and the home is for user files, but you may use a single partition instead (i.e., root). The home could be on another device too.

Note that *fdisk and *gdisk tools are used for their specific purposes. Some features are not available in fdisk family yet.

  • The partition label can't be set with fdisk tools. Partition labels are not very relevant though. However, sfdisk does copy labels.
  • The partition type Linux LUKS can't be set with cfdisk. You can set partition type with sfdisk --part-type /dev/correct-disk <partition-number> <GUID>.
  • When partitions are copied to another device, there is no tool in fdisk to reset GPT partition IDs.

See Arch wiki about partition types.

  • If you setup RAID, use Linux RAID, gdisk fd00, GUID A19D880F-05FC-4D3B-A006-743F0F84911E) for root and home partitions.
  • For encrypted disks, use Linux LUKS gdisk 8309, GUID CA7D7CCB-63ED-4C53-861C-1742536059CC. This is good for swap too, as TPM and other alternative unlocking requires secondary key slots. There is also Linux dm-crypt, 8308, 7FFEC5C9-2D00-49B7-8941-3EA10A5586B7 for non-LUKS uses.

4.1. For EFI systems with shared EFI and /boot

See Arch wiki for details about EFI and /boot.

cgdisk /dev/correct-disk
# purpose size  Type        gdisk   GUID
# ESP       4G  EFI System  ef00    C12A7328-F81F-11D2-BA4B-00A0C93EC93B
# root    >30G  Linux LUKS  8309    CA7D7CCB-63ED-4C53-861C-1742536059CC
# home      nG  Linux LUKS  8309    CA7D7CCB-63ED-4C53-861C-1742536059CC
# swap   8-64G  Linux LUKS  8309    CA7D7CCB-63ED-4C53-861C-1742536059CC

Verify

# Verify
sfdisk --verify /dev/correct-disk
sgdisk --verify /dev/correct-disk

4.2. For EFI systems with separate EFI and /boot

You may use purpose as the partition name

cgdisk /dev/correct-disk
# purpose size  Type        gdisk   GUID
# efi     512M  EFI System  ef00    C12A7328-F81F-11D2-BA4B-00A0C93EC93B
# boot      1G  XBOOTLDR    ea00    BC13C2FF-59E6-4262-A352-B275FD6F7172
# root    >30G  Linux LUKS  8309    CA7D7CCB-63ED-4C53-861C-1742536059CC
# home      nG  Linux LUKS  8309    CA7D7CCB-63ED-4C53-861C-1742536059CC
# swap   8-64G  Linux LUKS  8309    CA7D7CCB-63ED-4C53-861C-1742536059CC

For hibernation support, see Arch wiki.

4.3. For non-EFI systems (e.g., cloud VMs):

cgdisk /dev/correct-disk
# purpose size  GUID name       gdisk GUID
# grub    2M                    EF02  21686148-6449-6E6F-744E-656564454649
# boot    256M  XBOOTLDR        EA00  BC13C2FF-59E6-4262-A352-B275FD6F7172
# luks    >10G  Linux LUKS      8309  CA7D7CCB-63ED-4C53-861C-1742536059CC
# swap    1-4G  Linux dm-crypt  8308  7FFEC5C9-2D00-49B7-8941-3EA10A5586B7

You can start with following command, which will set the first 2 partitions nicely.

sfdisk /dev/correct-disk <<EOF
label: gpt
device: /d
unit: sectors
first-lba: 34

/d1 : start= 6144, size= 487424, type=BC13C2FF-59E6-4262-A352-B275FD6F7172, name="boot"
/d9 : start= 2048, size=   4096, type=21686148-6449-6E6F-744E-656564454649, name="grub"
EOF

4.4. For RAID systemd, copy partition table to second RAID disk

sfdisk --dump /dev/second-disk | sfdisk /dev/first-disk
sgdisk -G /dev/second-disk # --randomize-guids

Notice the order of arguments!

5. For RAID systems, create the RAID

# RAID for the root partition
mdadm -v -C /dev/md/root -e 1.2 -b internal -l 1 -n 2 /dev/first-device3 /dev/second-device3
# If you created home in the RAID disk
mdadm -v -C /dev/md/home -e 1.2 -b internal -l 1 -n 2 /dev/first-device4 /dev/second-device4
# When there is separate EFI and /boot, add v1.0 mirror for /boot
mdadm -v -C /dev/md/boot -e 1.0 -b none -l 1 -n 2 /dev/first-device2 /dev/second-device2

Note that we use version 1.0 for boot, so they can be read without using RAID, but we mount them with raid, so both disk have the same data when updated.

Note that we don't setup raid for EFI, as that device can be edited by multiple OSes and such. Instead, we will setup a copy hook later.

Converting plain disk to RAID later is quite hard, thus if you anticipate to add second disk later, you should create a single disk arrow now. To do that, replace -n 2 with --force -n 1. Later, you can add new disk with mdadm -a /dev/md/name /dev/second-deviceN and mdadm --frow -n 2 /dev/md/name.

Verify result with

cat /proc/mdstat

Prepare config

mkdir -p /prepare/mdadm
(sed '/ARRAY/d' /etc/mdadm/mdadm.conf; mdadm --detail --scan) | tee /prepare/mdadm/mdadm.conf

If the RAID home host gets broken, then mdadm --assemble /dev/md/root --update=homehost will fix it.

6. Setup crypto

The boot-up partitions won't be encrypted (EFI and boot). Therefore, run the following command for the other partitions (root, home and swap). Use RAID devices /dev/md1[34], if you created those.

Create key files.

for n in home swap; do
  dd bs=1024 count=1 if=/dev/random iflag=fullblock of=/prepare/crypttab_$n.key
  chmod 0400 /prepare/crypttab_$n.key
  ln -s /prepare/crypttab_$n.key /etc/crypttab_$n.key
done

Create a nice password with pwqgen or come up with one. I recommend to use multiple words and less special characters. Consider that you should be able to write the password when the keyboard layout is not correct (i.e., just letters, numbers, comma, dot and space).

cryptsetup --type luks2 --label "luks:root" luksFormat <root partition>
# Setup home
cryptsetup --type luks2 --label "luks:home" luksFormat <home partition>
cryptsetup luksAddKey <home partition> /prepare/crypttab_home.key
# Setup LUKS for swap partitions.
cryptsetup --type luks2 --label "luks:swap0" luksFormat <swap0 partition> /prepare/crypttab_swap.key
cryptsetup --type luks2 --label "luks:swap1" luksFormat <swap1 partition> /prepare/crypttab_swap.key

Add cryptdisks to crypttab

lsblk -o label,uuid,fstype,path | sort -u | awk '/ crypto_LUKS / { print $1, "UUID=" $2 " none luks,discard"}' | tee /prepare/crypttab

Edit the /prepare/crypttab file to look like:

root UUID=cryptdev-0000-0000-0000-aaaaaaaaaaaa none luks,discard
home UUID=cryptdev-0000-0000-0000-bbbbbbbbbbbb /etc/crypttab_home.key luks,discard
# repeat for every disk with swap
swap0 UUID=cryptdev-0000-0000-0000-bbbbbbbbbbbb /etc/crypttab_swap.key luks,discard

Open created devices

TABFILE=/prepare/crypttab cryptdisks_start root # requires password
TABFILE=/prepare/crypttab cryptdisks_start home # unlocks with key
# repeat for every swap
TABFILE=/prepare/crypttab cryptdisks_start swap0 # unlocks with key

7. Create filesystems and fstab

Create swaps

# repeat for every swap
mkswap -L swap0 /dev/mapper/swap0

Create actual filesystems

mkfs.ext4 -L boot </dev/correct-disk2 or /dev/md/boot>
mkfs.ext4 -L root /dev/mapper/root
mkfs.ext4 -L home -m 0 /dev/mapper/home
# repeat for every disk
mkfs.vfat -F 32 -n ESP0 /dev/disk1p1

Add all mounted filesystems to fstab

lsblk -o label,path,uuid,fstype -M | grep -E '(ext.|vfat|swap)$' | tee /prepare/fstab

Edit the /prepare/fstab file to look like:

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>

# root /dev/mapper/root
UUID=filesyst-em00-0000-0000-aaaaaaaaaaaa / ext4 defaults,user_xattr,lazytime,commit=30,errors=remount-ro 0 1
# home /dev/mapper/home
UUID=filesyst-em00-0000-0000-dddddddddddd /home ext4 defaults,user_xattr,lazytime,nodev,nosuid,commit=30 0 2

## If only one EFI/boot
# ESP0 /dev/disk0p1 - first disk goes to /boot
UUID=DEAD-B11F /boot vfat defaults,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed 0 2
# ESP1 /dev/disk1p1 - rest go to /boot-N
UUID=DEAD-B22F /boot-1 vfat defaults,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed 0 2

## If separate /boot
# boot /dev/disk0p2 - mount the ext to /boot
UUID=filesyst-em00-0000-0000-bbbbbbbbbbbb /boot ext4 defaults,lazytime,nodev,nosuid,noexec,commit=60 0 2
# repeat for every efi device
# EFI0 /dev/disk0p1 - mount the efi to /efi, and rest to /efi-N
UUID=DEAD-BEEF /efi vfat defaults,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed 0 2

## repeat for every swap device
# swap0 /dev/mapper/swap0 - LUSK swaps have UUID
UUID=4f0a2053-0823-4669-8e75-014726676ff7 none swap sw 0 0

8. Prepare filesystems for chroot

Copy it for chroot mounting

cp /prepare/fstab /target.fstab

Edit /target.fstab to look like, i.e., prefix paths, drop swaps and add system mounts.

UUID=filesyst-em00-0000-0000-aaaaaaaaaaaa /target ext4 defaults,user_xattr,lazytime,commit=30,errors=remount-ro 0 1
UUID=filesyst-em00-0000-0000-dddddddddddd /target/home ext4 defaults,user_xattr,lazytime,nodev,nosuid,commit=30 0 2

## If only one EFI/boot
UUID=DEAD-B11F /target/boot vfat defaults,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed 0 2
UUID=DEAD-B22F /target/boot-1 vfat defaults,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed 0 2

## If separate /boot
UUID=filesyst-em00-0000-0000-bbbbbbbbbbbb /target/boot ext4 defaults,lazytime,nodev,nosuid,noexec,commit=60 0 2
UUID=DEAD-BEEF /target/efi vfat defaults,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed 0 2
UUID=DEAD-BEEF /target/efi-1 vfat defaults,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed 0 2

run /target/run tmpfs defaults 0 0
sys /target/sys sysfs defaults 0 0
udev /target/dev devtmpfs defaults 0 0
dpts /target/dev/pts devpts defaults 0 0
proc /target/proc proc defaults 0 0
efivars /target/sys/firmware/efi/efivars efivarfs defaults

Mount root filesystem

mkdir -p /target
mount -T /target.fstab /target

Installing Debian

Install base system

1. download tools

apt install -y debootstrap

2. setup apt info

release="$(lsb_release -c -s)"
nameserver="$(host -t PTR $(awk '/^nameserver/ {print $2; exit}' /etc/resolv.conf))"
nameserver="${nameserver%.}"
mirror=https://deb.debian.org/debian
case "$nameserver" in
    *ovh.net) mirror=https://debian.mirrors.ovh.net/debian ;;
    *hetzner.de) mirror=https://mirror.hetzner.com/debian/packages ;;
    *.[a-z][a-z])
        domain="ftp.${nameserver##*.}.debian.org"
        host -W 1 "$domain" &>/dev/null && mirror="https://$domain/debian" ;;
esac
echo $mirror $release

3. install with debootstrap

debootstrap \
  --components=main,contrib,non-free \
  --include=curl \
  $release /target $mirror \
  || echo "Installation failed: exit=$?"

4. setup a minimal level of the base system

cat > /target/etc/apt/sources.list <<EOF
deb $mirror $release main contrib non-free
deb $mirror $release-updates main contrib non-free
deb https://security.debian.org/debian-security $release-security main contrib non-free
EOF

cp -a /prepare/* /target/etc/

5. mount rest of the filesystem

awk '/#/ {next}; $2 ~ /\/target\// {print length($2), $2}' /target.fstab | sort -n | while read l p; do
  mkdir -p $p && mount -T /target.fstab $p
done

NOTE: above is required only for the first time. If you need to remount disks, following is enough. However remember that /target.fstab doesn't persist over reboots on live installers and rescue systems.

mount -T /target.fstab -a

6. enter chroot

cp /etc/resolv.conf /target/etc/resolv.conf
LANG=C.UTF-8 chroot /target /bin/bash

7. (optional) install deb.n-1.fi private repo and install base system packages

# in chroot
curl -sSLo /run/nm1.deb https://deb.n-1.fi/archive-keyring.deb
dpkg -E -i /run/nm1.deb
rm /run/nm1.deb

apt update
# basic desktop:
apt install blend-n-1.fi-desktop blend-n-1.fi-efi-amd64
# basic VPS:
apt install blend-n-1.fi-shell blend-n-1.fi-vps-amd64 openssh-server
# basic HW server
apt install blend-n-1.fi-shell blend-n-1.fi-efi-amd64 openssh-server

# remove recommends:
apt remove os-prober

8. (alternative) install required packages manually

Check content of above packages from the web site to get up-to-date idea what to install.

# in chroot
apt update
# blend-n-1.fi-efi-amd64
apt install console-setup grub-efi grub-theme-breeze linux-image-amd64
# blend-n-1.fi-basesystem
apt install cryptsetup cryptsetup-initramfs locales sudo
apt install apt-listchanges apt-utils e2fsprogs gawk gzip less lz4 p7zip pv systemd systemd-cron systemd-sysv
# consider these
apt install ipset lm-sensors openssh-client passwdqc rsync unattended-upgrades vlan

9. Configure system

# configure locales
dpkg-reconfigure locales

10. Configure users and permissions

# Add password for root
passwd

# Create user
adduser user
adduser user ssh
adduser user sudo

11. Setup networking

Configure network device, if needed

cat > /etc/systemd/network/ether.network <<EOF
# see https://wiki.debian.org/SystemdNetworkd

[Match]
Name=enp*
Type=ether

[Link]
#MTUBytes=9000

[Network]
DHCP=ipv4
# Use this if you want to force DHCP-Registration with
# the MAC-Address instead of duid (DHCP Unique Identifier)
# This way you can pre-assign them in your DHCPD.
#ClientIdentifier=mac
EOF
# For servers, enable networkd
systemctl enable systemd-networkd

See Debian wiki and Arch wiki.

# If you installed ssh server, enable it.
systemctl enable ssh

12. Make system bootable (RAID, initramfs and grub)

# if you used RAID
apt install mdadm
# revreate initramfs and grub config
update-initramfs -u -k all
update-grub

13. Install grub

EFI:

(set -x; for d in $(mount -t vfat | awk '$3 ~ /boot|efi/ {print $3}' | sort -r); do
  i=${d##*-}; if [ "$i" = "$d" ]; then i=''; else i="-$i"; fi
  grub-install --efi-directory="$d" --bootloader-id="debian$i"
done)

Verify that boot entry was added correctly

efibootmgr

NOTE: if above fails, then add boot entry manually

 efibootmgr -c -d /dev/disk-with-boot -L Debian -l \\EFI\\debian\\grubx64.efi

Non-EFI:

grub-install /dev/correct-device

Clean and reboot

Exit the chroot

exit

Umount target

umount -R /target

Stop cryptdisks

cryptdisks_stop root
cryptdisks_stop home
# repeat for every swap
cryptdisks_stop swap0

Reboot...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment