HOW TO INSTALL DEBIAN 12 FROM SCRATCH
2025-05-16
In this guide we will see how to set up a Debian system completely from scratch; that is, without
using the official Debian installer. To do this we shall use the debootstrap(8)
utility, which allows us
to install a Debian base system in a subdirectory of another, already installed system[1]. The installation
process will cover the following three scenarios:
- UEFI installation;
- BIOS installation;
- LUKS installation.
Prerequisites §
Before getting started, get yourself a GNU/Linux distribution(even a live one) that includes thedebootstrap(8)
command
in its repository. Debian/RHEL/Arch-based distributions offer this package directly from their official repository, so you
can easily install it using the distro's package manager.
Be also sure to back up any important files and to double check the commands you issue on your system. This guide will walk you through setting up a Debian installation "à la Arch"; that is, by doing everything by hand. Therefore, it assumes that you know how to work with UNIX-like systems and how to troubleshoot issues on your own.
Keep in mind that this guide was written and tested against the latest release of Debian stable and while it may also work with other Debian-based systems, they are not officially supported. I will, however, update the guide regularly to ensure compatibility and reliability.
Partitions §
As stated before, we can define three different ways to install Debian; each of them will result in a different partition layout. Let's see them.UEFI layout:
Name | Type | Mount | Size |
---|---|---|---|
/dev/sda1 | EFI | /boot |
1 GiB |
/dev/sda2 | ext4 | / |
24 GiB |
You can format the partitions using the following commands:
$ mkfs.vfat -F32 /dev/sda1
$ mkfs.ext4 /dev/sda2
BIOS layout:
Name | Type | Mount | Size |
---|---|---|---|
/dev/sda1 | ext4 | / |
25 GiB |
To format the partition, you can issue the following command:
$ mkfs.ext4 /dev/sda1
LUKS layout:
Finally, let's see the partition layout for an UEFI+LUKS partition scheme.
Name | Type | Mount | Size |
---|---|---|---|
/dev/sda1 | EFI | /boot |
1 GiB |
/dev/sda2 | LUKS | n/a | 24 GiB |
/dev/sda
partition doesn't get mounted directly, instead we will need
to unlock it first and then mount the device mapper associated with the LUKS partition[2].
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 instructions...
$ cryptsetup luksOpen /dev/sda2 luks # open
$ mkfs.ext4 /dev/mapper/luks # format
Mounting §
We can now proceed to mount the previously created partitions. For a BIOS-based system, this will be a matter of issuing the following command:
$ mount /dev/sda1 /mnt
while for UEFI-based 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 on it:
$ mkdir -p /mnt/boot
$ mount /dev/sda1 /mnt/boot
System bootstrap §
We are now ready to bootstrap our system using thedebootstrap(8)
utility, this utility
will download, extract and configure the base Debian system into a subdirectory:
$ debootstrap --arch amd64 stable /mnt https://deb.debian.org/debian
This will take some time depending on your internet connection and disk speed. The process
is non-interactive though, so you won't be bothered with questions allowing you to let it run
on its own.
Chroot §
At this point, we can chroot 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 essential packages §
Right now, the system lacks any essential program such as a text editor, the kernel and pretty much any kind of firmware. Issue the following command to install the bare minimum to proceed:
$ apt update && apt install vim net-tools
Also, if you are following the LUKS path, this is the right moment to install the required packages to boot
from an encrypted partition:
$ apt install cryptsetup cryptsetup-bin cryptsetup-initramfs
fstab
configuration §
Let's configure the /etc/fstab
file by listing the partitions names and mount points. Depending on the
installation scheme you have chosen, there are three different ways to set up the fstab file[3].
UEFI installation:
In this case we need to list both the root and the boot partition on the fstab file:
UUID=260dbe03-e88a-4de2-bab2-fa21eb838b91 / ext4 errors=remount-ro 0 1
UUID=8EB7-322B /boot vfat defaults 0 2
LUKS installation:
This case 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 only 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 ram disk generator to
build the initramfs image.
Add the following line to the file:
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'ssources.list
file. We will use the new deb822 debian.sources syntax which is more
intuitive and less verbose than the old one[4]:
Edit the /etc/apt/sources.list.d/debian.sources
and add the following content:
Types: deb deb-src
URIs: https://deb.debian.org/debian
Suites: bookworm bookworm-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: bookworm-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:
$ apt update
$ apt upgrade
Timezone & locales §
Let's now proceed to configure the rest of the system. We will start by setting the timezone and the locales:
$ /usr/sbin/dpkg-reconfigure tzdata
$ apt install locales
$ /usr/sbin/dpkg-reconfigure locales
In both cases an interactive, text-based UI will be shown which will guide you to the configuration process.
Network configuration §
No kind of network configuration is available out of the box, we need to configure it manually, even if you want to stick to a simple wired DHCP network. 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. Then, we can proceed to configure the hostname:
$ echo "laptop" > /etc/hostname
I also suggest adding the hostname to the /etc/hosts
file in order to resolve it to localhost:
127.0.0.1 localhost laptop
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Kernel & firmware §
Now we will install the kernel and the firmware. 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:
$ 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:
$ su - root
User configuration §
Let's configure the root password by issuing thepasswd
command, then let's create a new user with the following
command[5]:
$ useradd -m -G wheel,video,audio,system,disk,sudo,network -s /bin/bash <USER_NAME>
$ passwd <USER_NAME>
We can then install sudo with the following command:
$ apt install sudo
Since our user is already inside the "sudo" group, there's not need to edit the sudoers file.
Bootloader §
We can now complete the base installation process by configuring the bootloader(GRUB). Let's start by installing it:
$ apt install grub2
if you are running an UEFI system, you will also need to install the following package:
$ apt install grub-efi
If, on top of that, you are doing a LUKS installation, you will first 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:
GRUB_CMDLINE_LINUX
specifies which partition represent the cryptdevice(i.e., the device to unlock). Be sure to replace this value with the second-to-last UUID fromlsblk(8)
;luks
represents the device mapper name. That is, the name on/dev/mapper/<dev>
;GRUB_ENABLE_CRYPTODISK
enables GRUB's encryption support.
On an UEFI-based system, issue the following command:
$ grub-install --target=x86_64-efi --efi-directory=/boot --recheck
while, on a BIOS-based system, run the following one instead:
$ grub-install --target=i386-pc /dev/sda --recheck
Finally, for both system types, execute the following command:
$ update-grub
Reboot & post-installation §
Now that the installation process is completed, we can exit chroot, unmount the partitions and reboot to our freshly installed system. On the next reboot, you will be prompted for the LUKS decryption password if you chose that configuration; otherwise, the boot process should complete without any user interaction.At this point you are left with a fully working Debian system with no extra packages installed on top of it. If you want to install some common use packages, you can run
tasksel
to add any of 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
Tip: by default, Debian enables a systemd timer to automatically download and install software updates.
While this behaviour might be useful in certain scenarios, if you are following this guide you may prefer managing system updates by yourself. To stop Debian to automatically install updates, you can disable and mask these systemd timers/services:
$ 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 installation installed completely from scratch. If you have any questions or if you'd like to report something, feel free to contact me via my email. 👋References §
[1]: Deboostrap wiki page ↩
[2]: In
fdisk(1)
, you can leave the default "Linux filesystem" type for this partition ↩[3]: You can retrieve the UUID of your partitions using
lsblk -f /dev/sda
↩[4]: If you prefer using the old syntax, refer to this document ↩
[5]: You can add missing user groups by issuing
groupadd <GROUP_NAME>
↩