Title: How-to install Alpine Linux in full ram with persistency Author: Solène Date: 14 July 2023 Tags: immutability linux alpine Description: In this article, you will learn how to install and configure Alpine Linux to run your system from memory and save its state for next boots. # Introduction In this guide, I'd like to share with you how to install Alpine Linux, so it runs entirely from RAM, but using its built-in tool to handle persistency. Perfect setup for a NAS or router, so you don't waste a disk for the system, and this can even be used for a workstation. HTML Alpine Linux official project website HTML Alpine Linux wiki: Alpine local backup # The plan Basically, we want to get the Alpine installer on a writable disk formatted in FAT instead of a read only image like official installers, then we will use the command `lbu` to handle persistency, and we will see what need to be configured to have a working system. This is only a list of steps, they will be detailed later: 1. boot from an Alpine Installer (if you are using Alpine, you don't need too) 2. format an usb memory drive with an ESP partition and make it bootable 3. run `setup-bootloader` to copy the bootloader from the installer to the freshly formatted drive 4. reboot on the usb drive 5. run `setup-alpine` 6. you are on your new Alpine system 7. run `lbu commit` to make changes persistent across reboot 8. make changes, run `lbu commit` again IMG A mad scientist Girl with a t-shirt labeled "rare t-shirt" is looking at a penguin strapped on a Frankenstein like machine, with his head connected to a huge box with LBU written on it. HTML Artwork above by Prahou # The setup ## Booting Alpine For this step you have to download an Alpine Linux installer, take the one that suits your needs, if unsure, take the "Extended" one. Don't forget to verify the file checksum. => https://www.alpinelinux.org/downloads/ Once you have the ISO file, create the installation media: HTML Alpine Linux documentation: Using the image Now, boot your system using your brand-new installer. ## Writable boot media creation In this step, we will need to boot on the Alpine installer to create a new Alpine installer, but writable. You need another USB media for this step, the one that will keep your system and data. On Alpine Linux, you can use `setup-alpine` to configure your network, key map and a few things for the current system. You only have to say "none" when you are asked what you want to install, where, and if you want to store the configuration somewhere. Run the following commands on the destination USB drive (networking is required to install a package), this will format it and use all the space as a FAT32 partition. In the example below, the drive is `/dev/sdc`. ```shell apk add parted parted /dev/sdc -- mklabel gpt parted /dev/sdc -- mkpart ESP fat32 1MB 100% parted /dev/sdc -- set 1 esp on ``` This creates a GPT table on `/dev/sdc`, then creates a first partition as FAT32 from the first megabyte up to the full disk size, and finally marks it bootable. This guide is only for UEFI compatible systems. We actually have to format the drive as FAT32, otherwise it's just a partition type without a way to mount it as FAT32: ``` mkfs.vfat /dev/sdc1 modprobe vfat ``` Final step, we use an Alpine tool to copy the bootloader from the installer to our new disk. In the example below, your installer may be `/media/usb` and the destination `/dev/sdc1`, you could figure the first one using `mount`. ``` setup-bootable /media/usb /dev/sdc1 ``` At this step, you made a USB disk in FAT32 containing the Alpine Linux installer you were using live. Reboot on the new one. ## System installation On your new installation media, run `setup-alpine` as if you were installing Alpine Linux, but answer "none" when you are asked which disk you want to use. When asked "Enter where to store configs", you should be prompted your new device by default, accept. Immediately, after, you will be prompted for an APK cache, accept. At this point, we can say Alpine is installed! Don't reboot yet, you are already on your new system! Just use it, and run `lbu commit` when you need to save changes done to packages or `/etc/`. `lbu commit` creates a new tarball in your USB disk containing a list of files configured in `/etc/apk/protected_paths.d/`, and this tarball is loaded at boot time, and will install your package list quickly from the local cache. HTML Alpine Linux wiki: Alpine local backup (lbu command documentation) Please take extra care that if you include more files, everything you commit the changes, they have to be stored on your USB media. You could modify the fstab to add an extra disk/partition for persistent data on a performant drive. # Updating the kernel The kernel can't be upgraded using apk, you have to use the script `update-kernel` that will create a "modloop" file in the boot partition which contains the boot image. You can't rollback this file. You will need a few gigabytes in your in-memory filesystem, or use a temporary build directory by affecting `TMPDIR` variable to a persistent storage. By default, tmpfs on root is set to 1 GB, this can be increased given you have enough memory using the command: `mount -o remount,size=6G /`. The script should have the boot directory as a parameter, so it should look like `update-kernel /media/usb/boot` in a default setup, if you use an external partition, this would look like `env TMPDIR=/mnt/something/ update-kernel /media/usb/boot`. ## Extra configuration Here is a list of tweaks to improve your experience! ### keep last n configuration By default, lbu will only keep the last version you save, by setting`BACKUP_LIMIT` to a number n, you will always have the last n versions of your system stored in the boot media, this is practical if you want to roll back a change. ### apk repositories Edit `/etc/apk/repositories` to uncomment the community repository. ### fstab check Edit `/etc/fstab` to make sure the disk you are using is explicitly configured using a UUID entry, if you only have this: ``` /dev/cdrom /media/cdrom iso9660 noauto,ro 0 0 /dev/usbdisk /media/usb vfat noauto,ro 0 0 ``` This mean your system may have troubles if you use it on a different computer or that you plug another USB disk in it. Fix by using the UUID of your partition, you can find it using the program `blkid` from the eponym package, and fix the fstab like this: ``` UUID=61B2-04FA /media/persist vfat noauto,ro 0 0 /dev/cdrom /media/cdrom iso9660 noauto,ro 0 0 /dev/usbdisk /media/usb vfat noauto,ro 0 0 ``` This will ALWAYS mount your drive as `/media/persist`. If you had to make the change, you need to make some extra changes to keep things coherent: * set `LBU_MEDIA=persist` into `/etc/lbu/lbu.conf` * umount the drive in `/media` and run `mkdir -p /media/persist && mount -a`, you should have `/media/persist` with data in it * run `lbu commit` to save the changes ### desktop setup You can install a graphical desktop, this can easily be done with these commands: ``` setup-desktop xfce setup-xorg-base ``` Due to a bug, we have to re-enable some important services, otherwise you would not have networking at the next boot: ``` rc-update add hwdrivers sysinit ``` HTML Alpine bug report #9653 You may want to enable the display manager at boot, which may be lightdm, gdm or sddm depending on your desktop: ``` rc-update add lightdm ``` ### user persistency If you added a user during `setup-alpine`, its home directory has been automatically added to `/etc/apk/protected_paths.d/lbu.list`, when you run `lbu commit`, its whole home is stored. This may not be desired. If you don't want to save the whole home directory, but only a selection of files/directories, here is how to proceed: 1. edit `/etc/apk/protected_paths.d/lbu.list` to remove the line adding your user directory 2. you need to create the user directory at boot with the correct permissions: `echo "install -d -o solene -g solene -m 700 /home/solene" | doas tee /etc/local.d/00-user.start` 3. in case you have some persistency set at least one user sub directories, it's important to fix the permissions of all the user data after the boot: `echo "chown -R solene:solene /home/solene | doas tee -a /etc/local.d/00-user.start` 4. you need to mark this script as executable: `doas chmod +x /etc/local.d/00-user.start` 5. you need to run the local scripts at boot time: `doas rc-update add local` 6. save the changes: `doas lbu commit` I'd recommend the use of a directory named `Persist` and adding it to the lbu list. Doing so, you have a place to store some important data without having to save all your home directory (including garbage such as cache). This is even nicer if you use ecryptfs as explained below. ### extra convenience Because Alpine Linux is packaged in a minimalistic manner, you may have to install a lot of extra packages to have all the fonts, icons, emojis, cursors etc... working correctly as you would expect for a standard Linux desktop. Fortunately, there is a community guide explaining each section you may want to configure. HTML Alpine Linux wiki: Post installation ### Set X default keyboard layout Alpine insists of you using a qwerty desktop for X until you log into your session, this can be complicated to type passwords. You can create a file `/etc/X11/xorg.conf.d/00-keyboard.conf` like in the linked example and choose your default keyboard layout. You will have to create the directories `/etc/X11/xorg.conf.d` first. HTML Arch Linux wiki: Keyboard configuration ### encrypted personal directory You could use ecryptfs to either encrypt the home partition of your user, or just give it a Private directory that could be unlocked on demand AND made persistent without pulling all the user files at every configuration commit. ``` $ doas apk add ecryptfs-utils $ doas modprobe ecryptfs $ ecryptfs-setup-private Enter your login passphrase [solene]: Enter your mount passphrase [leave blank to generate one]: [...] $ doas lbu add $HOME/.Private $ doas lbu add $HOME/.ecryptfs $ echo "install -d -o solene -g solene -m 700 /home/solene/Private" | doas tee /etc/local.d/50-ecryptfs.start $ doas chmod +x /etc/local.d/50-ecryptfs.start $ doas rc-update add local $ doas lbu commit ``` Now, when you need to access your private directory, run `ecryptfs-mount-private` and you have your `$HOME/Private` directory which is encrypted. You could use ecryptfs to encrypt the whole user directory, this requires extra steps and changes into `/etc/pam.d/base-auth`, don't forget to add `/home/.ecryptfs` to the lbu include list. HTML Using ecryptfs guide # Security Let's be clear, this setup isn't secure! The weak part is the boot media, which doesn't use secure boot, could easily be modified, and has nothing encrypted (except the local backups, but NOT BY DEFAULT). However, once the system has booted, if you remove the boot media, nothing can be damaged as everything lives in memory, but you should still use passwords for your users. # Conclusion Alpine is a very good platform for this kind of setup, and they provide all the tools out of the box! It's a very fun setup to play with. Don't forget that by default everything runs from memory without persistency, so be careful if you generate data you don't want to lose (passwords, downloads, etc...). # Going further The lbu configuration can be encrypted, this is recommended if you plan to carry your disk around, especially if it contains sensitive data. You can use the fat32 partition only for the bootloader and the local backup files, but you could have an extra partition that could be mounted for /home or something, and why not a layer of LUKS for encryption. You may want to use zram if you are tight on memory, this creates a compressed block device that could be used for swap, it's basically compressed RAM, it's very efficient but less useful if you have a slow CPU.