How to Install Debian From Scratch

16th May 2025 • Marco Cetica

The Debian installer provides a versatile approach which allows users to cover most installation scenarios, from simple setups to advanced configurations. While it is perfectly suitable for the majority of use cases, certain situations require greater flexibility; for example, when it is required to manage specific phases of the installation process or when system options must diverge from the defaults provided by the standard installer.

If you ever find yourself in one of these latter situations, then this guide is for you. It describes how to install Debian entirely from scratch, without relying on the official installer, using only the debootstrap(8) utility.

In particular, we will cover three different installation scenarios:

  1. UEFI installation;
  2. BIOS installation;
  3. LUKS installation.

The former scenario is what you should typically follow for modern systems such as laptops or desktop computers. The second option should only be used on older systems that don't support UEFI or on virtual machines where you can choose which firmware to use. The last option, instead, shows you how to set up a LUKS encrypted Debian installation.

Prerequisites

Before getting started, get yourself a GNU/Linux distribution (for instance, a live distro) that includes the deboostrap(8) utility on its repositories. Both Debian, RHEL and Arch distributions offer this packages directly from their official repositories, making very easy to install it using the builtin package manager.

Be also sure to back up any important file and to double check each command you issue on your system. This guide will walk you through setting a Debian installation "à la Arch"; that is, by doing everything by hand. Therefore, it assumes a certain experience with UNIX-like systems and a certain ability to troubleshoot issues on your own.

This guide was written and tested against the latest release of Debian stable and I will update it regularly to ensure maximum compatibility with each major release.

Disk Partition

As stated before, we can follow three different ways to install Debian; each of them will result in a different partition layout. Let's see them.

UEFI layout

In this case, we need to reserve at least 100 MiB for the EFI partition, though you may allocate more space if you also plain to store the kernel and the initial ramdisk there. The rest of the disk can be used for the base system using any partition scheme of your choice. To keep things as simple as possible, I will keep everything in a single root partition:

Name Type Mount Point Size
/dev/sda1 EFI /boot 1 GiB
/dev/sda2 ext4 / 24 GiB

You can then format the partitions using the following commands:

# mkfs.vfat -F32 /dev/sda1 # mkfs.ext4 /dev/sda2

BIOS layout

In this case, things are way more straightforward than before. In fact, you can use the whole disk for your base system without reserving any additional space for the firmware:

Name Type Mount Point Size
/dev/sda1 ext4 / 25 GiB

To format the partition, you can issue the following command:

# mkfs.ext4 /dev/sda1

LUKS layout

Finally, for the UEFI+LUKS setup, we will need to create a LUKS partition acting as a "container" for all the other partitions. That is:

Name Type Mount Point size
/dev/sda1 EFI /boot 1 GiB
/dev/sda2 LUKS n/a 24 GiB

As you can see, the /dev/sda2 partition doesn't get mounted directly, instead we will need to unlock it first and then mount the partitions using the device mapper.

Let's start by formatting the boot partition:

# mkfs.vfat -F32 /dev/sda1

and then let's proceed by creating the encrypted partition:

# cryptsetup luksFormat /dev/sda2 # Create # follow the interactive setup... # cryptsetup luksOpen /dev/sda2 luks # Open

Once the encrypted device has been opened, we can create as many partitions as we want through the device mapper. In this guide, to keep things as simple as possible, I will only create a single root partition:

# mkfs.ext4 /dev/mapper/luks # Format

Mounting

Let's now proceed to mount the partitions we have created in the last section. For a BIOS-based system, this will be a matter of issuing the following command:

# mount /dev/sda1 /mnt

while for UEFI/LUKS installations, you will first need to mount the root partition:

# mount /dev/sda2 /mnt # mount /dev/mapper/luks /mnt # for LUKS installations

then create the boot mount point and finally mount the boot partition:

# mkdir -p /mnt/boot # mount /dev/sda1 /mnt/boot

System bootstrap

We are now ready to bootstrap our system using the debootstrap(8) utility. This tool will download, extract and configure the base Debian system into a path of our choice:

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

This process will take some time depending on your internet connection and disk speed. The whole procedure is non-interactive though, so you will not be bothered with additional configurations.

Chroot

At this point, we can set the root into the freshly installed system. In order to do that, we will need to mount a few extra things first:

# mount --make-rslave --rbind /proc /mnt/proc # mount --make-rslave --rbind /dev /mnt/dev # mount --make-rslave --rbind /sys /mnt/sys # mount --make-rslave --rbind /run /mnt/run

Then, we can chroot using

# chroot /mnt /bin/bash

Install base packages

Currently, the system lacks of any essential program such as the kernel, a text editor and basically any kind of firmware. Issue the following command to install the bare minimum to proceed:

(chroot)# apt update && apt install vim net-tools

Also, if you are configuring a LUKS installation, this is the right moment to install the required packages to boot from an encrypted partition:

(chroot)# apt install cryptsetup cryptsetup-bin cryptsetup-initramfs

fstab configuration

Let's configure the /etc/fstab file by listing the partition names and the relative mount points. Depending on the installation scheme you have chosen, there are three different ways to set up the fstab file.

UEFI installation

In this case we need to list both the root and the boot partition:

UUID=260dbe03-e88a-4de2-bab2-fa21eb838b91 / ext4 errors=remount-ro 0 1 UUID=8EB7-322B /boot vfat defaults 0 2

LUKS installation

This configuration is quite similar to the previous one, except that we need to replace the physical root UUID with the device mapper associated with the encrypted partition:

/dev/mapper/luks / ext4 errors=remount-ro 0 1 UUID=8EB7-322B /boot vfat defaults 0 2

BIOS installation

Finally, since the BIOS scheme consists only of one single partition, the resulting fstab file will just have one single entry:

UUID=260dbe03-e88a-4de2-bab2-fa21eb838b91 / ext4 errors=remount-ro 0 1

LUKS-only settings

LUKS installations require to set up an additional configuration file: /etc/crypttab. This file controls which partition to decrypt during the boot process and is also used by the initial ramdisk generator to build the initramfs image each time the kernel update requires a new initram disk image.

luks UUID=355f7b01-c0de-4f1e-8e29-170d39caada4 none luks,discard

Be sure to replace the UUID value with the UUID of the crypto_LUKS device from lsblk(8). In other words, from the following output:

NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS sda ├─sda1 vfat FAT32 8EB7-322 1G 1% /boot └─sda2 crypto_LUKS 2 355f7b01-c0de-4f1e-8e29-170d39caada4 └─luks ext4 1.0 5dabf729-cf4f-4c14-9256-05dbd411122a 24G 1% /

You want to copy the second-to-last UUID, not the last one.

Apt sources

We can now configure apt sources file. We will use the new deb822 debian.sources syntax which is more intuitive and less verbose than the old one. Edit the debian.sources and add the following content:

(chroot)# cat /etc/apt/sources.list.d/debian.sources Types: deb deb-src URIs: https://deb.debian.org/debian Suites: trixie trixie-updates Components: main non-free-firmware Enabled: yes Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg Types: deb deb-src URIs: https://security.debian.org/debian-security Suites: trixie-security Components: main non-free-firmware Enabled: yes Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg

After that, perform a system update using the following commands:

(chroot)# apt update (chroot)# apt upgrade

Timezone & locales

Let's now move to configure the rest of the system. We will start by setting the timezone and the locales:

(chroot)# /usr/sbin/dpkg-reconfigure tzdata (chroot)# apt install locales (chroot)# /usr/sbin/dpkg-reconfigure locales

In both cases an interactive, text-based UI will guide you to the configuration process.

Network configuration

By default, no kind of network configuration is available; therefore, we will need to either install NetworkManager or configure it manually. Let's see how to set up a simple wired DHCP network.

In order to configure it, add the following content to /etc/network/interfaces:

# Loopback interface auto lo iface lo inet loopback # Primary interface auto enp1s0 iface enp1s0 inet dhcp

Be sure to replace the enp1s0 with your actual NIC.

After that, we can proceed to configure the hostname:

(chroot)# echo "debian" > /etc/hostname

It is also advisable to add the hostname to the /etc/hosts file in order to resolve it to localhost:

127.0.0.1 localhost debian ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters

Kernel & firmware

Let's now install the kernel and the firmwares. Since we already set up the /etc/fstab and the /etc/crypttab files, the kernel installer should be able to configure both the kernel and the initramfs correctly by itself (if you have chosen the LUKS installation scheme).

(chroot)# apt install linux-image-amd64 firmware-linux

Before proceeding, we need to include some additional paths (e.g., /usr/sbin) into our environment. The fastest way to do it, is to issue the following command:

(chroot)# su - root

User configuration

It's now time to set a root password. Let's do it by running passwd. After that, we can also add a user:

(chroot)# useradd -m -G wheel,video,audio,system,disk,sudo,network -s /bin/bash (chroot)# passwd

and install sudo with the following command:

(chroot)# apt install sudo

Since our user is already a member of the "sudo" group, there's no need to modify the sudoers file.

Bootloader

We can now complete the base installation process by configuring the bootloader (GRUB). Let's start by installing it:

(chroot)# apt install grub2

IF you are running an UEFI system, you will also need to install the following package:

(chroot)# apt install grub-efi

LUKS installation

If, on top of that, you are also doing a LUKS installation, you will need to modify the /etc/default/grub file by adding the following two lines:

[...] GRUB_CMDLINE_LINUX="cryptdevice=UUID=355f7b01-c0de-4f1e-8e29-170d39caada4:luks" GRUB_ENABLE_CRYPTODISK=y [...]

Where:

After that, we can proceed by installing the bootloader.

UEFI installation

On an UEFI-based system, issue the following command:

(chroot)# grub-install --target=x86_64-efi --efi-directory=/boot --recheck

BIOS installation

On a BIOS-based system, run the following command instead:

(chroot)# grub-install --target=i386-pc /dev/sda --recheck

Finally, for both types of installation, execute the following command:

(chroot)# update-grub

Reboot & post-installation

The installation process is now complete. You can exit chroot, unmount the partitions and reboot the machine. On the next reboot, you will prompted for the LUKS decryption password if you chose that kind of configuration; otherwise, the boot process will proceed without any user interaction.

At this point, if you want to install additional packages (such as a desktop environment), you can run tasksel which allows you to easily install the following package groups:

$ tasksel --list-tasks desktop Debian desktop environment gnome-desktop GNOME xfce-desktop Xfce gnome-flashback-desktop GNOME Flashback kde-desktop KDE Plasma cinnamon-desktop Cinnamon mate-desktop MATE lxde-desktop LXDE lxqt-desktop LXQt web-server web server ssh-server SSH server laptop laptop

Disable automatic updates

By default, Debian enables some annoying systemd timers to automatically download and install software updates when available. While this behavior might be useful in certain scenarios (when?), if you are following this guide chances are you prefer managing system updates by yourself. To disable this intrusive and undesired behavior, you can mask the relative systemd timers/services by issuing the following commands:

# systemctl disable apt-daily.service # systemctl disable apt-daily.timer # systemctl mask apt-daily.timer # systemctl mask apt-daily.service # systemctl disable apt-daily-upgrade.service # systemctl disable apt-daily-upgrade.timer # systemctl mask apt-daily-upgrade.service # systemctl mask apt-daily-upgrade.timer

Conclusions

At this point, you should have a fully working Debian system installed entirely from scratch. If you have question or if you would like to report an issue, feel free to contact me via my email. 👋