Instructions how to install Debian using debootstrap. Below instructions were verified to work with debootstrapping Debian 11.
- Conventions
- Essential steps
- Install debootstrap
- Prepare disk for installing boot loader
- Set up filesystem for Debian
- Mount filesystem
- Install base system
- Chroot into installed base system
- Set up editor
- Edit fstab file
- Configure apt sources
- Choose timezone
- Configure locales
- Install kernel
- Install firmware
- Set hostname
- Configure networking
- Install boot loader
- Set root's password
 
- Optional steps
- Finish installation
- /dev/PARTITION: replace it with the partition where Debian is to be installed e.g.- /dev/sda2or- /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)
Prepare work directory, e.g:
cd /tmpGo 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.debBIOS systems require different steps than UEFI 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 -land look for- Disklabel type:.- Disklabel type: gptmeans GPT.
- Disklabel type: dosmeans MBR.
- no Disklabel type:probably means partition table is missing.
 
- parted /dev/GRUBDISK printand look for- Partition Table:- Partition Table: gptmeans GPT.
- Partition Table: msdosmeans MBR.
- Partition Table: unknownprobably means partition table is missing.
 
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/GRUBDISKIn 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.
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.
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
E.g.
mkfs.ext4 /dev/PARTITIONmount /dev/PARTITION /mntUsage: debootstrap --arch ARCH RELEASE DIR MIRROR
E.g.
debootstrap --arch amd64 stable /mnt https://deb.debian.org/debianmount --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- nano: should already be there as default
- vim:E.g. I chose- apt install vim update-alternatives --config editor - /usr/bin/vim.basic.
- others: proceed analogously to vim
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/PARTITIONTo edit /etc/fstab use:
editor /etc/fstabE.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/fstabFor more details see: man fstab
Fill /etc/apt/sources.list:
apt install ca-certificates 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
HEREDOCThen check if everything is as you like:
editor /etc/apt/sources.listFinally, run:
apt updateFor more details see: https://wiki.debian.org/SourcesList
dpkg-reconfigure tzdata
apt install locales
dpkg-reconfigure localesE.g. select en_US.UTF-8, then C.UTF-8.
To boot the system you will need Linux kernel and a boot loader. You can search available kernel images by running:
apt search linux-imageThen install your chosen kernel image, e.g.:
apt install linux-image-amd64apt install firmware-linuxSet hostname e.g.:
echo "MY_HOSTNAME" > /etc/hostnamewhere 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
HEREDOCapt install network-managerFor more details see: https://wiki.debian.org/NetworkManager
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/interfacesor 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
apt install grub2This will not overwrite the current grub installation on disk, we will do it at the very end of these instructions.
passwdapt install openssh-serverRemember that an unprivileged user has to be created because, by default ssh'ing onto root is forbidden.
Create user and set password:
exec su -
useradd USERNAME -m
passwd USERNAMEReplace 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 
E.g.
tasksel install standardTo get list of all available tasks use:
tasksel --list-tasksapt install console-setup console-setup-linuxTo change layout:
dpkg-reconfigure keyboard-configuration
systemctl restart console-setupE.g. I select Generic 105-key PC (intl.) > Polish - Polish (programmer Dvorak).
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
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.
First, set GRUB_DEFAULT to saved:
editor /etc/default/grubor just run:
sed -i 's/^GRUB_DEFAULT=.*/GRUB_DEFAULT=saved/' /etc/default/grubAfter that:
update-grubNow, 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
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/grubThen
update-grubTo 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.timerRemember to disable this if the new system boots successfully: systemctl disable --now precautionary-reboot.timer
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
Warning: this step overwrites the current grub installation
update-grub && grub-install --root-directory / /dev/GRUBDISKwhere /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).
exitumount -R /mntreboot
Thanks, I updated the instructions.