Table of Contents

Bare metal server provisioning (debian trixie)

Install of a Debian 13 (Trixie) on a dedicated server with:

Target disk layout

nvme0n1 (419 Go)              nvme1n1 (419 Go)
├── p1 : 512 Mo ESP           ├── p1 : 512 Mo ESP (copy)
├── p2 : 512 Mo ────┐         ├── p2 : 512 Mo ────┐
│                   ├── md0 (RAID1) → /boot (ext4)
└── p3 : ~418 Go ───┤         └── p3 : ~418 Go ───┤
                    └── md1 (RAID1) → LUKS → LVM (vg0)
                                                 ├── root (10 Go, ext4)
                                                 └── thin pool

Procedure

1. Boot in rescue mode

2. Disk setup

$ apt update
$ apt install -y mdadm cryptsetup lvm2 parted debootstrap gdisk rsync
 
# Cleanup (/!\ this delete all data on disks /!\)
$ mdadm --stop --scan
$ mdadm --zero-superblock /dev/nvme0n1 2>/dev/null
$ mdadm --zero-superblock /dev/nvme1n1 2>/dev/null
$ wipefs -a /dev/nvme0n1 /dev/nvme1n1
$ sgdisk --zap-all /dev/nvme0n1
$ sgdisk --zap-all /dev/nvme1n1
 
# GPT partitioning on both disks
$ for D in /dev/nvme0n1 /dev/nvme1n1; do
  sgdisk -n 1:0:+512M -t 1:ef00 -c 1:"EFI"       $D
  sgdisk -n 2:0:+512M -t 2:fd00 -c 2:"boot RAID" $D
  sgdisk -n 3:0:0     -t 3:fd00 -c 3:"luks RAID" $D
done
 
$ partprobe

3. RAID1 mdadm

$ mdadm --create /dev/md0 \
  --level=1 --raid-devices=2 --metadata=1.2 \
  --homehost=schwartz --name=boot \
  /dev/nvme0n1p2 /dev/nvme1n1p2
 
$ mdadm --create /dev/md1 \
  --level=1 --raid-devices=2 --metadata=1.2 \
  --homehost=schwartz --name=cryptroot \
  /dev/nvme0n1p3 /dev/nvme1n1p3

4. LUKS on md1

$ cryptsetup luksFormat --type luks2 --iter-time 5000 /dev/md1
$ cryptsetup open /dev/md1 cryptroot

Passphrase generated with pass generate luks/schwartz 30 –no-symbols and stored in password-store.

5. LVM

$ pvcreate /dev/mapper/cryptroot
$ vgcreate vg0 /dev/mapper/cryptroot
$ lvcreate -L 10G -n root vg0

6. Formatting & partitions setup

$ mkfs.vfat -F32 -n EFI0 /dev/nvme0n1p1
$ mkfs.vfat -F32 -n EFI1 /dev/nvme1n1p1
$ mkfs.ext4 -L boot /dev/md0
$ mkfs.ext4 -L root /dev/vg0/root
 
$ mount /dev/vg0/root /mnt
$ mkdir -p /mnt/boot
$ mount /dev/md0 /mnt/boot
$ mkdir -p /mnt/boot/efi
$ mount /dev/nvme0n1p1 /mnt/boot/efi

7. Debootstrap

$ debootstrap --arch amd64 trixie /mnt http://deb.debian.org/debian/

8. Chroot setup

$ for d in dev dev/pts proc sys run; do
  mount --bind /$d /mnt/$d
done
$ mount --bind /sys/firmware/efi/efivars /mnt/sys/firmware/efi/efivars
$ cp /etc/resolv.conf /mnt/etc/resolv.conf
 
# Get UUIDs
$ blkid -s UUID -o value /dev/md0          # BOOT_UUID
$ blkid -s UUID -o value /dev/vg0/root     # ROOT_UUID
$ blkid -s UUID -o value /dev/md1          # LUKS_UUID
$ blkid -s UUID -o value /dev/nvme0n1p1    # EFI0_UUID
$ blkid -s UUID -o value /dev/nvme1n1p1    # EFI1_UUID
 
$ chroot /mnt /bin/bash

9. Base configuration (in chroot)

# Hostname
$ echo "schwartz" > /etc/hostname
$ cat > /etc/hosts <<EOF
127.0.0.1   localhost
127.0.1.1   schwartz
::1         localhost ip6-localhost ip6-loopback
ff02::1     ip6-allnodes
ff02::2     ip6-allrouters
EOF
 
 
# Locales / timezone
$ apt update && apt install -y locales
$ echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
$ echo "fr_FR.UTF-8 UTF-8" >> /etc/locale.gen
$ locale-gen
$ echo "LANG=en_US.UTF-8" > /etc/default/locale
$ ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime
$ dpkg-reconfigure -f noninteractive tzdata
 
# APT setup
$ cat > /etc/apt/sources.list <<EOF
deb http://deb.debian.org/debian trixie main contrib non-free-firmware
deb http://security.debian.org/debian-security trixie-security main contrib non-free-firmware
deb http://deb.debian.org/debian trixie-updates main contrib non-free-firmware
EOF
$ apt update

10. Network configuration

$ apt install -y ifupdown
 
$ cat > /etc/network/interfaces <<EOF
auto lo
iface lo inet loopback
 
auto eno1
iface eno1 inet dhcp
EOF

11. crypttab, fstab, mdadm.conf

# crypttab
$ cat > /etc/crypttab <<EOF
cryptroot UUID=$LUKS_UUID none luks,initramfs,discard
EOF
 
# fstab
$ cat > /etc/fstab <<EOF
UUID=$ROOT_UUID  /          ext4  defaults,noatime,errors=remount-ro  0  1
UUID=$BOOT_UUID  /boot      ext4  defaults                            0  2
UUID=$EFI0_UUID  /boot/efi  vfat  umask=0077,defaults                 0  2
EOF
 
# mdadm.conf
$ apt install -y mdadm
$ cat > /etc/mdadm/mdadm.conf <<EOF
HOMEHOST <system>
MAILADDR root
EOF
$ mdadm --detail --scan >> /etc/mdadm/mdadm.conf

12. Kernel and boot tools

$ apt install -y \
  linux-image-amd64 \
  cryptsetup cryptsetup-initramfs \
  lvm2 \
  thin-provisioning-tools \
  intel-microcode \
  firmware-linux \
  initramfs-tools \
  openssh-server

13. GRUB UEFI

$ apt install -y grub-efi-amd64 efibootmgr
 
$ echo 'GRUB_ENABLE_CRYPTODISK=y' >> /etc/default/grub
 
$ grub-install --target=x86_64-efi \
             --efi-directory=/boot/efi \
             --bootloader-id=debian \
             --recheck
 
$ update-grub
 
# Sync ESP2
$ mkdir -p /tmp/efi2
$ mount /dev/nvme1n1p1 /tmp/efi2
$ cp -av /boot/efi/* /tmp/efi2/
$ umount /tmp/efi2
 
# UEFI fallback for ESP2
$ efibootmgr --create \
  --disk /dev/nvme1n1 --part 1 \
  --label "debian-backup" \
  --loader '\EFI\debian\shimx64.efi'
 
# Reorder to make debian (ESP1) as priority
$ efibootmgr -o 000A,000B,0003,0006,0007,0004,0005,0000,0001,0002
# (adapt IDs from `efibootmgr`)

14. User et SSH

$ passwd  # root password setup
 
$ adduser phil
$ usermod -aG sudo phil
 
# SSH key
$ mkdir -p /home/phil/.ssh
$ cat > /home/phil/.ssh/authorized_keys <<'EOF'
ssh-ed25519 AAAA... phil@host
EOF
$ chmod 700 /home/phil/.ssh
$ chmod 600 /home/phil/.ssh/authorized_keys
$ chown -R phil:phil /home/phil/.ssh
 
# sshd hardening
$ cat > /etc/ssh/sshd_config.d/10-hardening.conf <<EOF
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
EOF
 
$ systemctl enable ssh

15. Dropbear-initramfs

$ apt install -y dropbear-initramfs busybox
 
# Config dropbear : port 2222 and force cryptroot-unlock command
$ cat > /etc/dropbear/initramfs/dropbear.conf <<'EOF'
DROPBEAR_OPTIONS="-p 2222 -s -j -k -I 60 -c cryptroot-unlock"
EOF
 
# ssh key allowed to connect
$ cat > /etc/dropbear/initramfs/authorized_keys <<'EOF'
ssh-ed25519 AAAA... phil@host
EOF
$ chmod 600 /etc/dropbear/initramfs/authorized_keys
 
# network config for initramfs
cat >> /etc/initramfs-tools/initramfs.conf <<EOF
IP=xx.xx.xx.xx::gw.ad.dr.ess:255.255.255.0:schwartz:eno1:off
EOF
 
$ update-initramfs -u

16. reboot

$ exit  # exit chroot
 
$ umount /mnt/sys/firmware/efi/efivars
$ umount /mnt/boot/efi
$ umount /mnt/boot
$ umount /mnt/run
$ umount /mnt/sys
$ umount /mnt/proc
$ umount /mnt/dev/pts
$ umount /mnt/dev
$ umount /mnt
 
$ vgchange -an vg0
$ cryptsetup close cryptroot
$ mdadm --stop /dev/md0 /dev/md1
 
 
$ reboot

17. First boot and unlock

# Wait dropbear to be up
nc -zv xx.xx.xx.xx 2222
 
# remote unlocking oneliner:
pass show luks/schwartz | tr -d '\n' | ssh -p 2222 root@xx.xx.xx.xx cryptroot-unlock

After few seconds, normal SSD become available.