Skip to content

Instantly share code, notes, and snippets.

@varqox
Last active October 27, 2024 21:16
Show Gist options
  • Save varqox/42e213b6b2dde2b636ef to your computer and use it in GitHub Desktop.
Save varqox/42e213b6b2dde2b636ef to your computer and use it in GitHub Desktop.
Instructions how to install Debian using debootstrap

Instructions how to install Debian using debootstrap. Below instructions were verified to work with debootstrapping Debian 11.

Table of contents

  1. Conventions
  2. Essential steps
    1. Install debootstrap
    2. Prepare disk for installing boot loader
    3. Set up filesystem for Debian
    4. Mount filesystem
    5. Install base system
    6. Chroot into installed base system
    7. Set up editor
    8. Edit fstab file
    9. Configure apt sources
    10. Choose timezone
    11. Configure locales
    12. Install kernel
    13. Install firmware
    14. Set hostname
    15. Configure networking
    16. Install boot loader
    17. Set root's password
  3. Optional steps
    1. Install ssh-server
    2. Create an unprivileged user
    3. Install additional software
    4. Configure console keyboard layout
  4. Finish installation
    1. Precautionary reboot
      1. Boot the old system by default
      2. Make kernel reboot after kernel panic
      3. Delayed reboot after startup
      4. On the next boot, boot the new system once
    2. Install boot loader to disk
    3. Exit chroot
    4. Unmount /mnt
    5. Reboot into the new system

Conventions

  • /dev/PARTITION: replace it with the partition where Debian is to be installed e.g. /dev/sda2 or /dev/sdb1
  • /mnt: mountpoint for /dev/PARTITION, you can change it to something else
  • /dev/GRUBDISK: the disk on which you want grub to be installed e.g. /dev/sda (don't confuse it with a partition e.g. /dev/sda1)

Essential steps

Install debootstrap

Prepare work directory, e.g:

cd /tmp

Go https://deb.debian.org/debian/pool/main/d/debootstrap/?C=M;O=D and download latest debootstrap_X.X.X_all.deb, e.g.:

wget 'https://deb.debian.org/debian/pool/main/d/debootstrap/debootstrap_1.0.124_all.deb'

Then install it:

dpkg -i debootstrap_*.*.*_all.deb

Prepare disk for installing boot loader

BIOS systems require different steps than UEFI systems.

BIOS systems

If you intend to boot the system you will need a boot loader and it needs a place on disk (see step Install boot loader to disk).

First check what is the partition table using either fdisk or parted:

  • fdisk /dev/GRUBDISK -l and look for Disklabel type:.
    • Disklabel type: gpt means GPT.
    • Disklabel type: dos means MBR.
    • no Disklabel type: probably means partition table is missing.
  • parted /dev/GRUBDISK print and look for Partition Table:
    • Partition Table: gpt means GPT.
    • Partition Table: msdos means MBR.
    • Partition Table: unknown probably means partition table is missing.

GPT specific instructions

GRUB needs unformatted BIOS boot partition (see: https://wiki.archlinux.org/title/GRUB#GUID_Partition_Table_(GPT)_specific_instructions). This partition should be big enough, but around 1000 KiB should suffice. To make one you can use e.g. gdisk:

apt install gdisk
gdisk /dev/GRUBDISK

In gdisk, to make some partition a BIOS boot partition, change its type to ef02.

Below is an example of how one can partition the whole disk e.g. /dev/vda (has Logical block size = 512 bytes; first created partition is BIOS boot partition, second is a partition for the new Debian):

[root@debian10:~]# gdisk /dev/vda
GPT fdisk (gdisk) version 1.0.3

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

Command (? for help): x

Expert command (? for help): l
Enter the sector alignment value (1-65536, default = 2048): 1
Warning: Setting alignment to a value that does not match the disk's
physical block size! Performance degradation may result!
Physical block size = 4096
Logical block size = 512
Optimal alignment = 8 or multiples thereof.

Expert command (? for help): m

Command (? for help): n
Partition number (1-128, default 1): 42
First sector (34-20971486, default = 34) or {+-}size{KMGTP}: 34
Last sector (34-20971486, default = 20971486) or {+-}size{KMGTP}: 2047
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): ef02
Changed type of partition to 'BIOS boot partition'

Command (? for help): n
Partition number (1-128, default 1):
First sector (2048-20971486, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-20971486, default = 20971486) or {+-}size{KMGTP}:
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'

Command (? for help): p
Disk /dev/vda: 20971520 sectors, 10.0 GiB
Sector size (logical/physical): 512/4096 bytes
Disk identifier (GUID): 2819ACC4-D83C-4DBC-AA01-C517C36A6A7B
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 20971486
Partitions will be aligned on 1-sector boundaries
Total free space is 0 sectors (0 bytes)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048        20971486   10.0 GiB    8300  Linux filesystem
  42              34            2047   1007.0 KiB  EF02  BIOS boot partition

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/vda.
The operation has completed successfully.

MBR specific instructions

The post-MBR gap (between MBR region and the start of the first partition) should be enough for GRUB, so you don't have to do anything.

If your first partition starts at 1 MiB (you can check it using fdisk /dev/GRUBDISK -l or parted /dev/GRUBDISK print; one sector = logical sector size), then all should be fine. Otherwise you may need to make the beginning of the first partition have bigger offset.

UEFI systems

TODO

For more information check out: https://wiki.debian.org/UEFI and https://wiki.archlinux.org/title/GRUB#UEFI_systems (should be more helpful).


For more information about setting up GRUB see: https://wiki.archlinux.org/title/GRUB

Set up filesystem for Debian

E.g.

mkfs.ext4 /dev/PARTITION

Mount filesystem

mount /dev/PARTITION /mnt

Install base system

Usage: debootstrap --arch ARCH RELEASE DIR MIRROR E.g.

debootstrap --arch amd64 stable /mnt https://deb.debian.org/debian

Chroot into installed base system

mount --make-rslave --rbind /proc /mnt/proc
mount --make-rslave --rbind /sys /mnt/sys
mount --make-rslave --rbind /dev /mnt/dev
mount --make-rslave --rbind /run /mnt/run
chroot /mnt /bin/bash

Set up editor

  • nano: should already be there as default
  • vim:
    apt install vim
    update-alternatives --config editor
    E.g. I chose /usr/bin/vim.basic.
  • others: proceed analogously to vim

Edit fstab file

It is not recommended to name partitions by kernel name e.g. /dev/sda1, as they may change. One of the alternatives is UUID. To get UUID of /dev/PARTITION you can use:

lsblk -f /dev/PARTITION

To edit /etc/fstab use:

editor /etc/fstab

E.g. /etc/fstab based on the one produced by Debian 11 installer:

# /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).
#
# systemd generates mount units based on this file, see systemd.mount(5).
# Please run 'systemctl daemon-reload' after making changes here.
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
UUID=f80d9192-2bd3-466b-8c5f-ac10614e1d3d       /       ext4    errors=remount-ro       0 1

To make life easier you can do:

lsblk -f /dev/PARTITION >> /etc/fstab
editor /etc/fstab

For more details see: man fstab

Configure apt sources

Fill /etc/apt/sources.list:

apt install lsb-release
CODENAME=$(lsb_release --codename --short)
cat > /etc/apt/sources.list << HEREDOC
deb https://deb.debian.org/debian/ $CODENAME main contrib non-free
deb-src https://deb.debian.org/debian/ $CODENAME main contrib non-free

deb https://security.debian.org/debian-security $CODENAME-security main contrib non-free
deb-src https://security.debian.org/debian-security $CODENAME-security main contrib non-free

deb https://deb.debian.org/debian/ $CODENAME-updates main contrib non-free
deb-src https://deb.debian.org/debian/ $CODENAME-updates main contrib non-free
HEREDOC

Then check if everything is as you like:

editor /etc/apt/sources.list

Finally, run:

apt update

For more details see: https://wiki.debian.org/SourcesList

Choose timezone

dpkg-reconfigure tzdata

Configure locales

apt install locales
dpkg-reconfigure locales

E.g. select en_US.UTF-8, then C.UTF-8.

Install kernel

To boot the system you will need Linux kernel and a boot loader. You can search available kernel images by running:

apt search linux-image

Then install your chosen kernel image, e.g.:

apt install linux-image-amd64

Install firmware

apt install firmware-linux

Set hostname

Set hostname e.g.:

echo "MY_HOSTNAME" > /etc/hostname

where MY_HOSTNAME is the hostname you want to set.

Then update /etc/hosts:

cat > /etc/hosts << HEREDOC
127.0.0.1 localhost
127.0.1.1 $(cat /etc/hostname)

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
HEREDOC

Configure networking

Simpler option: NetworkManager

apt install network-manager

For more details see: https://wiki.debian.org/NetworkManager

Other option: network interfaces

Warning: I had trouble with physically disconnecting and reconnecting Ethernet cables while using this method. With NetworkManager everything works seamlessly.

First take a look at examples in /usr/share/doc/ifupdown/examples/network-interfaces and then write your config:

editor /etc/network/interfaces

or create drop-in files in /etc/network/interfaces.d/ directory and write your configs there.

Enter your nameserver(s) and search directives in /etc/resolv.conf:

editor /etc/resolv.conf

A simple example /etc/resolv.conf:

search hqdom.local
nameserver 1.1.1.1
nameserver 9.9.9.9

For more detailed instructions see: https://wiki.debian.org/NetworkConfiguration

Install boot loader

apt install grub2

This will not overwrite the current grub installation on disk, we will do it at the very end of these instructions.

Set root's password

passwd

Optional steps

Install ssh-server

apt install openssh-server

Remember that an unprivileged user has to be created because, by default ssh'ing onto root is forbidden.

Create an unprivileged user

Create user and set password:

useradd USERNAME -m
passwd USERNAME

Replace USERNAME with username of an user you want to create.

(Optional) If you intend to use sudo:

  • Install sudo:
    apt install sudo
  • Add the new user to group sudo:
    usermod -aG sudo USERNAME

Install additional software

E.g.

tasksel install standard

To get list of all available tasks use:

tasksel --list-tasks

Configure console keyboard layout

apt install console-setup console-setup-linux

To change layout:

dpkg-reconfigure keyboard-configuration
systemctl restart console-setup

E.g. I select Generic 105-key PC (intl.) > Polish - Polish (programmer Dvorak).

Enable os_prober in grub

This will make grub search for and add to menu other systems like Windows or other Linux distribution.

(cat /etc/default/grub; echo GRUB_DISABLE_OS_PROBER=false) | sudo tee /etc/default/grub && sudo update-grub

Finish installation

Precautionary reboot

It would be great if the machine rebooted into the old system when something goes wrong with the new system. This is attainable to some degree.

If you can reboot machine physically or remotely if e.g. kernel malfunctions and have access to grub menu during boot, then below steps are unnecessary for you.

Boot the old system by default

First, set GRUB_DEFAULT to saved:

editor /etc/default/grub

or just run:

sed -i 's/^GRUB_DEFAULT=.*/GRUB_DEFAULT=saved/' /etc/default/grub

After that:

update-grub

Now, list all entries in grub menu:

grep -Pi "menu.* '" /boot/grub/grub.cfg | sed "s/' .*/'/g" | ( \
    IFS=""; A=-1; B=0; \
    while read x; do \
        echo "$x" | grep "^\s" -q && \
            { echo -e "$A>$B\t$x"; B=$((B+1)); } || \
            { A=$((A+1)); B=0; echo -e "$A\t$x"; }; \
    done)

E.g. output:

0   menuentry 'Debian GNU/Linux'
1   submenu 'Advanced options for Debian GNU/Linux'
1>0     menuentry 'Debian GNU/Linux, with Linux 5.10.0-9-amd64'
1>1     menuentry 'Debian GNU/Linux, with Linux 5.10.0-9-amd64 (recovery mode)'
2   menuentry 'Debian GNU/Linux 10 (buster) (on /dev/sda1)'
3   submenu 'Advanced options for Debian GNU/Linux 10 (buster) (on /dev/sda1)'
3>0     menuentry 'Debian GNU/Linux (on /dev/sda1)'
3>1     menuentry 'Debian GNU/Linux, with Linux 4.19.0-18-amd64 (on /dev/sda1)'
3>2     menuentry 'Debian GNU/Linux, with Linux 4.19.0-18-amd64 (recovery mode) (on /dev/sda1)'
3>3     menuentry 'Debian GNU/Linux, with Linux 4.19.0-11-amd64 (on /dev/sda1)'
3>4     menuentry 'Debian GNU/Linux, with Linux 4.19.0-11-amd64 (recovery mode) (on /dev/sda1)'

Now we want grub to always boot the old system by default.

To set default system use grub-set-default 'NUM' where NUM is the number from the first column e.g.

  • For Debian GNU/Linux 10 (buster) (on /dev/sda1) use:
    grub-set-default '2'
  • For Debian GNU/Linux, with Linux 4.19.0-18-amd64 (on /dev/sda1) use:
    grub-set-default '3>1'

Remember to change this if the new system boots successfully and you want it to be the default system e.g. grub-set-default '0'

For more details see: https://wiki.debian.org/GrubReboot#With_GRUB_v2

Make kernel reboot after kernel panic

Now tell kernel to reboot after 10 seconds if kernel panic happens.

Edit /etc/default/grub and append panic=10 to GRUB_CMDLINE_LINUX e.g. GRUB_CMDLINE_LINUX="panic=10":

editor /etc/default/grub

Then

update-grub

Delayed reboot after startup

To set the system to reboot after 30 seconds if something goes wrong, create systemd service and timer to trigger it and enable the timer:

cat > /etc/systemd/system/precautionary-reboot.service << 'HEREDOC'
[Service]
Type=oneshot
ExecStart=/bin/systemctl reboot
HEREDOC
cat > /etc/systemd/system/precautionary-reboot.timer << 'HEREDOC'
[Timer]
OnBootSec=30sec
AccuracySec=1sec

[Install]
WantedBy=timers.target
HEREDOC
systemctl enable precautionary-reboot.timer

Remember to disable this if the new system boots successfully: systemctl disable --now precautionary-reboot.timer

On the next boot, boot the new system once

Now tell GRUB to choose (only on the next boot) the new system using grub-reboot 'NUM' e.g. booting Debian GNU/Linux:

grub-reboot '0'

For more details see: https://wiki.debian.org/GrubReboot#With_GRUB_v2

Install boot loader to disk

Warning: this step overwrites the current grub installation

update-grub && grub-install --root-directory / /dev/GRUBDISK

where /dev/GRUBDISK is the disk on which you want grub to be installed e.g. /dev/sda (don't confuse it with a partition which is e.g. /dev/sda1).

Exit chroot

exit

Unmount /mnt

umount -R /mnt

Reboot into the new system

reboot
@balk77
Copy link

balk77 commented Jul 18, 2023

Excellent guide! Thanks.

Maybe good to add this to the Grub section? It makes Grub find other installations as well. See this.
sudo echo GRUB_DISABLE_OS_PROBER=false >> /etc/default/grub && sudo update-grub

@varqox
Copy link
Author

varqox commented Jul 18, 2023

@lightvision
Copy link

lightvision commented Sep 9, 2023

I will advise you to use genfstab for fstab generation, before entering the chroot:

genfstab -U > /mnt/etc/fstab

Otherwise thank you.

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