Marc Wäckerlin
Für eine libertäre Gesellschaft

Manual Ubuntu Installation from Scratch

November 14, 2025

Views: 16

Because the Ubuntu-Server installation does not offer the device configuration (see Multi-Disk Encryption Magic), I need to install Ubuntu manually from scratch. This is also a good training to understand what magic the Ubuntu installer does. Here my hard disk configuration is already done according to Multi-Disk Encryption Magic, so this blog does not cover device setup. I just expect you have partitions ready to mount:

  • one disk (hdd/ssd) prepared as boot device (if not, see below)
  • one partition for /boot
  • one partition for / (root)
  • only for UEFI devices: one partition to mount to /boot/uefi
  • optional: a swap partition

The partitions in /boot and below must not be encrypted, all other partitions can be encrypted, and in fact I recommend to encrypt them.

Boot the Installation Environment

Just download the latest Ubuntu Desktop ISO image and copy it to an installation USB-stick. Then boot your new computer from that stick. When the installer starts, choose your language and keyboard-layout, connect to the network, then choose Try Ubuntu to stop the installer.

On the left upper side of the desktop, there is a button to get the launch pad. Click on the launcher with the Ubuntu logo on the very bottom of the launch pad and start a console from there.

Remote Installation

Optionally you can run everything from remote using SSH. The advantage of this is, that you can sit on your normal computer with your favorite environment, instead of doing everything from the limited installer desktop.

For this, just install the SSH server and set a password for the default user named ubuntu:

sudo apt-get update
sudo apt-get install -y openssh-server
passwd

Check the IP address of the device you want to install. You find it from the network settings, just open the settings from the Ubuntu launcher. In this example, let’s say it is 192.168.0.8.

On your favorite computer, which must be in the same local network, open a console and run:

ssh -o PubkeyAuthentication=no ubuntu@192.168.0.8

Now you’re ready for remote installation.

Ubuntu Installation

The whole installation is done as root. Be careful, be aware that you could damage anything. Get root:

sudo -Hi

Prepare Target Filesystems

Make sure, all partitions are ready, e.g. open encrypted filesystems. In my case, this is: cryptsetup open /dev/big/big crypt. The LVMs are the automatically ready. In this example, I install:

  • swap on /dev/crypt/swap
  • / on /dev/big/root
  • /boot on /dev/sdd2
  • BIOS boot in /dev/sdd1
  • MBR (Master Boot Record) on /dev/sdd
  • no uefi (very old server from 2014)

Be aware that device names may change, i.e. those in /dev/sd*, so you will need to add the UUIDs to your fstab and crypttab configuration.

Prepare Boot Drive

BIOS (Legacy)-Boot, GPT-Disk

Without UEFI, you need a special 1MB BIOS boot partition. I’ll boot from `/dev/sdd`, so I create it in `/dev/sdd1`. The following steps destroy the device `/dev/sdd` and all it’s content. The following steps create a new GPT label, which destroys all existing partitions, then creates and initializes a BIOS boot partition as first partition, so partition 1 in /dev/sdd1:

parted /dev/sdd mklabel gpt
parted /dev/sdd mkpart biosboot 1MiB 2MiB
parted /dev/sdd set 1 bios_grub on
UEFI Boot Setup

On modern UEFI based systems, you need an EFI partition (FAT32, ca. 512MB with esp flag). I’ll boot from `/dev/sdd`, so I create it in `/dev/sdd1`. The following steps destroy the device `/dev/sdd` and all it’s content. The following steps create a new GPT label, which destroys all existing partitions, then creates and initializes an EFI partition as first partition, so partition 1 in /dev/sdd1:

parted /dev/sdd mklabel gpt
parted /dev/sdd mkpart ESP fat32 1MiB 513MiB
parted /dev/sdd set 1 esp on
mkfs.vfat -F32 /dev/sdd1
Boot Partition

All systems, legacy and UEFI, need a boot partition. I create it as /dev/sdd2 with ext4 file system on the same disk I prepared above. Again, this destroys previous data on the disk:

parted /dev/sdd mkpart boot ext4 2MiB 100%
mkfs.ext4 /dev/sdd2

Root Partition and Swap

I always use a large root partition without further splitting up, so I format (destroy) my device on /dev/crypt/root and initialize swap on /dev/crypt/swap:

mkfs.ext4 /dev/crypt/root
mkswap /dev/crypt/swap

Mount Filesystems

Now everything is ready to be mounted to /mnt (you can mount it wherever you want, /mnt is somehow a standard place). On legacy non UEFI systems, skip the last two steps to mount /boot/efi. It is important that you first mount the upper paths, then the lower paths:

mount /dev/crypt/root /mnt
mkdir /mnt/boot
mount /dev/sdd2 /mnt/boot
mkdir /mnt/boot/efi              # on UEFI BIOS only
mount /dev/sdd1 /mnt/boot/efi    # on UEFI BIOS only

Bootstrap Minimal Ubuntu Base System

There is a script debootstrap that downloads and installs a minimal debian system into a directory. All you need to specify is the release code name (e.g. noble for Ubuntu 24.04 LTS) and the target directory:

apt-get update
apt-get install -y debootstrap
debootstrap noble /mnt

Switch to New Ubuntu

Now we can chroot to the new system:

mount --bind /dev /mnt/dev
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
chroot /mnt

All we do now is applied to the new system that we setup.

Language, Localisation

To setup any localisation, e.g. German (de) in Switzerland (CH), save it to /etc/default/locale and generate the corresponding locales:

echo "LANG=de_CH.UTF-8" > /etc/default/locale
locale-gen de_CH.UTF-8

Host Name

To setup a host name, just store it in /etc/hostname, e.g. if you name your computer server01:

echo server01 > /etc/hostname
echo "127.0.1.1 server01" >> /etc/hosts

Create a User

If you want to be able to login after your computer restarts, you must create a user on your name. And if you want to execute administration tasks from that user, you need to give it root access through sudo by adding it to the sudo group. In this example, let’s name the user me:

adduser me
usermod -aG sudo me

Configure APT Package Sources

Simple

Typically you want all Ubuntu sources, so add them, the simplest way is to use apt-add-repository:

apt-get install -y software-properties-common
add-apt-repository -y main
add-apt-repository -y universe
add-apt-repository -y multiverse
add-apt-repository -y restricted
add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu $(lsb_release -cs)-updates main restricted universe multiverse"
add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu $(lsb_release -cs)-security main restricted universe multiverse"
add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu $(lsb_release -cs)-backports main restricted universe multiverse"
apt update

Fancy

Alternatively you can install everything manually without dependency on software-properties-common by writing into /etc/apt/sources.list:

CODENAME=$(lsb_release -cs)
cat > /etc/apt/sources.list <<EOF
deb http://archive.ubuntu.com/ubuntu $CODENAME main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu $CODENAME-updates main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu $CODENAME-security main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu $CODENAME-backports main restricted universe multiverse
EOF
apt update

Install Necessary System Packages

You may need the following packages:

  • Base System, choose your flavour, i.e. one of e.g.:
    • ubuntu-standard
    • ubuntu-base
    • ubuntu-minimal
    • ubuntu-server
    • ubuntu-server-minimal
    • ubuntu-desktop
    • ubuntu-dektop-minimal
    • kubuntu-desktop
  • for LVM: lvm2
  • for encrypted boot disks: cryptsetup-initramfs
  • to allow SSH access: openssh-server
  • and always: linux-image-generic grub-pc systemd-sysv

Example:

apt-get install -y ubuntu-standard linux-image-generic grub-pc \
               lvm2 cryptsetup-initramfs \
               openssh-server

Encrypted Filesystems in CryptTab

To be able to mount encrypted filesystems at boot, you must enter them in /etc/crypttab. in my example, the device /dev/big/big is encrypted. First I need it’s LUKS-UUID: cryptsetup luksUUID /dev/big/big, this is how I reference it in my /etc/crypttab. Be sure to always use UUIDs, unless you’re absolutely sure, the name you refer to will never change.

You can use vi or install vim to edit /etc/crypttab, or if it is just one device, you can use this script, just adapt DEVICE in the first line to your needs:

DEVICE=/dev/big/big
LUUID=$(cryptsetup luksUUID $DEVICE)
cat > /etc/crypttab <<EOF
crypt UUID=$LUUID none luks,discard
EOF

Verify that the file content makes sense and UUID is set correctly, e.g. cat /etc/crypttab results in my system to:

crypt UUID=eb3e94f0-2d76-4e92-b3ce-0e2911d9448e none luks,discard

All Filesystems in FSTab

You must add all filesystems you’ll need in /etc/fstab, including pseudo filesystems, here again, you may use an editor to set it up, or you can use cat, just change the variables. Again, don’t add the EFI part if you are on a legacy system and don’t add the SWAP part if you don’t have a swap partition:

SWAP=/dev/crypt/swap
ROOT=/dev/crypt/root
BOOT=/dev/sdd2
EFI=/dev/sdd1

cat > /etc/fstab <<EOF
proc                                      /proc     proc   defaults       0 0
sysfs                                     /sys      sysfs  defaults       0 0
devpts                                    /dev/pts  devpts gid=5,mode=620 0 0
tmpfs                                     /run      tmpfs  defaults       0 0
tmpfs                                     /tmp      tmpfs  defaults       0 0
UUID=$(blkid -s UUID -o value $ROOT) /         ext4   defaults       0 1
UUID=$(blkid -s UUID -o value $BOOT) /boot     ext4   defaults       0 2
UUID=$(blkid -s UUID -o value $EFI) /boot/efi vfat   defaults       0 2
UUID=$(blkid -s UUID -o value $SWAP) none      swap   sw             0 0
EOF

On my legacy system, this results in:

proc                                      /proc     proc   defaults       0 0
sysfs                                     /sys      sysfs  defaults       0 0
devpts                                    /dev/pts  devpts gid=5,mode=620 0 0
tmpfs                                     /run      tmpfs  defaults       0 0
tmpfs                                     /tmp      tmpfs  defaults       0 0
UUID=442880bf-1b95-4b53-8c48-7e64d787b0d0 /         ext4   defaults       0 1
UUID=4e077e0e-bf0d-405e-b1be-19c6e013ee75 /boot     ext4   defaults       0 2
UUID=72e6dea6-d286-4427-8e56-74ba8f779fa8 none      swap   sw             0 0

Configure DHCP Network

Netplan and the Resolver require some packages, either libnss-resolve (old Ubuntu, e.g. focal) or systemd-resolved (new Ubuntu, e.g. noble):

apt-get install -y netplan.io systemd-sysv systemd-resolved

DNS Resolver

For DNS-Resolver, the hosts: line in file /etc/nsswitch.conf must contain resolve as hosts: files resolve [!UNAVAIL=return] dns. You can edit it manually or with a script:

sed -i 's/^hosts:.*$/hosts:          files resolve [!UNAVAIL=return] dns/g' /etc/nsswitch.conf

NetPlan Configuration

To configure the network, you need to setup a netplan configuration. Use ip -br link to find all available network devices. Also here, you can create /etc/netplan/01-netcfg.yaml manually or with a script:

IFACES=$(ip -br link | awk '$2 ~ /UP|DOWN/ {print $1}')
cat > /etc/netplan/01-netcfg.yaml <<EOF
network:
  version: 2
  renderer: networkd
  ethernets:
$(
  for IFACE in $IFACES; do
    echo "    $IFACE:"
    echo "      dhcp4: true"
  done
)
EOF

On my server, there are two network interfaces eno1 and eno2, so the resulting file /etc/netplan/01-netcfg.yaml is:

network:
  version: 2
  renderer: networkd
  ethernets:
    eno1:
      dhcp4: true
    eno2:
      dhcp4: true

Setup InitRamFS and Kernel

Finally make sure our system boots and finds it’s kernel and initial filesystem. First of all, if you have LVm and encrypted filesystems and if you need to enter the password at boot time, this must be enabled:

echo "CRYPTSETUP=y" > /etc/cryptsetup-initramfs/conf-hook
echo "ASKPASS=y" >> /etc/cryptsetup-initramfs/conf-hook
echo "LVM=yes" > /etc/initramfs-tools/conf.d/lvm

Finally initialize GRUB and the initial ram filesystem, in my case, I install GRUB on /dev/sdd. For those on legacy systems without EFI, just skip the first grub-install line:

update-initramfs -u -k all
update-grub
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu
grub-install /dev/sdd

You’re done! Just reboot and make sure you unplug your temporary Ubuntu boot device before restarting:

exit
reboot

Hint: For those who used SSH during the installation, the key now has changed and you’ll need to remove the old SSH key of this machine. That’s not a bug nor an issue. So here: ssh-keygen -f ~/.ssh/known_hosts -R 192.168.0.8

comments title