Recently, I came across a VPS provider that does not provide Debian images. This is rather annoying since I much prefer a fresh minimal install of Debian over a “minimal” Ubuntu image that still has a lot of stuff that I don’t want.

Naturally, I decided to install Debian anyways, and came up with an approach to do so.

If you are feeling particularly bold, you can try running my pre-made scripts that would convert a fresh Ubuntu install to a fresh Debian install.

To use the scripts, you should download either the UEFI version or the BIOS version, depending on whether your current OS is using BIOS or UEFI.

At the top of the script, change the variables to match your system configuration. The most important one being BOOT_DRIVE so that grub would be installed on the correct device.

The scripts will prompt you for a root password and SSH keys. Once the script finishes, the system will be rebooted and you should be able to SSH into the now-Debian machine as root via the SSH keys.

If you don’t feel like using the script, I am also providing manual instructions. This also explains how the scripts work.

Installing Debian to a chroot

First, we need to bootstrap a new install of Debian. To avoid conflicting with the existing system, we will do it in a chroot with a tool called debootstrap. You will also need the Debian archive’s keyring to verify pacakges.

On a recent version of Ubuntu, you can probably install debootstrap and debian-archive-keyring by running:

sudo apt install debootstrap debian-archive-keyring

On an older version, the keyring or debootstrap might be out of date. Instead, you can try downloading the .deb packages from the Debian’s website:

These .deb files can then be instaled with dpkg -i. You should run apt install -f to install their dependencies.

Once this is done, you can install Debian into a chroot by running:

debootstrap --arch amd64 buster /debian http://deb.debian.org/debian

The chroot will be located at /debian. We will be installing buster, the latest release at this time, and the amd64 architecture, which is probably what you want. If not, feel free to change these. Be sure to change all subsequent operations.

Once debootstrap finishes, a fresh copy of Debian will be ready.

Entering the chroot

We need to be able to access the real /dev, /dev/pts, /proc and /sys inside the chroot. To do this, run:

for dir in /proc /sys /dev /dev/pts; do
    mount --bind "$dir" "/debian/$dir"
done

We will also need to access the original root directory. Let’s put it at /old_root in the chroot:

mkdir /debian/old_root
mount --bind / /debian/old_root

Let’s pretend that the OS is installed on /dev/sda and this is the device that needs to be bootable.

On UEFI systems, to avoid issues, we should unmount the EFI system partition and remount it later inside the chroot. Run df | grep /boot/efi to show the device for the EFI system partition. As an example, we will use /dev/sda1. We then unmount it:

umount /boot/efi

We will likely need some configuration files, so let’s copy them:

cp /etc/resolv.conf /etc/fstab /debian/etc

Now, we can enter the chroot by running:

chroot /debian /bin/bash

This should start bash inside the new Debian chroot.

Installing Basic Packages

We need to install a kernel, a grub, the SSH server, and rsync.

On a UEFI system, run:

apt install linux-image-amd64 grub-efi openssh-server rsync

On a BIOS system, run:

apt install linux-image-amd64 grub openssh-server rsync

To avoid network device issues, we tell Debian to continue using the old eth0 name for the network interface. To do this, we edit /etc/default/grub to and add net.ifnames=0 biosdevname=0 to GRUB_CMDLINE_LINUX.

We can then set up the network by putting the following lines in /etc/network/interfaces.d/eth0:

allow-hotplug eth0
iface eth0 inet dhcp

You might want to change this if your system needs static IPs. For details, see the Debian Wiki.

You might also want to take this opportunity to set the root password by running passwd, and adding your SSH keys to /root/.ssh/authorized_keys.

Removing the Old System

Our eventual goal is to install Debian into the original root filesystem (at /old_root inside the chroot). To do this, we need to first get the old system out of the way:

mkdir /old_root/old
mv old_root/* old_root/old

This will produce some errors, since we can’t move things like /dev, /proc, /sys, or even /old iself. But these errors can be safely ignored.

Installing the Boot Loader

On a BIOS system, run:

grub-install /dev/sda
update-grub

On a UEFI system, run:

mkdir /boot/efi
mount /dev/sda1 /boot/efi
echo 'grub-efi-amd64 grub2/force_efi_extra_removable boolean true' | debconf-set-selections
grub-install /dev/sda
update-grub
mkdir -p /boot/efi/EFI/boot
cp /boot/efi/EFI/debian/grubx64.efi /boot/efi/EFI/boot/bootx64.efi

Here, we force grub to be installed on the system as the fallback bootloader, i.e. EFI/boot/bootx64.efi. This is to avoid issues that can pop up if the NVRAM which stores the boot menu is wiped or simply not imaged. While this would prevent selection between multiple operating systems, I have yet to see a multi-OS VPS, so it’s probably not a big deal.

Move Debian into position

Now, we just need to move Debian from the chroot into the actual root filesystem. This can be easily accomplished by running:

cd /
rsync -ax bin boot etc home lib lib32 lib64 libx32 media mnt opt root sbin srv tmp usr var old_root/

This should move all the important directories into /old_root, which is the actual root directory, while preserving permissions and everything.

Reboot

You can now run exit to exit the chroot, and reboot to reboot into Debian. If all goes well, you should be able to run ssh root@<your server> to access your new Debian server. After successfully booting, you can then delete the old system as well as the chroot by running rm -rf /old as root.

Conclusion

If you are successful, then you should now have a Debian VPS despite not having a pre-built image. If you run into issues, please comment and I will try to address them.

I hope you found this guide useful.