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.
       
 (HTM) Alpine Linux official project website
 (HTM) 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.
       
 (HTM) 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:
       
 (HTM) 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.
       
 (HTM) 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
       ```
       
 (HTM) 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.
       
 (HTM) 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.
       
 (HTM) 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.
       
 (HTM) 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.