Oracle Free Tier: Install Debian on the x86 micro instances with full disk encryption
Attn: This is a copy from Pieter Hollander's home page, for self use only.
Oracle Cloud offers AMD VPSes with 0,1 virtual CPU core and 1GB RAM for free through their Oracle Free Tier program. Unfortunately, Debian is not part of their standard range of OSes available to install. For the free ARM nodes Oracle offers, reinstalling is very simple through the use of netboot.xyz and selecting a netinstall image. Unfortunately, reinstalling their x86 instances is a bit more cumbersome.
This document shows how to do an in-place install of Debian 12 with full disk encryption and remote unlocking on an instance after first choosing the Ubuntu 22.04 minimal image in the Oracle Cloud console. As root file system, a choice is given between ext4 and btrfs.
Installing Alpine Linux
In order to reinstall the instance, we will need to minimise the amount of resources the system uses. By installing Alpine Linux and then using that to install Debian, we get a very minimal temporary OS using less than 100 MB of RAM and can be moved from the boot volume into RAM while continuing to run stable.
First, SSH into the Ubuntu instance you deployed on Oracle Cloud.
Then, execute the following commands to replace Ubuntu with Alpine Linux:
cd /
wget https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-virt-3.21.3-x86_64.iso
dd if=alpine-virt-3.21.3-x86_64.iso of=/dev/sda
sync
reboot
The system will now reboot into an unconfigured Alpine Linux install.
Configure Alpine Linux
After the system is rebooted, you’ll lose SSH access. Therefore, use the Oracle Cloud Console to access the Alpine Linux VM. Deploy the cloud console by going to Compute -> Instances -> Instance details (by clicking on the instance you want to install). Scroll down and click ‘Console connection’ -> ‘Launch Cloud Shell connection’.
A new connection will deploy. Hit enter to get a login prompt after the console prints Instance Console Connection reached state: ACTIVE
On the resulting command prompt (localhost login:), login using username root and without a password.
Next, configure networking:
vi /etc/network/interfaces
Press i to start editing. The Oracle Cloud shell supports copy pasting.
auto eth0
iface eth0 inet dhcp
Press escape and type :wq to save and exit.
Restart networking
/etc/init.d/networking restart
Setup SSH using the Alpine SSH wizard.
setup-sshd
Which ssh server? ('openssh', 'dropbear' or 'none') [openssh]
Allow root ssh login? ('?' for help) [prohibit-password]
Enter ssh key or URL for root (or 'none') [none]
* service sshd added to runlevel default
* Caching service dependencies ...
[ ok ]
ssh-keygen: generating new host keys: RSA ECDSA ED25519
* Starting sshd ...
[ ok ]
Add your SSH public key
mkdir .ssh
vi .ssh/authorized_keys
Paste in your SSH public key and save.
Remove Alpine from the boot volume
SSH into the Alpine Linux install. Remove old IP and matching fingerprint
lines from your .ssh/known_hosts if you get any errors and retry.
Press 3 to create a new GPT partition table. Press n to create the boot partition. Make it 1024MB by answering the wizard as detailed below.
Command (? for help): n
Partition number (1-128, default 1):
First sector (34-104857566, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-104857566, default = 104855551) or {+-}size{KMGTP}: +1024M
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'
Press n to create the EFI partition. Make it 512MB and set it to EFI.
Command (? for help): n
Partition number (2-128, default 2):
First sector (34-104857566, default = 2099200) or {+-}size{KMGTP}:
Last sector (2099200-104857566, default = 104855551) or {+-}size{KMGTP}: +512M
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): EF00
Changed type of partition to 'EFI system partition'
Press n to create the root file system partition. Make it use all available remaining disk space.
Command (? for help): n
Partition number (3-128, default 3):
First sector (34-104857566, default = 3147776) or {+-}size{KMGTP}:
Last sector (3147776-104857566, default = 104855551) or {+-}size{KMGTP}:
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'
Press p to display the partition table. It should give the following result:
command (? for help): p
Disk /dev/sda: 104857600 sectors, 50.0 GiB
Model: BlockVolume
Sector size (logical/physical): 512/4096 bytes
Disk identifier (GUID): 57C983BB-7A42-4B74-BD69-F9A0AEFD5199
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 104857566
Partitions will be aligned on 2048-sector boundaries
Total free space is 4029 sectors (2.0 MiB)
Number Start (sector) End (sector) Size Code Name
1 2048 2099199 1024.0 MiB 8300 Linux filesystem
2 2099200 3147775 512.0 MiB EF00 EFI system partition
3 3147776 104855551 48.5 GiB 8300 Linux filesystem
If this is not the case or if you’d like to make changes to this setup, start over by pressing o to recreate the partition table. Otherwise, press w and y to exit and save your changes.
Formatting the new partitions
Remove the old partition table
Format root filesystem
Depending on your preference, you can use ext4 or btrfs, or your own choice as the main file system. The first two are options I’ve personally tried. Both work well. Choose one.
Option A: Format and mount the root partition (ext4)
mkfs.ext4 /dev/mapper/luks1
mount -t ext4 /dev/mapper/luks1 /mnt
Option B: Format and mount the root partition (btrfs)
Format the root partition (btrfs)
This step will take a while and it may sometimes even seem like it is hanging, especially when resolving dependencies and unpacking the base system. For me, the debootstrap command took around 15 minutes.
Configuring hostname
cat < /mnt/etc/apt/sources.list
deb http://ftp.nl.debian.org/debian/ bookworm main contrib non-free non-free-firmware
#deb-src http://ftp.nl.debian.org/debian/ bookworm main contrib non-free non-free-firmware
deb http://security.debian.org/ bookworm-security main contrib non-free non-free-firmware
#deb-src http://security.debian.org/ bookworm-security main contrib non-free non-free-firmware
# bookworm-updates, previously known as 'volatile'
deb http://ftp.nl.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware
#deb-src http://ftp.nl.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware
# bookworm-backports, previously on backports.debian.org
deb http://ftp.nl.debian.org/debian/ bookworm-backports main contrib non-free non-free-firmware
#deb-src http://ftp.nl.debian.org/debian/ bookworm-backports main contrib non-free non-free-firmware
EOF
Enter chroot
Create system bind mounts
mount --rbind /dev /mnt/dev
mount --rbind /proc /mnt/proc
mount --rbind /sys /mnt/sys
Select en_US.UTF-8 and possible other languages and set a default language.
dpkg-reconfigure tzdata
Choose your timezone
Enabling systemd-networkd if desired
If you chose to use systemd-networkd above, enable it here and uninstall ifupdown, otherwise don’t
Setting up mounts
Let’s first include the description you would see when installing Debian the conventional way.
cat < /etc/fstab
# /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).
#
#
EOF
Create a swap file
The Oracle free tier micro instances only have 1GB of RAM. To prevent out-of-memory errors, I created a 2GB swap file.
Option A: Create a swapfile on ext4
sed -i "s/backend = auto/backend = systemd/g" /etc/fail2ban/jail.conf
Harden SSH and prevent language setting errors
sed -i "s/#PasswordAuthentication yes/PasswordAuthentication no/g" /etc/ssh/sshd_config
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin no/g" /etc/ssh/sshd_config
sed -i "s/AcceptEnv LANG LC_*/#AcceptEnv LANG LC_*/g" /etc/ssh/sshd_config
Also make sure to open port 2222 by adding it to the VCN security list used for this VM in the Oracle cloud console. If you didn’t adjust anything before, this security list should be titled something like Default Security List for vcn-****. The rule you add should be similar to the one included by default for SSH access, but with port 2222 instead of 22.
nano /etc/dropbear/initramfs/authorized_keys
Add your SSH public key in here. You will now be able to unlock the encrypted root disk at boot by going to root@REPLACE_WITH_YOUR_INSTANCES_PUBLIC_IP_ADDRESS
Update the initramfs to add these changes and update grub just to be sure:
update-initramfs -u -k all
update-grub2
Cleanup
apt --purge autoremove
Rebooting into Debian
exit the chroot environment
exit
reboot
reboot
Conclusion
If you enjoyed reading this post and/or have suggestions for improvement, please let me know by leaving a comment down below or contacting me through the contact form.
As a final word of caution, be careful with how much you rely on freely offered services and take proper precautions wrt backups and recovery in case these offerings change.
Next steps could be to disable the sudo password prompt or to install zsh.
If you used BTRFS as your file system, now, with a clean installation, might be a good time to create your first snapshot. That way, you can repurpose this VM as often as you like without having to start from scratch.
Closing thoughts
I welcome your feedback and hearing about your experiences! If this post has been useful to you, please feel free to leave a comment down below.