<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.alpinelinux.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Garritfra</id>
	<title>Alpine Linux - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.alpinelinux.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Garritfra"/>
	<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/wiki/Special:Contributions/Garritfra"/>
	<updated>2026-04-27T03:00:53Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Immutable_root_with_atomic_upgrades&amp;diff=21200</id>
		<title>Immutable root with atomic upgrades</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Immutable_root_with_atomic_upgrades&amp;diff=21200"/>
		<updated>2021-12-31T14:23:42Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: /* Bootloader installation */ add reference to btrfs page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== What? ===&lt;br /&gt;
This article provides a basic guide to setting up a read-only-root-based Alpine Linux system with several boot environments and atomic upgrades using rEFInd and [[BTRFS|btrfs]].&lt;br /&gt;
&lt;br /&gt;
=== Why? ===&lt;br /&gt;
Read-only root and atomic upgrades with ability to easily rollback or boot previous configurations is a concept that got some popularity recently. Distributions providing and promoting such features, for example, are [https://silverblue.fedoraproject.org/ Fedora Silverblue], [https://microos.opensuse.org/ Opensuse MicroOS], [https://nixos.org NixOS] and [https://guix.gnu.org GNU Guix].&lt;br /&gt;
&lt;br /&gt;
While Alpine Linux has it&#039;s killer features it lacks mentioned above ones on default setup. This is a proof of concept that it&#039;s possible to implement them in a minimal way on a minimal system.&lt;br /&gt;
&lt;br /&gt;
{{Note|Alpine Linux can also boot from RAM in &#039;&#039;&#039;diskless mode&#039;&#039;&#039; (see [[Installation]]) which supports preserving changes between reboots using [[lbu]].}}&lt;br /&gt;
&lt;br /&gt;
= Preparation =&lt;br /&gt;
You should have bootable Alpine media. The process to obtain it decribed on the [[Installation|installation page.]]&lt;br /&gt;
{{Warning|Since version available in Alpine repositories lacks [[BTRFS|btrfs]] driver you should download rEFInd on [https://www.rodsbooks.com/refind/getting.html the official website] and copy it to installation media}}&lt;br /&gt;
&lt;br /&gt;
= Partitioning disks =&lt;br /&gt;
In this guide it is assumed that you have a fresh UEFI system without OS and just managed to boot into live Alpine using USB flash drive or CD.&lt;br /&gt;
The first step is creating partition table on your HDD/SSD target device (&amp;lt;code&amp;gt;/dev/sda&amp;lt;/code&amp;gt; here):&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add gptfdisk&lt;br /&gt;
# gdisk /dev/sda&lt;br /&gt;
&amp;gt; o ↵&lt;br /&gt;
&amp;gt; y ↵&lt;br /&gt;
&amp;gt; w ↵&lt;br /&gt;
&amp;gt; y ↵&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can define the partitions:&lt;br /&gt;
&amp;lt;pre&amp;gt;# cgdisk /dev/sda&amp;lt;/pre&amp;gt;&lt;br /&gt;
Partition creation process consists of several steps:&lt;br /&gt;
# Start sector - you can safely use default value by pressing ↵&lt;br /&gt;
# Size&lt;br /&gt;
# Type (as hex code) - EFI is ef00, Linux filesystem is 8300, Swap is 8200.&lt;br /&gt;
Result table:&lt;br /&gt;
&amp;lt;pre&amp;gt;Part.     #     Size        Partition Type            Partition Name&lt;br /&gt;
----------------------------------------------------------------&lt;br /&gt;
1               200.0 MiB   EFI System                EFI&lt;br /&gt;
2               200.0 GiB   Linux filesystem          ROOT&lt;br /&gt;
3               32.0 GiB    Linux swap                SWAP&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;ROOT&amp;lt;/code&amp;gt; partition name will later be used in rEFInd configuration to identify boot volume.&lt;br /&gt;
Next step is creating filesystems:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkfs.vfat -F32 /dev/sda1&lt;br /&gt;
# mkfs.btrfs /dev/sda2&lt;br /&gt;
# mkswap /dev/sda3&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can mount our root volume:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mount -t btrfs /dev/sda2 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
= File system structure =&lt;br /&gt;
Now we should create file structure that would provide reliable atomic system upgrades.&amp;lt;br&amp;gt;&lt;br /&gt;
Start with following directories:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/next&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores next &amp;lt;code&amp;gt;current&amp;lt;/code&amp;gt; link, is necessary due to how busybox &amp;lt;code&amp;gt;mv&amp;lt;/code&amp;gt; does atomic link replacement.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/commons&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores common non-snapshotting subvolumes.&amp;lt;br&amp;gt;&lt;br /&gt;
We may populate it right away:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@tmp&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@var@cache&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@var@log&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@home&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you use flatpak, you may also want to keep it&#039;s directory separate:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@lib@flatpak&amp;lt;/pre&amp;gt;&lt;br /&gt;
Include anything else in &amp;lt;code&amp;gt;/var&amp;lt;/code&amp;gt; that should be mutable, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@lib@iwd&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, most important directories:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/snapshots&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores directories containing snapshots belonging to one generation.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/links&amp;lt;/pre&amp;gt; &lt;br /&gt;
Stores generations of directories containing links to snapshot generations.&amp;lt;br&amp;gt;&lt;br /&gt;
Let&#039;s create first generation and populate it with one OS root snapshot &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;# NEWSNAPSHOTS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot;&lt;br /&gt;
# mkdir &amp;quot;/mnt/snapshots/$NEWSNAPSHOTS&amp;quot;&lt;br /&gt;
# btrfs subvolume create /mnt/snapshots/$NEWSNAPSHOTS/@&amp;lt;/pre&amp;gt;&lt;br /&gt;
Populate &amp;lt;code&amp;gt;links&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;# NEWLINKS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot;&lt;br /&gt;
# mkdir &amp;quot;/mnt/links/$NEWLINKS&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/0&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/1&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/2&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/3&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can have as many links as you like, just apply changes to rEFInd config and upgrade scripts described below accordingly.&amp;lt;br&amp;gt;&lt;br /&gt;
Link that will point to latest links generation:&lt;br /&gt;
&amp;lt;pre&amp;gt;# ln -s &amp;quot;./links/$NEWLINKS&amp;quot; /mnt/current&amp;lt;/pre&amp;gt;&lt;br /&gt;
This setup allows us to just have static rEFInd config that points to to &amp;lt;code&amp;gt;/current/0/@&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/current/1/@&amp;lt;/code&amp;gt;, etc. while the actual underlying boot environment will change with each upgrade.&amp;lt;br&amp;gt;&lt;br /&gt;
But how will fs mounting services know which snapshot generation is currently loaded?&amp;lt;br&amp;gt;&lt;br /&gt;
The answer is common &amp;lt;code&amp;gt;fstab&amp;lt;/code&amp;gt; in the [[BTRFS|btrfs]] root.&amp;lt;br&amp;gt;&lt;br /&gt;
Get UUIDs of the partitions first:&lt;br /&gt;
&amp;lt;pre&amp;gt;# blkid &amp;gt; /mnt/fstab&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now edit fstab accordingly:&lt;br /&gt;
&amp;lt;pre&amp;gt;# vi /mnt/fstab&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 / btrfs subvol=CURRENT_SNAPSHOTS_PATH/@,ro,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/tmp btrfs subvol=/commons/@var@tmp,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/cache btrfs subvol=/commons/@var@cache,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/log btrfs subvol=/commons/@var@log,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/lib/flatpak btrfs subvol=/commons/@var@lib@flatpak,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/lib/iwd btrfs subvol=/commons/@var@lib@iwd,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /home btrfs subvol=/commons/@home,rw,noatime 0 0&lt;br /&gt;
# UUID=2FE6-837A /boot/efi vfat rw,noatime,discard 0 2&lt;br /&gt;
tmpfs /tmp tmpfs mode=1777,noatime,nosuid,nodev,size=2G 0 0&lt;br /&gt;
UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 swap swap rw,noatime,discard 0 0&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;CURRENT_SNAPSHOTS_PATH&amp;lt;/code&amp;gt; will be replaced by scripts with, for example, &amp;lt;code&amp;gt;/snapshots/20210411212549sdBXyLxg&amp;lt;/code&amp;gt;, and the result will be piped into &amp;lt;code&amp;gt;/etc/fstab&amp;lt;/code&amp;gt; of a created &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; snapshot during new generation preparations.&amp;lt;br&amp;gt;&lt;br /&gt;
Root [[BTRFS|btrfs]] volume structure mounted on &amp;lt;code&amp;gt;/mnt&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;|--mnt&lt;br /&gt;
| |--commons&lt;br /&gt;
| | |--@var@tmp&lt;br /&gt;
| | |--@var@cache&lt;br /&gt;
| | |--@var@log&lt;br /&gt;
| | |--@var@lib@flatpak&lt;br /&gt;
| | |--@var@lib@iwd&lt;br /&gt;
| | |--@home&lt;br /&gt;
| |--current&lt;br /&gt;
| |--fstab&lt;br /&gt;
| |--links&lt;br /&gt;
| | |--20210411213742qwrXAJBz&lt;br /&gt;
| | | |--0&lt;br /&gt;
| | | |--1&lt;br /&gt;
| | | |--2&lt;br /&gt;
| | | |--3&lt;br /&gt;
| |--next&lt;br /&gt;
| |--snapshots&lt;br /&gt;
| | |--20210411212549sdBXyLxg&lt;br /&gt;
| | | |--@&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Base system install =&lt;br /&gt;
With the directory strtucture prepared we can start installation of a basic Alpine Linux system.&amp;lt;br&amp;gt;&lt;br /&gt;
Considering that installation is done from Alpine system, we only need following parts of [[Alpine_Linux_in_a_chroot|the process]]:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk -X https://dl-cdn.alpinelinux.org/alpine/latest-stable/main -U --allow-untrusted -p /mnt/snapshots/20210411212549sdBXyLxg/@ --initdb add alpine-base&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can setup basic chroot to complete the installation process:&lt;br /&gt;
&amp;lt;pre&amp;gt;# export SNP=&amp;quot;/mnt/snapshots/20210411212549sdBXyLxg/@&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# mount -o bind /dev $SNP/dev&lt;br /&gt;
# mount -t proc none $SNP/proc&lt;br /&gt;
# mount -t sysfs sys $SNP/sys&lt;br /&gt;
&lt;br /&gt;
# sed &amp;quot;s#CURRENT_SNAPSHOTS_PATH#/snapshots/20210411212549sdBXyLxg#g&amp;quot; /mnt/fstab &amp;gt; &amp;quot;$SNP/etc/fstab&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# cp -L /etc/resolv.conf &amp;quot;$SNP/etc/&amp;quot;&lt;br /&gt;
# chroot &amp;quot;$SNP&amp;quot; /bin/sh&lt;br /&gt;
&lt;br /&gt;
# mount -a&lt;br /&gt;
&lt;br /&gt;
# mv /etc/resolv.conf /tmp/&lt;br /&gt;
# ln -s /tmp/resolv.conf /etc/resolv.conf&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as you in chroot, define repositories:&lt;br /&gt;
&amp;lt;pre&amp;gt;# echo &amp;quot;https://dl-cdn.alpinelinux.org/alpine/latest-stable/main&amp;quot; &amp;gt; /etc/apk/repositories&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example shows only &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;, but you should also add &amp;lt;code&amp;gt;testing&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;community&amp;lt;/code&amp;gt; if you need any packages in those.&amp;lt;br&amp;gt;&lt;br /&gt;
Now it&#039;s time for firmware, kernel and btrfs packages:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add -U linux-firmware linux-lts btrfs-progs&amp;lt;/pre&amp;gt;&lt;br /&gt;
You may want to change &amp;lt;code&amp;gt;linux-firmware&amp;lt;/code&amp;gt; to a custom set of firmware packages suitable for you system, for example &amp;lt;code&amp;gt;linux-firmware-amd linux-firmware-amd-ucode linux-firmware-amdgpu linux-firmware-ath10k linux-firmware-qca&amp;lt;/code&amp;gt; for typical AMD laptop.&amp;lt;br&amp;gt;&lt;br /&gt;
It is also important to add &amp;lt;code&amp;gt;btrfs&amp;lt;/code&amp;gt; feature to &amp;lt;code&amp;gt;mkinitfs.conf&amp;lt;/code&amp;gt; and run &amp;lt;code&amp;gt;mkinitfs&amp;lt;/code&amp;gt; manually:&lt;br /&gt;
&amp;lt;pre&amp;gt;# vi /etc/mkinitfs/mkinitfs.conf&lt;br /&gt;
# mkinitfs&amp;lt;/pre&amp;gt;&lt;br /&gt;
These steps prepare kernel and generate &amp;lt;code&amp;gt;initramfs&amp;lt;/code&amp;gt; which later will be used to boot from our first snapshot.&amp;lt;br&amp;gt;&lt;br /&gt;
After that you should install any package you may need on first boot.&lt;br /&gt;
&lt;br /&gt;
{{Warning|In case your PC only has wireless connection you should also install any suitable networking software, like &amp;lt;code&amp;gt;iwd&amp;lt;/code&amp;gt; in this example, so you will not end up severed from network on your first boot.}}&lt;br /&gt;
&lt;br /&gt;
{{Note|Due to root being immutable during operation, it&#039;s recommended to install package &amp;lt;code&amp;gt;openresolv&amp;lt;/code&amp;gt; to support changing network connection. In this case &amp;lt;code&amp;gt;/etc/resolvconf.conf&amp;lt;/code&amp;gt; should have &amp;lt;code&amp;gt;resolv_conf{{=}}/tmp/resolv.conf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/etc/resolv.conf&amp;lt;/code&amp;gt; should be moved to &amp;lt;code&amp;gt;/tmp/resolv.conf&amp;lt;/code&amp;gt; and a link to the new resolv.conf location should be created: &amp;lt;code&amp;gt;ln -sfn /tmp/resolv.conf /etc/resolv.conf&amp;lt;/code&amp;gt;.&lt;br /&gt;
You may also use static DNS, but this would make your network activity directly identifiable to the DNS server provider, therefore it&#039;s not recommended.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Now, configure the system, start with setting a password for the root:&lt;br /&gt;
&amp;lt;pre&amp;gt;# passwd root&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With the snapshot prepared and configured we can chroot out of it and unmount everything:&lt;br /&gt;
&amp;lt;pre&amp;gt;# umount -a&lt;br /&gt;
# exit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finish editing snapshot by setting &amp;lt;code&amp;gt;ro&amp;lt;/code&amp;gt; flag and unmounting root volume:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs property set -ts &amp;quot;/mnt/snapshots/20210411212549sdBXyLxg/@&amp;quot; ro true&lt;br /&gt;
# umount /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Bootloader installation =&lt;br /&gt;
{{Note|The example demonstrated here only make use of rEFInd bootloader as it is relatively easy to install manually and generally easy to use. You may however setup any prefered bootloader given it supports [[BTRFS|btrfs]] and can be configured to boot specific snapshot.}}&lt;br /&gt;
Mount the EFI partition:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mount -t vfat /dev/sda1 /mnt&lt;br /&gt;
# mkdir /mnt/EFI&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unpack prepared rEFInd archive and copy relevant files to &amp;lt;code&amp;gt;/mnt/EFI/&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# unzip refind-bin-version.zip&lt;br /&gt;
# cp -r refind-bin-version/refind /mnt/EFI/&lt;br /&gt;
# cd /mnt/EFI/refind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Delete all unnecessary files - everything that is not for your CPU architecture:&lt;br /&gt;
&amp;lt;pre&amp;gt;# rm -r drivers_aa64 drivers_ia32 tools_aa64 tools_ia32 refind_aa64.efi refind_ia32.efi&amp;lt;/pre&amp;gt;&lt;br /&gt;
Rename config file and edit it:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mv refind.conf-sample refind.conf&lt;br /&gt;
# vi refind.conf&amp;lt;/pre&amp;gt;&lt;br /&gt;
And append following to the end of the file, remember to replace example UUIDs with your own for &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; ([[BTRFS|btrfs]] partition) and &amp;lt;code&amp;gt;resume&amp;lt;/code&amp;gt; (swap partition):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
menuentry &amp;quot;Alpine Linux&amp;quot; {&lt;br /&gt;
    icon /EFI/refind/icons/os_linux.png&lt;br /&gt;
    volume &amp;quot;ROOT&amp;quot;&lt;br /&gt;
    loader /current/0/@/boot/vmlinuz-lts&lt;br /&gt;
    initrd /current/0/@/boot/initramfs-lts&lt;br /&gt;
    options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/0/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 1&amp;quot; {&lt;br /&gt;
        loader /current/1/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/1/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/1/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 2&amp;quot; {&lt;br /&gt;
        loader /current/2/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/2/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/2/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 3&amp;quot; {&lt;br /&gt;
        loader /current/3/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/3/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/3/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
{{Note|&amp;lt;code&amp;gt;&amp;quot;ROOT&amp;quot;&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;PARTLABEL&amp;lt;/code&amp;gt; of the [[BTRFS|btrfs]] partition. You may also use &amp;lt;code&amp;gt;PARTUUID&amp;lt;/code&amp;gt; instead. To get both &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; package can be used. &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; included in busybox does not provide this information. }}&lt;br /&gt;
To add rEFInd to UEFI, &amp;lt;code&amp;gt;efibootmgr&amp;lt;/code&amp;gt; is a suitable tool:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add efibootmgr&lt;br /&gt;
# efibootmgr --create --disk /dev/sda --part 1 --loader /EFI/refind/refind_x64.efi --label &amp;quot;rEFInd&amp;quot; --verbose&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/dev/sda&amp;lt;/code&amp;gt; is our disk device and &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; is the number of partition containing &amp;lt;code&amp;gt;rEFInd&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Updating or altering the system =&lt;br /&gt;
&amp;lt;pre&amp;gt;# touch /sbin/sysmut&lt;br /&gt;
# chmod +x /sbin/sysmut&lt;br /&gt;
# vi /sbin/sysmut&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example script to mutate the the system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
ROOTVOLMNT=&amp;quot;/vol/root&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t btrfs -o rw,noatime UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 &amp;quot;$ROOTVOLMNT&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
NEWSNAPSHOTS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
btrfs subvolume snapshot &amp;quot;$ROOTVOLMNT/current/0/@&amp;quot; &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
sed &amp;quot;s#CURRENT_SNAPSHOTS_PATH#/snapshots/$NEWSNAPSHOTS#g&amp;quot; &amp;quot;$ROOTVOLMNT/fstab&amp;quot; &amp;gt; &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/etc/fstab&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t proc none &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/proc&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t sysfs sys &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/sys&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -o bind /dev &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/dev&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
chroot &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; /bin/sh -c &#039;mount -a; sh; APPLY=$?; umount -a; exit $APPLY&#039; &amp;amp;&amp;amp; \&lt;br /&gt;
btrfs property set -ts &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; ro true &amp;amp;&amp;amp; \&lt;br /&gt;
NEWLINKS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/links/$NEWLINKS&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/0&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/0&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/1&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/1&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/2&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/2&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/3&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/next&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
ln -sfn &amp;quot;./links/$NEWLINKS&amp;quot; &amp;quot;$ROOTVOLMNT/next/current&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mv &amp;quot;$ROOTVOLMNT/next/current&amp;quot; &amp;quot;$ROOTVOLMNT/&amp;quot; \&lt;br /&gt;
&amp;amp;&amp;amp; echo &amp;quot;Switched to the new snapshots&amp;quot; \&lt;br /&gt;
|| echo &amp;quot;Changes discarded&amp;quot;&lt;br /&gt;
umount &amp;quot;$ROOTVOLMNT&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It will get you into the root shell chrooted into the new snapshot, where you can apply any change you like.&amp;lt;br&amp;gt;&lt;br /&gt;
If chroot shell exits with an error, there will be no switch to the new snapshots. This means you can manually discard changes while in the chroot by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# exit 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Deleting unused snapshots =&lt;br /&gt;
Unused snapshots can be garbage-collected by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# touch /sbin/syscln&lt;br /&gt;
# chmod +x /sbin/syscln&lt;br /&gt;
# vi /sbin/syscln&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
ROOTVOLMNT=&amp;quot;/vol/root&amp;quot;&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT&amp;quot;&lt;br /&gt;
mount -t btrfs -o rw,noatime UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 &amp;quot;$ROOTVOLMNT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
SNAPSHOTS=$({ \&lt;br /&gt;
    find &amp;quot;$ROOTVOLMNT/snapshots/&amp;quot; -maxdepth 1 -mindepth 1&lt;br /&gt;
    find &amp;quot;$ROOTVOLMNT/current/&amp;quot; -maxdepth 1 -mindepth 1 \&lt;br /&gt;
        | xargs -n 1 readlink -f&lt;br /&gt;
} | sort | uniq -u)&lt;br /&gt;
&lt;br /&gt;
if [ -z &amp;quot;$SNAPSHOTS&amp;quot; ]; then&lt;br /&gt;
    echo &amp;quot;Nothing to remove&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    printf %s\\n &amp;quot;$SNAPSHOTS&amp;quot; \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 -n 1 -I {} find {} -maxdepth 1 -mindepth 1 \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 btrfs subvolume delete&lt;br /&gt;
    printf %s\\n &amp;quot;$SNAPSHOTS&amp;quot; \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 rm -r&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
umount &amp;quot;$ROOTVOLMNT&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Allowing temporary runtime alterations =&lt;br /&gt;
You can use &amp;lt;code&amp;gt;overlayfs&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;tmpfs&amp;lt;/code&amp;gt; built into Alpine&#039;s init script to allow changes in the rootfs which will be automatically reverted upon reboot.&amp;lt;br&amp;gt;&lt;br /&gt;
To make use this just add &amp;lt;code&amp;gt;overlaytmpfs&amp;lt;/code&amp;gt; to the kernel boot options in &amp;lt;code&amp;gt;refind.conf&amp;lt;/code&amp;gt;, e.g.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    initrd /current/0/@/boot/initramfs-lts&lt;br /&gt;
    options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/0/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 overlaytmpfs quiet splash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 1&amp;quot; {&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Immutable_root_with_atomic_upgrades&amp;diff=21199</id>
		<title>Immutable root with atomic upgrades</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Immutable_root_with_atomic_upgrades&amp;diff=21199"/>
		<updated>2021-12-31T14:22:47Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: /* File system structure */ add reference to btrfs page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== What? ===&lt;br /&gt;
This article provides a basic guide to setting up a read-only-root-based Alpine Linux system with several boot environments and atomic upgrades using rEFInd and [[BTRFS|btrfs]].&lt;br /&gt;
&lt;br /&gt;
=== Why? ===&lt;br /&gt;
Read-only root and atomic upgrades with ability to easily rollback or boot previous configurations is a concept that got some popularity recently. Distributions providing and promoting such features, for example, are [https://silverblue.fedoraproject.org/ Fedora Silverblue], [https://microos.opensuse.org/ Opensuse MicroOS], [https://nixos.org NixOS] and [https://guix.gnu.org GNU Guix].&lt;br /&gt;
&lt;br /&gt;
While Alpine Linux has it&#039;s killer features it lacks mentioned above ones on default setup. This is a proof of concept that it&#039;s possible to implement them in a minimal way on a minimal system.&lt;br /&gt;
&lt;br /&gt;
{{Note|Alpine Linux can also boot from RAM in &#039;&#039;&#039;diskless mode&#039;&#039;&#039; (see [[Installation]]) which supports preserving changes between reboots using [[lbu]].}}&lt;br /&gt;
&lt;br /&gt;
= Preparation =&lt;br /&gt;
You should have bootable Alpine media. The process to obtain it decribed on the [[Installation|installation page.]]&lt;br /&gt;
{{Warning|Since version available in Alpine repositories lacks [[BTRFS|btrfs]] driver you should download rEFInd on [https://www.rodsbooks.com/refind/getting.html the official website] and copy it to installation media}}&lt;br /&gt;
&lt;br /&gt;
= Partitioning disks =&lt;br /&gt;
In this guide it is assumed that you have a fresh UEFI system without OS and just managed to boot into live Alpine using USB flash drive or CD.&lt;br /&gt;
The first step is creating partition table on your HDD/SSD target device (&amp;lt;code&amp;gt;/dev/sda&amp;lt;/code&amp;gt; here):&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add gptfdisk&lt;br /&gt;
# gdisk /dev/sda&lt;br /&gt;
&amp;gt; o ↵&lt;br /&gt;
&amp;gt; y ↵&lt;br /&gt;
&amp;gt; w ↵&lt;br /&gt;
&amp;gt; y ↵&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can define the partitions:&lt;br /&gt;
&amp;lt;pre&amp;gt;# cgdisk /dev/sda&amp;lt;/pre&amp;gt;&lt;br /&gt;
Partition creation process consists of several steps:&lt;br /&gt;
# Start sector - you can safely use default value by pressing ↵&lt;br /&gt;
# Size&lt;br /&gt;
# Type (as hex code) - EFI is ef00, Linux filesystem is 8300, Swap is 8200.&lt;br /&gt;
Result table:&lt;br /&gt;
&amp;lt;pre&amp;gt;Part.     #     Size        Partition Type            Partition Name&lt;br /&gt;
----------------------------------------------------------------&lt;br /&gt;
1               200.0 MiB   EFI System                EFI&lt;br /&gt;
2               200.0 GiB   Linux filesystem          ROOT&lt;br /&gt;
3               32.0 GiB    Linux swap                SWAP&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;ROOT&amp;lt;/code&amp;gt; partition name will later be used in rEFInd configuration to identify boot volume.&lt;br /&gt;
Next step is creating filesystems:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkfs.vfat -F32 /dev/sda1&lt;br /&gt;
# mkfs.btrfs /dev/sda2&lt;br /&gt;
# mkswap /dev/sda3&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can mount our root volume:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mount -t btrfs /dev/sda2 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
= File system structure =&lt;br /&gt;
Now we should create file structure that would provide reliable atomic system upgrades.&amp;lt;br&amp;gt;&lt;br /&gt;
Start with following directories:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/next&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores next &amp;lt;code&amp;gt;current&amp;lt;/code&amp;gt; link, is necessary due to how busybox &amp;lt;code&amp;gt;mv&amp;lt;/code&amp;gt; does atomic link replacement.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/commons&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores common non-snapshotting subvolumes.&amp;lt;br&amp;gt;&lt;br /&gt;
We may populate it right away:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@tmp&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@var@cache&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@var@log&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@home&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you use flatpak, you may also want to keep it&#039;s directory separate:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@lib@flatpak&amp;lt;/pre&amp;gt;&lt;br /&gt;
Include anything else in &amp;lt;code&amp;gt;/var&amp;lt;/code&amp;gt; that should be mutable, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@lib@iwd&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, most important directories:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/snapshots&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores directories containing snapshots belonging to one generation.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/links&amp;lt;/pre&amp;gt; &lt;br /&gt;
Stores generations of directories containing links to snapshot generations.&amp;lt;br&amp;gt;&lt;br /&gt;
Let&#039;s create first generation and populate it with one OS root snapshot &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;# NEWSNAPSHOTS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot;&lt;br /&gt;
# mkdir &amp;quot;/mnt/snapshots/$NEWSNAPSHOTS&amp;quot;&lt;br /&gt;
# btrfs subvolume create /mnt/snapshots/$NEWSNAPSHOTS/@&amp;lt;/pre&amp;gt;&lt;br /&gt;
Populate &amp;lt;code&amp;gt;links&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;# NEWLINKS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot;&lt;br /&gt;
# mkdir &amp;quot;/mnt/links/$NEWLINKS&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/0&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/1&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/2&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/3&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can have as many links as you like, just apply changes to rEFInd config and upgrade scripts described below accordingly.&amp;lt;br&amp;gt;&lt;br /&gt;
Link that will point to latest links generation:&lt;br /&gt;
&amp;lt;pre&amp;gt;# ln -s &amp;quot;./links/$NEWLINKS&amp;quot; /mnt/current&amp;lt;/pre&amp;gt;&lt;br /&gt;
This setup allows us to just have static rEFInd config that points to to &amp;lt;code&amp;gt;/current/0/@&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/current/1/@&amp;lt;/code&amp;gt;, etc. while the actual underlying boot environment will change with each upgrade.&amp;lt;br&amp;gt;&lt;br /&gt;
But how will fs mounting services know which snapshot generation is currently loaded?&amp;lt;br&amp;gt;&lt;br /&gt;
The answer is common &amp;lt;code&amp;gt;fstab&amp;lt;/code&amp;gt; in the [[BTRFS|btrfs]] root.&amp;lt;br&amp;gt;&lt;br /&gt;
Get UUIDs of the partitions first:&lt;br /&gt;
&amp;lt;pre&amp;gt;# blkid &amp;gt; /mnt/fstab&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now edit fstab accordingly:&lt;br /&gt;
&amp;lt;pre&amp;gt;# vi /mnt/fstab&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 / btrfs subvol=CURRENT_SNAPSHOTS_PATH/@,ro,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/tmp btrfs subvol=/commons/@var@tmp,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/cache btrfs subvol=/commons/@var@cache,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/log btrfs subvol=/commons/@var@log,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/lib/flatpak btrfs subvol=/commons/@var@lib@flatpak,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/lib/iwd btrfs subvol=/commons/@var@lib@iwd,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /home btrfs subvol=/commons/@home,rw,noatime 0 0&lt;br /&gt;
# UUID=2FE6-837A /boot/efi vfat rw,noatime,discard 0 2&lt;br /&gt;
tmpfs /tmp tmpfs mode=1777,noatime,nosuid,nodev,size=2G 0 0&lt;br /&gt;
UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 swap swap rw,noatime,discard 0 0&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;CURRENT_SNAPSHOTS_PATH&amp;lt;/code&amp;gt; will be replaced by scripts with, for example, &amp;lt;code&amp;gt;/snapshots/20210411212549sdBXyLxg&amp;lt;/code&amp;gt;, and the result will be piped into &amp;lt;code&amp;gt;/etc/fstab&amp;lt;/code&amp;gt; of a created &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; snapshot during new generation preparations.&amp;lt;br&amp;gt;&lt;br /&gt;
Root [[BTRFS|btrfs]] volume structure mounted on &amp;lt;code&amp;gt;/mnt&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;|--mnt&lt;br /&gt;
| |--commons&lt;br /&gt;
| | |--@var@tmp&lt;br /&gt;
| | |--@var@cache&lt;br /&gt;
| | |--@var@log&lt;br /&gt;
| | |--@var@lib@flatpak&lt;br /&gt;
| | |--@var@lib@iwd&lt;br /&gt;
| | |--@home&lt;br /&gt;
| |--current&lt;br /&gt;
| |--fstab&lt;br /&gt;
| |--links&lt;br /&gt;
| | |--20210411213742qwrXAJBz&lt;br /&gt;
| | | |--0&lt;br /&gt;
| | | |--1&lt;br /&gt;
| | | |--2&lt;br /&gt;
| | | |--3&lt;br /&gt;
| |--next&lt;br /&gt;
| |--snapshots&lt;br /&gt;
| | |--20210411212549sdBXyLxg&lt;br /&gt;
| | | |--@&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Base system install =&lt;br /&gt;
With the directory strtucture prepared we can start installation of a basic Alpine Linux system.&amp;lt;br&amp;gt;&lt;br /&gt;
Considering that installation is done from Alpine system, we only need following parts of [[Alpine_Linux_in_a_chroot|the process]]:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk -X https://dl-cdn.alpinelinux.org/alpine/latest-stable/main -U --allow-untrusted -p /mnt/snapshots/20210411212549sdBXyLxg/@ --initdb add alpine-base&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can setup basic chroot to complete the installation process:&lt;br /&gt;
&amp;lt;pre&amp;gt;# export SNP=&amp;quot;/mnt/snapshots/20210411212549sdBXyLxg/@&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# mount -o bind /dev $SNP/dev&lt;br /&gt;
# mount -t proc none $SNP/proc&lt;br /&gt;
# mount -t sysfs sys $SNP/sys&lt;br /&gt;
&lt;br /&gt;
# sed &amp;quot;s#CURRENT_SNAPSHOTS_PATH#/snapshots/20210411212549sdBXyLxg#g&amp;quot; /mnt/fstab &amp;gt; &amp;quot;$SNP/etc/fstab&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# cp -L /etc/resolv.conf &amp;quot;$SNP/etc/&amp;quot;&lt;br /&gt;
# chroot &amp;quot;$SNP&amp;quot; /bin/sh&lt;br /&gt;
&lt;br /&gt;
# mount -a&lt;br /&gt;
&lt;br /&gt;
# mv /etc/resolv.conf /tmp/&lt;br /&gt;
# ln -s /tmp/resolv.conf /etc/resolv.conf&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as you in chroot, define repositories:&lt;br /&gt;
&amp;lt;pre&amp;gt;# echo &amp;quot;https://dl-cdn.alpinelinux.org/alpine/latest-stable/main&amp;quot; &amp;gt; /etc/apk/repositories&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example shows only &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;, but you should also add &amp;lt;code&amp;gt;testing&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;community&amp;lt;/code&amp;gt; if you need any packages in those.&amp;lt;br&amp;gt;&lt;br /&gt;
Now it&#039;s time for firmware, kernel and btrfs packages:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add -U linux-firmware linux-lts btrfs-progs&amp;lt;/pre&amp;gt;&lt;br /&gt;
You may want to change &amp;lt;code&amp;gt;linux-firmware&amp;lt;/code&amp;gt; to a custom set of firmware packages suitable for you system, for example &amp;lt;code&amp;gt;linux-firmware-amd linux-firmware-amd-ucode linux-firmware-amdgpu linux-firmware-ath10k linux-firmware-qca&amp;lt;/code&amp;gt; for typical AMD laptop.&amp;lt;br&amp;gt;&lt;br /&gt;
It is also important to add &amp;lt;code&amp;gt;btrfs&amp;lt;/code&amp;gt; feature to &amp;lt;code&amp;gt;mkinitfs.conf&amp;lt;/code&amp;gt; and run &amp;lt;code&amp;gt;mkinitfs&amp;lt;/code&amp;gt; manually:&lt;br /&gt;
&amp;lt;pre&amp;gt;# vi /etc/mkinitfs/mkinitfs.conf&lt;br /&gt;
# mkinitfs&amp;lt;/pre&amp;gt;&lt;br /&gt;
These steps prepare kernel and generate &amp;lt;code&amp;gt;initramfs&amp;lt;/code&amp;gt; which later will be used to boot from our first snapshot.&amp;lt;br&amp;gt;&lt;br /&gt;
After that you should install any package you may need on first boot.&lt;br /&gt;
&lt;br /&gt;
{{Warning|In case your PC only has wireless connection you should also install any suitable networking software, like &amp;lt;code&amp;gt;iwd&amp;lt;/code&amp;gt; in this example, so you will not end up severed from network on your first boot.}}&lt;br /&gt;
&lt;br /&gt;
{{Note|Due to root being immutable during operation, it&#039;s recommended to install package &amp;lt;code&amp;gt;openresolv&amp;lt;/code&amp;gt; to support changing network connection. In this case &amp;lt;code&amp;gt;/etc/resolvconf.conf&amp;lt;/code&amp;gt; should have &amp;lt;code&amp;gt;resolv_conf{{=}}/tmp/resolv.conf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/etc/resolv.conf&amp;lt;/code&amp;gt; should be moved to &amp;lt;code&amp;gt;/tmp/resolv.conf&amp;lt;/code&amp;gt; and a link to the new resolv.conf location should be created: &amp;lt;code&amp;gt;ln -sfn /tmp/resolv.conf /etc/resolv.conf&amp;lt;/code&amp;gt;.&lt;br /&gt;
You may also use static DNS, but this would make your network activity directly identifiable to the DNS server provider, therefore it&#039;s not recommended.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Now, configure the system, start with setting a password for the root:&lt;br /&gt;
&amp;lt;pre&amp;gt;# passwd root&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With the snapshot prepared and configured we can chroot out of it and unmount everything:&lt;br /&gt;
&amp;lt;pre&amp;gt;# umount -a&lt;br /&gt;
# exit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finish editing snapshot by setting &amp;lt;code&amp;gt;ro&amp;lt;/code&amp;gt; flag and unmounting root volume:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs property set -ts &amp;quot;/mnt/snapshots/20210411212549sdBXyLxg/@&amp;quot; ro true&lt;br /&gt;
# umount /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Bootloader installation =&lt;br /&gt;
{{Note|The example demonstrated here only make use of rEFInd bootloader as it is relatively easy to install manually and generally easy to use. You may however setup any prefered bootloader given it supports btrfs and can be configured to boot specific snapshot.}}&lt;br /&gt;
Mount the EFI partition:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mount -t vfat /dev/sda1 /mnt&lt;br /&gt;
# mkdir /mnt/EFI&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unpack prepared rEFInd archive and copy relevant files to &amp;lt;code&amp;gt;/mnt/EFI/&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# unzip refind-bin-version.zip&lt;br /&gt;
# cp -r refind-bin-version/refind /mnt/EFI/&lt;br /&gt;
# cd /mnt/EFI/refind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Delete all unnecessary files - everything that is not for your CPU architecture:&lt;br /&gt;
&amp;lt;pre&amp;gt;# rm -r drivers_aa64 drivers_ia32 tools_aa64 tools_ia32 refind_aa64.efi refind_ia32.efi&amp;lt;/pre&amp;gt;&lt;br /&gt;
Rename config file and edit it:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mv refind.conf-sample refind.conf&lt;br /&gt;
# vi refind.conf&amp;lt;/pre&amp;gt;&lt;br /&gt;
And append following to the end of the file, remember to replace example UUIDs with your own for &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; (btrfs partition) and &amp;lt;code&amp;gt;resume&amp;lt;/code&amp;gt; (swap partition):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
menuentry &amp;quot;Alpine Linux&amp;quot; {&lt;br /&gt;
    icon /EFI/refind/icons/os_linux.png&lt;br /&gt;
    volume &amp;quot;ROOT&amp;quot;&lt;br /&gt;
    loader /current/0/@/boot/vmlinuz-lts&lt;br /&gt;
    initrd /current/0/@/boot/initramfs-lts&lt;br /&gt;
    options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/0/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 1&amp;quot; {&lt;br /&gt;
        loader /current/1/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/1/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/1/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 2&amp;quot; {&lt;br /&gt;
        loader /current/2/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/2/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/2/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 3&amp;quot; {&lt;br /&gt;
        loader /current/3/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/3/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/3/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
{{Note|&amp;lt;code&amp;gt;&amp;quot;ROOT&amp;quot;&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;PARTLABEL&amp;lt;/code&amp;gt; of the btrfs partition. You may also use &amp;lt;code&amp;gt;PARTUUID&amp;lt;/code&amp;gt; instead. To get both &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; package can be used. &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; included in busybox does not provide this information. }}&lt;br /&gt;
To add rEFInd to UEFI, &amp;lt;code&amp;gt;efibootmgr&amp;lt;/code&amp;gt; is a suitable tool:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add efibootmgr&lt;br /&gt;
# efibootmgr --create --disk /dev/sda --part 1 --loader /EFI/refind/refind_x64.efi --label &amp;quot;rEFInd&amp;quot; --verbose&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/dev/sda&amp;lt;/code&amp;gt; is our disk device and &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; is the number of partition containing &amp;lt;code&amp;gt;rEFInd&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Updating or altering the system =&lt;br /&gt;
&amp;lt;pre&amp;gt;# touch /sbin/sysmut&lt;br /&gt;
# chmod +x /sbin/sysmut&lt;br /&gt;
# vi /sbin/sysmut&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example script to mutate the the system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
ROOTVOLMNT=&amp;quot;/vol/root&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t btrfs -o rw,noatime UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 &amp;quot;$ROOTVOLMNT&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
NEWSNAPSHOTS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
btrfs subvolume snapshot &amp;quot;$ROOTVOLMNT/current/0/@&amp;quot; &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
sed &amp;quot;s#CURRENT_SNAPSHOTS_PATH#/snapshots/$NEWSNAPSHOTS#g&amp;quot; &amp;quot;$ROOTVOLMNT/fstab&amp;quot; &amp;gt; &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/etc/fstab&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t proc none &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/proc&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t sysfs sys &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/sys&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -o bind /dev &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/dev&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
chroot &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; /bin/sh -c &#039;mount -a; sh; APPLY=$?; umount -a; exit $APPLY&#039; &amp;amp;&amp;amp; \&lt;br /&gt;
btrfs property set -ts &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; ro true &amp;amp;&amp;amp; \&lt;br /&gt;
NEWLINKS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/links/$NEWLINKS&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/0&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/0&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/1&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/1&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/2&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/2&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/3&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/next&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
ln -sfn &amp;quot;./links/$NEWLINKS&amp;quot; &amp;quot;$ROOTVOLMNT/next/current&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mv &amp;quot;$ROOTVOLMNT/next/current&amp;quot; &amp;quot;$ROOTVOLMNT/&amp;quot; \&lt;br /&gt;
&amp;amp;&amp;amp; echo &amp;quot;Switched to the new snapshots&amp;quot; \&lt;br /&gt;
|| echo &amp;quot;Changes discarded&amp;quot;&lt;br /&gt;
umount &amp;quot;$ROOTVOLMNT&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It will get you into the root shell chrooted into the new snapshot, where you can apply any change you like.&amp;lt;br&amp;gt;&lt;br /&gt;
If chroot shell exits with an error, there will be no switch to the new snapshots. This means you can manually discard changes while in the chroot by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# exit 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Deleting unused snapshots =&lt;br /&gt;
Unused snapshots can be garbage-collected by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# touch /sbin/syscln&lt;br /&gt;
# chmod +x /sbin/syscln&lt;br /&gt;
# vi /sbin/syscln&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
ROOTVOLMNT=&amp;quot;/vol/root&amp;quot;&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT&amp;quot;&lt;br /&gt;
mount -t btrfs -o rw,noatime UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 &amp;quot;$ROOTVOLMNT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
SNAPSHOTS=$({ \&lt;br /&gt;
    find &amp;quot;$ROOTVOLMNT/snapshots/&amp;quot; -maxdepth 1 -mindepth 1&lt;br /&gt;
    find &amp;quot;$ROOTVOLMNT/current/&amp;quot; -maxdepth 1 -mindepth 1 \&lt;br /&gt;
        | xargs -n 1 readlink -f&lt;br /&gt;
} | sort | uniq -u)&lt;br /&gt;
&lt;br /&gt;
if [ -z &amp;quot;$SNAPSHOTS&amp;quot; ]; then&lt;br /&gt;
    echo &amp;quot;Nothing to remove&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    printf %s\\n &amp;quot;$SNAPSHOTS&amp;quot; \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 -n 1 -I {} find {} -maxdepth 1 -mindepth 1 \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 btrfs subvolume delete&lt;br /&gt;
    printf %s\\n &amp;quot;$SNAPSHOTS&amp;quot; \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 rm -r&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
umount &amp;quot;$ROOTVOLMNT&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Allowing temporary runtime alterations =&lt;br /&gt;
You can use &amp;lt;code&amp;gt;overlayfs&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;tmpfs&amp;lt;/code&amp;gt; built into Alpine&#039;s init script to allow changes in the rootfs which will be automatically reverted upon reboot.&amp;lt;br&amp;gt;&lt;br /&gt;
To make use this just add &amp;lt;code&amp;gt;overlaytmpfs&amp;lt;/code&amp;gt; to the kernel boot options in &amp;lt;code&amp;gt;refind.conf&amp;lt;/code&amp;gt;, e.g.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    initrd /current/0/@/boot/initramfs-lts&lt;br /&gt;
    options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/0/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 overlaytmpfs quiet splash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 1&amp;quot; {&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Immutable_root_with_atomic_upgrades&amp;diff=21198</id>
		<title>Immutable root with atomic upgrades</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Immutable_root_with_atomic_upgrades&amp;diff=21198"/>
		<updated>2021-12-31T14:21:45Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: /* Preparation */ add reference to btrfs page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== What? ===&lt;br /&gt;
This article provides a basic guide to setting up a read-only-root-based Alpine Linux system with several boot environments and atomic upgrades using rEFInd and [[BTRFS|btrfs]].&lt;br /&gt;
&lt;br /&gt;
=== Why? ===&lt;br /&gt;
Read-only root and atomic upgrades with ability to easily rollback or boot previous configurations is a concept that got some popularity recently. Distributions providing and promoting such features, for example, are [https://silverblue.fedoraproject.org/ Fedora Silverblue], [https://microos.opensuse.org/ Opensuse MicroOS], [https://nixos.org NixOS] and [https://guix.gnu.org GNU Guix].&lt;br /&gt;
&lt;br /&gt;
While Alpine Linux has it&#039;s killer features it lacks mentioned above ones on default setup. This is a proof of concept that it&#039;s possible to implement them in a minimal way on a minimal system.&lt;br /&gt;
&lt;br /&gt;
{{Note|Alpine Linux can also boot from RAM in &#039;&#039;&#039;diskless mode&#039;&#039;&#039; (see [[Installation]]) which supports preserving changes between reboots using [[lbu]].}}&lt;br /&gt;
&lt;br /&gt;
= Preparation =&lt;br /&gt;
You should have bootable Alpine media. The process to obtain it decribed on the [[Installation|installation page.]]&lt;br /&gt;
{{Warning|Since version available in Alpine repositories lacks [[BTRFS|btrfs]] driver you should download rEFInd on [https://www.rodsbooks.com/refind/getting.html the official website] and copy it to installation media}}&lt;br /&gt;
&lt;br /&gt;
= Partitioning disks =&lt;br /&gt;
In this guide it is assumed that you have a fresh UEFI system without OS and just managed to boot into live Alpine using USB flash drive or CD.&lt;br /&gt;
The first step is creating partition table on your HDD/SSD target device (&amp;lt;code&amp;gt;/dev/sda&amp;lt;/code&amp;gt; here):&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add gptfdisk&lt;br /&gt;
# gdisk /dev/sda&lt;br /&gt;
&amp;gt; o ↵&lt;br /&gt;
&amp;gt; y ↵&lt;br /&gt;
&amp;gt; w ↵&lt;br /&gt;
&amp;gt; y ↵&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can define the partitions:&lt;br /&gt;
&amp;lt;pre&amp;gt;# cgdisk /dev/sda&amp;lt;/pre&amp;gt;&lt;br /&gt;
Partition creation process consists of several steps:&lt;br /&gt;
# Start sector - you can safely use default value by pressing ↵&lt;br /&gt;
# Size&lt;br /&gt;
# Type (as hex code) - EFI is ef00, Linux filesystem is 8300, Swap is 8200.&lt;br /&gt;
Result table:&lt;br /&gt;
&amp;lt;pre&amp;gt;Part.     #     Size        Partition Type            Partition Name&lt;br /&gt;
----------------------------------------------------------------&lt;br /&gt;
1               200.0 MiB   EFI System                EFI&lt;br /&gt;
2               200.0 GiB   Linux filesystem          ROOT&lt;br /&gt;
3               32.0 GiB    Linux swap                SWAP&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;ROOT&amp;lt;/code&amp;gt; partition name will later be used in rEFInd configuration to identify boot volume.&lt;br /&gt;
Next step is creating filesystems:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkfs.vfat -F32 /dev/sda1&lt;br /&gt;
# mkfs.btrfs /dev/sda2&lt;br /&gt;
# mkswap /dev/sda3&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can mount our root volume:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mount -t btrfs /dev/sda2 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
= File system structure =&lt;br /&gt;
Now we should create file structure that would provide reliable atomic system upgrades.&amp;lt;br&amp;gt;&lt;br /&gt;
Start with following directories:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/next&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores next &amp;lt;code&amp;gt;current&amp;lt;/code&amp;gt; link, is necessary due to how busybox &amp;lt;code&amp;gt;mv&amp;lt;/code&amp;gt; does atomic link replacement.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/commons&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores common non-snapshotting subvolumes.&amp;lt;br&amp;gt;&lt;br /&gt;
We may populate it right away:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@tmp&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@var@cache&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@var@log&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@home&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you use flatpak, you may also want to keep it&#039;s directory separate:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@lib@flatpak&amp;lt;/pre&amp;gt;&lt;br /&gt;
Include anything else in &amp;lt;code&amp;gt;/var&amp;lt;/code&amp;gt; that should be mutable, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@lib@iwd&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, most important directories:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/snapshots&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores directories containing snapshots belonging to one generation.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/links&amp;lt;/pre&amp;gt; &lt;br /&gt;
Stores generations of directories containing links to snapshot generations.&amp;lt;br&amp;gt;&lt;br /&gt;
Let&#039;s create first generation and populate it with one OS root snapshot &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;# NEWSNAPSHOTS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot;&lt;br /&gt;
# mkdir &amp;quot;/mnt/snapshots/$NEWSNAPSHOTS&amp;quot;&lt;br /&gt;
# btrfs subvolume create /mnt/snapshots/$NEWSNAPSHOTS/@&amp;lt;/pre&amp;gt;&lt;br /&gt;
Populate &amp;lt;code&amp;gt;links&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;# NEWLINKS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot;&lt;br /&gt;
# mkdir &amp;quot;/mnt/links/$NEWLINKS&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/0&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/1&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/2&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/3&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can have as many links as you like, just apply changes to rEFInd config and upgrade scripts described below accordingly.&amp;lt;br&amp;gt;&lt;br /&gt;
Link that will point to latest links generation:&lt;br /&gt;
&amp;lt;pre&amp;gt;# ln -s &amp;quot;./links/$NEWLINKS&amp;quot; /mnt/current&amp;lt;/pre&amp;gt;&lt;br /&gt;
This setup allows us to just have static rEFInd config that points to to &amp;lt;code&amp;gt;/current/0/@&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/current/1/@&amp;lt;/code&amp;gt;, etc. while the actual underlying boot environment will change with each upgrade.&amp;lt;br&amp;gt;&lt;br /&gt;
But how will fs mounting services know which snapshot generation is currently loaded?&amp;lt;br&amp;gt;&lt;br /&gt;
The answer is common &amp;lt;code&amp;gt;fstab&amp;lt;/code&amp;gt; in the btrfs root.&amp;lt;br&amp;gt;&lt;br /&gt;
Get UUIDs of the partitions first:&lt;br /&gt;
&amp;lt;pre&amp;gt;# blkid &amp;gt; /mnt/fstab&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now edit fstab accordingly:&lt;br /&gt;
&amp;lt;pre&amp;gt;# vi /mnt/fstab&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 / btrfs subvol=CURRENT_SNAPSHOTS_PATH/@,ro,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/tmp btrfs subvol=/commons/@var@tmp,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/cache btrfs subvol=/commons/@var@cache,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/log btrfs subvol=/commons/@var@log,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/lib/flatpak btrfs subvol=/commons/@var@lib@flatpak,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/lib/iwd btrfs subvol=/commons/@var@lib@iwd,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /home btrfs subvol=/commons/@home,rw,noatime 0 0&lt;br /&gt;
# UUID=2FE6-837A /boot/efi vfat rw,noatime,discard 0 2&lt;br /&gt;
tmpfs /tmp tmpfs mode=1777,noatime,nosuid,nodev,size=2G 0 0&lt;br /&gt;
UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 swap swap rw,noatime,discard 0 0&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;CURRENT_SNAPSHOTS_PATH&amp;lt;/code&amp;gt; will be replaced by scripts with, for example, &amp;lt;code&amp;gt;/snapshots/20210411212549sdBXyLxg&amp;lt;/code&amp;gt;, and the result will be piped into &amp;lt;code&amp;gt;/etc/fstab&amp;lt;/code&amp;gt; of a created &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; snapshot during new generation preparations.&amp;lt;br&amp;gt;&lt;br /&gt;
Root btrfs volume structure mounted on &amp;lt;code&amp;gt;/mnt&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;|--mnt&lt;br /&gt;
| |--commons&lt;br /&gt;
| | |--@var@tmp&lt;br /&gt;
| | |--@var@cache&lt;br /&gt;
| | |--@var@log&lt;br /&gt;
| | |--@var@lib@flatpak&lt;br /&gt;
| | |--@var@lib@iwd&lt;br /&gt;
| | |--@home&lt;br /&gt;
| |--current&lt;br /&gt;
| |--fstab&lt;br /&gt;
| |--links&lt;br /&gt;
| | |--20210411213742qwrXAJBz&lt;br /&gt;
| | | |--0&lt;br /&gt;
| | | |--1&lt;br /&gt;
| | | |--2&lt;br /&gt;
| | | |--3&lt;br /&gt;
| |--next&lt;br /&gt;
| |--snapshots&lt;br /&gt;
| | |--20210411212549sdBXyLxg&lt;br /&gt;
| | | |--@&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Base system install =&lt;br /&gt;
With the directory strtucture prepared we can start installation of a basic Alpine Linux system.&amp;lt;br&amp;gt;&lt;br /&gt;
Considering that installation is done from Alpine system, we only need following parts of [[Alpine_Linux_in_a_chroot|the process]]:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk -X https://dl-cdn.alpinelinux.org/alpine/latest-stable/main -U --allow-untrusted -p /mnt/snapshots/20210411212549sdBXyLxg/@ --initdb add alpine-base&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can setup basic chroot to complete the installation process:&lt;br /&gt;
&amp;lt;pre&amp;gt;# export SNP=&amp;quot;/mnt/snapshots/20210411212549sdBXyLxg/@&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# mount -o bind /dev $SNP/dev&lt;br /&gt;
# mount -t proc none $SNP/proc&lt;br /&gt;
# mount -t sysfs sys $SNP/sys&lt;br /&gt;
&lt;br /&gt;
# sed &amp;quot;s#CURRENT_SNAPSHOTS_PATH#/snapshots/20210411212549sdBXyLxg#g&amp;quot; /mnt/fstab &amp;gt; &amp;quot;$SNP/etc/fstab&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# cp -L /etc/resolv.conf &amp;quot;$SNP/etc/&amp;quot;&lt;br /&gt;
# chroot &amp;quot;$SNP&amp;quot; /bin/sh&lt;br /&gt;
&lt;br /&gt;
# mount -a&lt;br /&gt;
&lt;br /&gt;
# mv /etc/resolv.conf /tmp/&lt;br /&gt;
# ln -s /tmp/resolv.conf /etc/resolv.conf&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as you in chroot, define repositories:&lt;br /&gt;
&amp;lt;pre&amp;gt;# echo &amp;quot;https://dl-cdn.alpinelinux.org/alpine/latest-stable/main&amp;quot; &amp;gt; /etc/apk/repositories&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example shows only &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;, but you should also add &amp;lt;code&amp;gt;testing&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;community&amp;lt;/code&amp;gt; if you need any packages in those.&amp;lt;br&amp;gt;&lt;br /&gt;
Now it&#039;s time for firmware, kernel and btrfs packages:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add -U linux-firmware linux-lts btrfs-progs&amp;lt;/pre&amp;gt;&lt;br /&gt;
You may want to change &amp;lt;code&amp;gt;linux-firmware&amp;lt;/code&amp;gt; to a custom set of firmware packages suitable for you system, for example &amp;lt;code&amp;gt;linux-firmware-amd linux-firmware-amd-ucode linux-firmware-amdgpu linux-firmware-ath10k linux-firmware-qca&amp;lt;/code&amp;gt; for typical AMD laptop.&amp;lt;br&amp;gt;&lt;br /&gt;
It is also important to add &amp;lt;code&amp;gt;btrfs&amp;lt;/code&amp;gt; feature to &amp;lt;code&amp;gt;mkinitfs.conf&amp;lt;/code&amp;gt; and run &amp;lt;code&amp;gt;mkinitfs&amp;lt;/code&amp;gt; manually:&lt;br /&gt;
&amp;lt;pre&amp;gt;# vi /etc/mkinitfs/mkinitfs.conf&lt;br /&gt;
# mkinitfs&amp;lt;/pre&amp;gt;&lt;br /&gt;
These steps prepare kernel and generate &amp;lt;code&amp;gt;initramfs&amp;lt;/code&amp;gt; which later will be used to boot from our first snapshot.&amp;lt;br&amp;gt;&lt;br /&gt;
After that you should install any package you may need on first boot.&lt;br /&gt;
&lt;br /&gt;
{{Warning|In case your PC only has wireless connection you should also install any suitable networking software, like &amp;lt;code&amp;gt;iwd&amp;lt;/code&amp;gt; in this example, so you will not end up severed from network on your first boot.}}&lt;br /&gt;
&lt;br /&gt;
{{Note|Due to root being immutable during operation, it&#039;s recommended to install package &amp;lt;code&amp;gt;openresolv&amp;lt;/code&amp;gt; to support changing network connection. In this case &amp;lt;code&amp;gt;/etc/resolvconf.conf&amp;lt;/code&amp;gt; should have &amp;lt;code&amp;gt;resolv_conf{{=}}/tmp/resolv.conf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/etc/resolv.conf&amp;lt;/code&amp;gt; should be moved to &amp;lt;code&amp;gt;/tmp/resolv.conf&amp;lt;/code&amp;gt; and a link to the new resolv.conf location should be created: &amp;lt;code&amp;gt;ln -sfn /tmp/resolv.conf /etc/resolv.conf&amp;lt;/code&amp;gt;.&lt;br /&gt;
You may also use static DNS, but this would make your network activity directly identifiable to the DNS server provider, therefore it&#039;s not recommended.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Now, configure the system, start with setting a password for the root:&lt;br /&gt;
&amp;lt;pre&amp;gt;# passwd root&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With the snapshot prepared and configured we can chroot out of it and unmount everything:&lt;br /&gt;
&amp;lt;pre&amp;gt;# umount -a&lt;br /&gt;
# exit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finish editing snapshot by setting &amp;lt;code&amp;gt;ro&amp;lt;/code&amp;gt; flag and unmounting root volume:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs property set -ts &amp;quot;/mnt/snapshots/20210411212549sdBXyLxg/@&amp;quot; ro true&lt;br /&gt;
# umount /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Bootloader installation =&lt;br /&gt;
{{Note|The example demonstrated here only make use of rEFInd bootloader as it is relatively easy to install manually and generally easy to use. You may however setup any prefered bootloader given it supports btrfs and can be configured to boot specific snapshot.}}&lt;br /&gt;
Mount the EFI partition:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mount -t vfat /dev/sda1 /mnt&lt;br /&gt;
# mkdir /mnt/EFI&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unpack prepared rEFInd archive and copy relevant files to &amp;lt;code&amp;gt;/mnt/EFI/&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# unzip refind-bin-version.zip&lt;br /&gt;
# cp -r refind-bin-version/refind /mnt/EFI/&lt;br /&gt;
# cd /mnt/EFI/refind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Delete all unnecessary files - everything that is not for your CPU architecture:&lt;br /&gt;
&amp;lt;pre&amp;gt;# rm -r drivers_aa64 drivers_ia32 tools_aa64 tools_ia32 refind_aa64.efi refind_ia32.efi&amp;lt;/pre&amp;gt;&lt;br /&gt;
Rename config file and edit it:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mv refind.conf-sample refind.conf&lt;br /&gt;
# vi refind.conf&amp;lt;/pre&amp;gt;&lt;br /&gt;
And append following to the end of the file, remember to replace example UUIDs with your own for &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; (btrfs partition) and &amp;lt;code&amp;gt;resume&amp;lt;/code&amp;gt; (swap partition):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
menuentry &amp;quot;Alpine Linux&amp;quot; {&lt;br /&gt;
    icon /EFI/refind/icons/os_linux.png&lt;br /&gt;
    volume &amp;quot;ROOT&amp;quot;&lt;br /&gt;
    loader /current/0/@/boot/vmlinuz-lts&lt;br /&gt;
    initrd /current/0/@/boot/initramfs-lts&lt;br /&gt;
    options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/0/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 1&amp;quot; {&lt;br /&gt;
        loader /current/1/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/1/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/1/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 2&amp;quot; {&lt;br /&gt;
        loader /current/2/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/2/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/2/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 3&amp;quot; {&lt;br /&gt;
        loader /current/3/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/3/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/3/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
{{Note|&amp;lt;code&amp;gt;&amp;quot;ROOT&amp;quot;&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;PARTLABEL&amp;lt;/code&amp;gt; of the btrfs partition. You may also use &amp;lt;code&amp;gt;PARTUUID&amp;lt;/code&amp;gt; instead. To get both &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; package can be used. &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; included in busybox does not provide this information. }}&lt;br /&gt;
To add rEFInd to UEFI, &amp;lt;code&amp;gt;efibootmgr&amp;lt;/code&amp;gt; is a suitable tool:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add efibootmgr&lt;br /&gt;
# efibootmgr --create --disk /dev/sda --part 1 --loader /EFI/refind/refind_x64.efi --label &amp;quot;rEFInd&amp;quot; --verbose&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/dev/sda&amp;lt;/code&amp;gt; is our disk device and &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; is the number of partition containing &amp;lt;code&amp;gt;rEFInd&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Updating or altering the system =&lt;br /&gt;
&amp;lt;pre&amp;gt;# touch /sbin/sysmut&lt;br /&gt;
# chmod +x /sbin/sysmut&lt;br /&gt;
# vi /sbin/sysmut&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example script to mutate the the system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
ROOTVOLMNT=&amp;quot;/vol/root&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t btrfs -o rw,noatime UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 &amp;quot;$ROOTVOLMNT&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
NEWSNAPSHOTS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
btrfs subvolume snapshot &amp;quot;$ROOTVOLMNT/current/0/@&amp;quot; &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
sed &amp;quot;s#CURRENT_SNAPSHOTS_PATH#/snapshots/$NEWSNAPSHOTS#g&amp;quot; &amp;quot;$ROOTVOLMNT/fstab&amp;quot; &amp;gt; &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/etc/fstab&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t proc none &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/proc&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t sysfs sys &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/sys&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -o bind /dev &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/dev&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
chroot &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; /bin/sh -c &#039;mount -a; sh; APPLY=$?; umount -a; exit $APPLY&#039; &amp;amp;&amp;amp; \&lt;br /&gt;
btrfs property set -ts &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; ro true &amp;amp;&amp;amp; \&lt;br /&gt;
NEWLINKS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/links/$NEWLINKS&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/0&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/0&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/1&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/1&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/2&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/2&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/3&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/next&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
ln -sfn &amp;quot;./links/$NEWLINKS&amp;quot; &amp;quot;$ROOTVOLMNT/next/current&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mv &amp;quot;$ROOTVOLMNT/next/current&amp;quot; &amp;quot;$ROOTVOLMNT/&amp;quot; \&lt;br /&gt;
&amp;amp;&amp;amp; echo &amp;quot;Switched to the new snapshots&amp;quot; \&lt;br /&gt;
|| echo &amp;quot;Changes discarded&amp;quot;&lt;br /&gt;
umount &amp;quot;$ROOTVOLMNT&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It will get you into the root shell chrooted into the new snapshot, where you can apply any change you like.&amp;lt;br&amp;gt;&lt;br /&gt;
If chroot shell exits with an error, there will be no switch to the new snapshots. This means you can manually discard changes while in the chroot by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# exit 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Deleting unused snapshots =&lt;br /&gt;
Unused snapshots can be garbage-collected by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# touch /sbin/syscln&lt;br /&gt;
# chmod +x /sbin/syscln&lt;br /&gt;
# vi /sbin/syscln&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
ROOTVOLMNT=&amp;quot;/vol/root&amp;quot;&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT&amp;quot;&lt;br /&gt;
mount -t btrfs -o rw,noatime UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 &amp;quot;$ROOTVOLMNT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
SNAPSHOTS=$({ \&lt;br /&gt;
    find &amp;quot;$ROOTVOLMNT/snapshots/&amp;quot; -maxdepth 1 -mindepth 1&lt;br /&gt;
    find &amp;quot;$ROOTVOLMNT/current/&amp;quot; -maxdepth 1 -mindepth 1 \&lt;br /&gt;
        | xargs -n 1 readlink -f&lt;br /&gt;
} | sort | uniq -u)&lt;br /&gt;
&lt;br /&gt;
if [ -z &amp;quot;$SNAPSHOTS&amp;quot; ]; then&lt;br /&gt;
    echo &amp;quot;Nothing to remove&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    printf %s\\n &amp;quot;$SNAPSHOTS&amp;quot; \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 -n 1 -I {} find {} -maxdepth 1 -mindepth 1 \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 btrfs subvolume delete&lt;br /&gt;
    printf %s\\n &amp;quot;$SNAPSHOTS&amp;quot; \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 rm -r&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
umount &amp;quot;$ROOTVOLMNT&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Allowing temporary runtime alterations =&lt;br /&gt;
You can use &amp;lt;code&amp;gt;overlayfs&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;tmpfs&amp;lt;/code&amp;gt; built into Alpine&#039;s init script to allow changes in the rootfs which will be automatically reverted upon reboot.&amp;lt;br&amp;gt;&lt;br /&gt;
To make use this just add &amp;lt;code&amp;gt;overlaytmpfs&amp;lt;/code&amp;gt; to the kernel boot options in &amp;lt;code&amp;gt;refind.conf&amp;lt;/code&amp;gt;, e.g.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    initrd /current/0/@/boot/initramfs-lts&lt;br /&gt;
    options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/0/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 overlaytmpfs quiet splash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 1&amp;quot; {&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Immutable_root_with_atomic_upgrades&amp;diff=21197</id>
		<title>Immutable root with atomic upgrades</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Immutable_root_with_atomic_upgrades&amp;diff=21197"/>
		<updated>2021-12-31T14:21:25Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: /* What? */  add reference to btrfs page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== What? ===&lt;br /&gt;
This article provides a basic guide to setting up a read-only-root-based Alpine Linux system with several boot environments and atomic upgrades using rEFInd and [[BTRFS|btrfs]].&lt;br /&gt;
&lt;br /&gt;
=== Why? ===&lt;br /&gt;
Read-only root and atomic upgrades with ability to easily rollback or boot previous configurations is a concept that got some popularity recently. Distributions providing and promoting such features, for example, are [https://silverblue.fedoraproject.org/ Fedora Silverblue], [https://microos.opensuse.org/ Opensuse MicroOS], [https://nixos.org NixOS] and [https://guix.gnu.org GNU Guix].&lt;br /&gt;
&lt;br /&gt;
While Alpine Linux has it&#039;s killer features it lacks mentioned above ones on default setup. This is a proof of concept that it&#039;s possible to implement them in a minimal way on a minimal system.&lt;br /&gt;
&lt;br /&gt;
{{Note|Alpine Linux can also boot from RAM in &#039;&#039;&#039;diskless mode&#039;&#039;&#039; (see [[Installation]]) which supports preserving changes between reboots using [[lbu]].}}&lt;br /&gt;
&lt;br /&gt;
= Preparation =&lt;br /&gt;
You should have bootable Alpine media. The process to obtain it decribed on the [[Installation|installation page.]]&lt;br /&gt;
{{Warning|Since version available in Alpine repositories lacks btrfs driver you should download rEFInd on [https://www.rodsbooks.com/refind/getting.html the official website] and copy it to installation media}}&lt;br /&gt;
&lt;br /&gt;
= Partitioning disks =&lt;br /&gt;
In this guide it is assumed that you have a fresh UEFI system without OS and just managed to boot into live Alpine using USB flash drive or CD.&lt;br /&gt;
The first step is creating partition table on your HDD/SSD target device (&amp;lt;code&amp;gt;/dev/sda&amp;lt;/code&amp;gt; here):&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add gptfdisk&lt;br /&gt;
# gdisk /dev/sda&lt;br /&gt;
&amp;gt; o ↵&lt;br /&gt;
&amp;gt; y ↵&lt;br /&gt;
&amp;gt; w ↵&lt;br /&gt;
&amp;gt; y ↵&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can define the partitions:&lt;br /&gt;
&amp;lt;pre&amp;gt;# cgdisk /dev/sda&amp;lt;/pre&amp;gt;&lt;br /&gt;
Partition creation process consists of several steps:&lt;br /&gt;
# Start sector - you can safely use default value by pressing ↵&lt;br /&gt;
# Size&lt;br /&gt;
# Type (as hex code) - EFI is ef00, Linux filesystem is 8300, Swap is 8200.&lt;br /&gt;
Result table:&lt;br /&gt;
&amp;lt;pre&amp;gt;Part.     #     Size        Partition Type            Partition Name&lt;br /&gt;
----------------------------------------------------------------&lt;br /&gt;
1               200.0 MiB   EFI System                EFI&lt;br /&gt;
2               200.0 GiB   Linux filesystem          ROOT&lt;br /&gt;
3               32.0 GiB    Linux swap                SWAP&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;ROOT&amp;lt;/code&amp;gt; partition name will later be used in rEFInd configuration to identify boot volume.&lt;br /&gt;
Next step is creating filesystems:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkfs.vfat -F32 /dev/sda1&lt;br /&gt;
# mkfs.btrfs /dev/sda2&lt;br /&gt;
# mkswap /dev/sda3&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can mount our root volume:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mount -t btrfs /dev/sda2 /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
= File system structure =&lt;br /&gt;
Now we should create file structure that would provide reliable atomic system upgrades.&amp;lt;br&amp;gt;&lt;br /&gt;
Start with following directories:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/next&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores next &amp;lt;code&amp;gt;current&amp;lt;/code&amp;gt; link, is necessary due to how busybox &amp;lt;code&amp;gt;mv&amp;lt;/code&amp;gt; does atomic link replacement.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/commons&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores common non-snapshotting subvolumes.&amp;lt;br&amp;gt;&lt;br /&gt;
We may populate it right away:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@tmp&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@var@cache&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@var@log&lt;br /&gt;
# btrfs subvolume create /mnt/commons/@home&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you use flatpak, you may also want to keep it&#039;s directory separate:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@lib@flatpak&amp;lt;/pre&amp;gt;&lt;br /&gt;
Include anything else in &amp;lt;code&amp;gt;/var&amp;lt;/code&amp;gt; that should be mutable, for example:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs subvolume create /mnt/commons/@var@lib@iwd&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, most important directories:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/snapshots&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores directories containing snapshots belonging to one generation.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# mkdir /mnt/links&amp;lt;/pre&amp;gt; &lt;br /&gt;
Stores generations of directories containing links to snapshot generations.&amp;lt;br&amp;gt;&lt;br /&gt;
Let&#039;s create first generation and populate it with one OS root snapshot &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;# NEWSNAPSHOTS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot;&lt;br /&gt;
# mkdir &amp;quot;/mnt/snapshots/$NEWSNAPSHOTS&amp;quot;&lt;br /&gt;
# btrfs subvolume create /mnt/snapshots/$NEWSNAPSHOTS/@&amp;lt;/pre&amp;gt;&lt;br /&gt;
Populate &amp;lt;code&amp;gt;links&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;# NEWLINKS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot;&lt;br /&gt;
# mkdir &amp;quot;/mnt/links/$NEWLINKS&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/0&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/1&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/2&amp;quot;&lt;br /&gt;
# ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;/mnt/links/$NEWLINKS/3&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can have as many links as you like, just apply changes to rEFInd config and upgrade scripts described below accordingly.&amp;lt;br&amp;gt;&lt;br /&gt;
Link that will point to latest links generation:&lt;br /&gt;
&amp;lt;pre&amp;gt;# ln -s &amp;quot;./links/$NEWLINKS&amp;quot; /mnt/current&amp;lt;/pre&amp;gt;&lt;br /&gt;
This setup allows us to just have static rEFInd config that points to to &amp;lt;code&amp;gt;/current/0/@&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/current/1/@&amp;lt;/code&amp;gt;, etc. while the actual underlying boot environment will change with each upgrade.&amp;lt;br&amp;gt;&lt;br /&gt;
But how will fs mounting services know which snapshot generation is currently loaded?&amp;lt;br&amp;gt;&lt;br /&gt;
The answer is common &amp;lt;code&amp;gt;fstab&amp;lt;/code&amp;gt; in the btrfs root.&amp;lt;br&amp;gt;&lt;br /&gt;
Get UUIDs of the partitions first:&lt;br /&gt;
&amp;lt;pre&amp;gt;# blkid &amp;gt; /mnt/fstab&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now edit fstab accordingly:&lt;br /&gt;
&amp;lt;pre&amp;gt;# vi /mnt/fstab&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 / btrfs subvol=CURRENT_SNAPSHOTS_PATH/@,ro,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/tmp btrfs subvol=/commons/@var@tmp,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/cache btrfs subvol=/commons/@var@cache,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/log btrfs subvol=/commons/@var@log,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/lib/flatpak btrfs subvol=/commons/@var@lib@flatpak,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /var/lib/iwd btrfs subvol=/commons/@var@lib@iwd,rw,noatime 0 0&lt;br /&gt;
UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 /home btrfs subvol=/commons/@home,rw,noatime 0 0&lt;br /&gt;
# UUID=2FE6-837A /boot/efi vfat rw,noatime,discard 0 2&lt;br /&gt;
tmpfs /tmp tmpfs mode=1777,noatime,nosuid,nodev,size=2G 0 0&lt;br /&gt;
UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 swap swap rw,noatime,discard 0 0&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;CURRENT_SNAPSHOTS_PATH&amp;lt;/code&amp;gt; will be replaced by scripts with, for example, &amp;lt;code&amp;gt;/snapshots/20210411212549sdBXyLxg&amp;lt;/code&amp;gt;, and the result will be piped into &amp;lt;code&amp;gt;/etc/fstab&amp;lt;/code&amp;gt; of a created &amp;lt;code&amp;gt;@&amp;lt;/code&amp;gt; snapshot during new generation preparations.&amp;lt;br&amp;gt;&lt;br /&gt;
Root btrfs volume structure mounted on &amp;lt;code&amp;gt;/mnt&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;|--mnt&lt;br /&gt;
| |--commons&lt;br /&gt;
| | |--@var@tmp&lt;br /&gt;
| | |--@var@cache&lt;br /&gt;
| | |--@var@log&lt;br /&gt;
| | |--@var@lib@flatpak&lt;br /&gt;
| | |--@var@lib@iwd&lt;br /&gt;
| | |--@home&lt;br /&gt;
| |--current&lt;br /&gt;
| |--fstab&lt;br /&gt;
| |--links&lt;br /&gt;
| | |--20210411213742qwrXAJBz&lt;br /&gt;
| | | |--0&lt;br /&gt;
| | | |--1&lt;br /&gt;
| | | |--2&lt;br /&gt;
| | | |--3&lt;br /&gt;
| |--next&lt;br /&gt;
| |--snapshots&lt;br /&gt;
| | |--20210411212549sdBXyLxg&lt;br /&gt;
| | | |--@&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Base system install =&lt;br /&gt;
With the directory strtucture prepared we can start installation of a basic Alpine Linux system.&amp;lt;br&amp;gt;&lt;br /&gt;
Considering that installation is done from Alpine system, we only need following parts of [[Alpine_Linux_in_a_chroot|the process]]:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk -X https://dl-cdn.alpinelinux.org/alpine/latest-stable/main -U --allow-untrusted -p /mnt/snapshots/20210411212549sdBXyLxg/@ --initdb add alpine-base&amp;lt;/pre&amp;gt;&lt;br /&gt;
Now we can setup basic chroot to complete the installation process:&lt;br /&gt;
&amp;lt;pre&amp;gt;# export SNP=&amp;quot;/mnt/snapshots/20210411212549sdBXyLxg/@&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# mount -o bind /dev $SNP/dev&lt;br /&gt;
# mount -t proc none $SNP/proc&lt;br /&gt;
# mount -t sysfs sys $SNP/sys&lt;br /&gt;
&lt;br /&gt;
# sed &amp;quot;s#CURRENT_SNAPSHOTS_PATH#/snapshots/20210411212549sdBXyLxg#g&amp;quot; /mnt/fstab &amp;gt; &amp;quot;$SNP/etc/fstab&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# cp -L /etc/resolv.conf &amp;quot;$SNP/etc/&amp;quot;&lt;br /&gt;
# chroot &amp;quot;$SNP&amp;quot; /bin/sh&lt;br /&gt;
&lt;br /&gt;
# mount -a&lt;br /&gt;
&lt;br /&gt;
# mv /etc/resolv.conf /tmp/&lt;br /&gt;
# ln -s /tmp/resolv.conf /etc/resolv.conf&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as you in chroot, define repositories:&lt;br /&gt;
&amp;lt;pre&amp;gt;# echo &amp;quot;https://dl-cdn.alpinelinux.org/alpine/latest-stable/main&amp;quot; &amp;gt; /etc/apk/repositories&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example shows only &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;, but you should also add &amp;lt;code&amp;gt;testing&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;community&amp;lt;/code&amp;gt; if you need any packages in those.&amp;lt;br&amp;gt;&lt;br /&gt;
Now it&#039;s time for firmware, kernel and btrfs packages:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add -U linux-firmware linux-lts btrfs-progs&amp;lt;/pre&amp;gt;&lt;br /&gt;
You may want to change &amp;lt;code&amp;gt;linux-firmware&amp;lt;/code&amp;gt; to a custom set of firmware packages suitable for you system, for example &amp;lt;code&amp;gt;linux-firmware-amd linux-firmware-amd-ucode linux-firmware-amdgpu linux-firmware-ath10k linux-firmware-qca&amp;lt;/code&amp;gt; for typical AMD laptop.&amp;lt;br&amp;gt;&lt;br /&gt;
It is also important to add &amp;lt;code&amp;gt;btrfs&amp;lt;/code&amp;gt; feature to &amp;lt;code&amp;gt;mkinitfs.conf&amp;lt;/code&amp;gt; and run &amp;lt;code&amp;gt;mkinitfs&amp;lt;/code&amp;gt; manually:&lt;br /&gt;
&amp;lt;pre&amp;gt;# vi /etc/mkinitfs/mkinitfs.conf&lt;br /&gt;
# mkinitfs&amp;lt;/pre&amp;gt;&lt;br /&gt;
These steps prepare kernel and generate &amp;lt;code&amp;gt;initramfs&amp;lt;/code&amp;gt; which later will be used to boot from our first snapshot.&amp;lt;br&amp;gt;&lt;br /&gt;
After that you should install any package you may need on first boot.&lt;br /&gt;
&lt;br /&gt;
{{Warning|In case your PC only has wireless connection you should also install any suitable networking software, like &amp;lt;code&amp;gt;iwd&amp;lt;/code&amp;gt; in this example, so you will not end up severed from network on your first boot.}}&lt;br /&gt;
&lt;br /&gt;
{{Note|Due to root being immutable during operation, it&#039;s recommended to install package &amp;lt;code&amp;gt;openresolv&amp;lt;/code&amp;gt; to support changing network connection. In this case &amp;lt;code&amp;gt;/etc/resolvconf.conf&amp;lt;/code&amp;gt; should have &amp;lt;code&amp;gt;resolv_conf{{=}}/tmp/resolv.conf&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/etc/resolv.conf&amp;lt;/code&amp;gt; should be moved to &amp;lt;code&amp;gt;/tmp/resolv.conf&amp;lt;/code&amp;gt; and a link to the new resolv.conf location should be created: &amp;lt;code&amp;gt;ln -sfn /tmp/resolv.conf /etc/resolv.conf&amp;lt;/code&amp;gt;.&lt;br /&gt;
You may also use static DNS, but this would make your network activity directly identifiable to the DNS server provider, therefore it&#039;s not recommended.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Now, configure the system, start with setting a password for the root:&lt;br /&gt;
&amp;lt;pre&amp;gt;# passwd root&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With the snapshot prepared and configured we can chroot out of it and unmount everything:&lt;br /&gt;
&amp;lt;pre&amp;gt;# umount -a&lt;br /&gt;
# exit&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finish editing snapshot by setting &amp;lt;code&amp;gt;ro&amp;lt;/code&amp;gt; flag and unmounting root volume:&lt;br /&gt;
&amp;lt;pre&amp;gt;# btrfs property set -ts &amp;quot;/mnt/snapshots/20210411212549sdBXyLxg/@&amp;quot; ro true&lt;br /&gt;
# umount /mnt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Bootloader installation =&lt;br /&gt;
{{Note|The example demonstrated here only make use of rEFInd bootloader as it is relatively easy to install manually and generally easy to use. You may however setup any prefered bootloader given it supports btrfs and can be configured to boot specific snapshot.}}&lt;br /&gt;
Mount the EFI partition:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mount -t vfat /dev/sda1 /mnt&lt;br /&gt;
# mkdir /mnt/EFI&amp;lt;/pre&amp;gt;&lt;br /&gt;
Unpack prepared rEFInd archive and copy relevant files to &amp;lt;code&amp;gt;/mnt/EFI/&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;# unzip refind-bin-version.zip&lt;br /&gt;
# cp -r refind-bin-version/refind /mnt/EFI/&lt;br /&gt;
# cd /mnt/EFI/refind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Delete all unnecessary files - everything that is not for your CPU architecture:&lt;br /&gt;
&amp;lt;pre&amp;gt;# rm -r drivers_aa64 drivers_ia32 tools_aa64 tools_ia32 refind_aa64.efi refind_ia32.efi&amp;lt;/pre&amp;gt;&lt;br /&gt;
Rename config file and edit it:&lt;br /&gt;
&amp;lt;pre&amp;gt;# mv refind.conf-sample refind.conf&lt;br /&gt;
# vi refind.conf&amp;lt;/pre&amp;gt;&lt;br /&gt;
And append following to the end of the file, remember to replace example UUIDs with your own for &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; (btrfs partition) and &amp;lt;code&amp;gt;resume&amp;lt;/code&amp;gt; (swap partition):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
menuentry &amp;quot;Alpine Linux&amp;quot; {&lt;br /&gt;
    icon /EFI/refind/icons/os_linux.png&lt;br /&gt;
    volume &amp;quot;ROOT&amp;quot;&lt;br /&gt;
    loader /current/0/@/boot/vmlinuz-lts&lt;br /&gt;
    initrd /current/0/@/boot/initramfs-lts&lt;br /&gt;
    options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/0/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 1&amp;quot; {&lt;br /&gt;
        loader /current/1/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/1/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/1/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 2&amp;quot; {&lt;br /&gt;
        loader /current/2/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/2/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/2/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 3&amp;quot; {&lt;br /&gt;
        loader /current/3/@/boot/vmlinuz-lts&lt;br /&gt;
        initrd /current/3/@/boot/initramfs-lts&lt;br /&gt;
        options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/3/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 quiet splash&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
{{Note|&amp;lt;code&amp;gt;&amp;quot;ROOT&amp;quot;&amp;lt;/code&amp;gt; is the &amp;lt;code&amp;gt;PARTLABEL&amp;lt;/code&amp;gt; of the btrfs partition. You may also use &amp;lt;code&amp;gt;PARTUUID&amp;lt;/code&amp;gt; instead. To get both &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; package can be used. &amp;lt;code&amp;gt;blkid&amp;lt;/code&amp;gt; included in busybox does not provide this information. }}&lt;br /&gt;
To add rEFInd to UEFI, &amp;lt;code&amp;gt;efibootmgr&amp;lt;/code&amp;gt; is a suitable tool:&lt;br /&gt;
&amp;lt;pre&amp;gt;# apk add efibootmgr&lt;br /&gt;
# efibootmgr --create --disk /dev/sda --part 1 --loader /EFI/refind/refind_x64.efi --label &amp;quot;rEFInd&amp;quot; --verbose&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;/dev/sda&amp;lt;/code&amp;gt; is our disk device and &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; is the number of partition containing &amp;lt;code&amp;gt;rEFInd&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Updating or altering the system =&lt;br /&gt;
&amp;lt;pre&amp;gt;# touch /sbin/sysmut&lt;br /&gt;
# chmod +x /sbin/sysmut&lt;br /&gt;
# vi /sbin/sysmut&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example script to mutate the the system:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
ROOTVOLMNT=&amp;quot;/vol/root&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t btrfs -o rw,noatime UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 &amp;quot;$ROOTVOLMNT&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
NEWSNAPSHOTS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
btrfs subvolume snapshot &amp;quot;$ROOTVOLMNT/current/0/@&amp;quot; &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
sed &amp;quot;s#CURRENT_SNAPSHOTS_PATH#/snapshots/$NEWSNAPSHOTS#g&amp;quot; &amp;quot;$ROOTVOLMNT/fstab&amp;quot; &amp;gt; &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/etc/fstab&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t proc none &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/proc&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -t sysfs sys &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/sys&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mount -o bind /dev &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@/dev&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
chroot &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; /bin/sh -c &#039;mount -a; sh; APPLY=$?; umount -a; exit $APPLY&#039; &amp;amp;&amp;amp; \&lt;br /&gt;
btrfs property set -ts &amp;quot;$ROOTVOLMNT/snapshots/$NEWSNAPSHOTS/@&amp;quot; ro true &amp;amp;&amp;amp; \&lt;br /&gt;
NEWLINKS=&amp;quot;$(date -u +&amp;quot;%Y%m%d%H%M%S&amp;quot;)$(cat /dev/urandom | tr -dc &#039;a-zA-Z&#039; | fold -w 8 | head -n 1)&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/links/$NEWLINKS&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
ln -s &amp;quot;../../snapshots/$NEWSNAPSHOTS&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/0&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/0&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/1&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/1&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/2&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
cp -P &amp;quot;$ROOTVOLMNT/current/2&amp;quot; &amp;quot;$ROOTVOLMNT/links/$NEWLINKS/3&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT/next&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
ln -sfn &amp;quot;./links/$NEWLINKS&amp;quot; &amp;quot;$ROOTVOLMNT/next/current&amp;quot; &amp;amp;&amp;amp; \&lt;br /&gt;
mv &amp;quot;$ROOTVOLMNT/next/current&amp;quot; &amp;quot;$ROOTVOLMNT/&amp;quot; \&lt;br /&gt;
&amp;amp;&amp;amp; echo &amp;quot;Switched to the new snapshots&amp;quot; \&lt;br /&gt;
|| echo &amp;quot;Changes discarded&amp;quot;&lt;br /&gt;
umount &amp;quot;$ROOTVOLMNT&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It will get you into the root shell chrooted into the new snapshot, where you can apply any change you like.&amp;lt;br&amp;gt;&lt;br /&gt;
If chroot shell exits with an error, there will be no switch to the new snapshots. This means you can manually discard changes while in the chroot by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# exit 1&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Deleting unused snapshots =&lt;br /&gt;
Unused snapshots can be garbage-collected by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;# touch /sbin/syscln&lt;br /&gt;
# chmod +x /sbin/syscln&lt;br /&gt;
# vi /sbin/syscln&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
ROOTVOLMNT=&amp;quot;/vol/root&amp;quot;&lt;br /&gt;
mkdir -p &amp;quot;$ROOTVOLMNT&amp;quot;&lt;br /&gt;
mount -t btrfs -o rw,noatime UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 &amp;quot;$ROOTVOLMNT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
SNAPSHOTS=$({ \&lt;br /&gt;
    find &amp;quot;$ROOTVOLMNT/snapshots/&amp;quot; -maxdepth 1 -mindepth 1&lt;br /&gt;
    find &amp;quot;$ROOTVOLMNT/current/&amp;quot; -maxdepth 1 -mindepth 1 \&lt;br /&gt;
        | xargs -n 1 readlink -f&lt;br /&gt;
} | sort | uniq -u)&lt;br /&gt;
&lt;br /&gt;
if [ -z &amp;quot;$SNAPSHOTS&amp;quot; ]; then&lt;br /&gt;
    echo &amp;quot;Nothing to remove&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    printf %s\\n &amp;quot;$SNAPSHOTS&amp;quot; \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 -n 1 -I {} find {} -maxdepth 1 -mindepth 1 \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 btrfs subvolume delete&lt;br /&gt;
    printf %s\\n &amp;quot;$SNAPSHOTS&amp;quot; \&lt;br /&gt;
        | tr \\n \\0 \&lt;br /&gt;
        | xargs -r -0 rm -r&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
umount &amp;quot;$ROOTVOLMNT&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Allowing temporary runtime alterations =&lt;br /&gt;
You can use &amp;lt;code&amp;gt;overlayfs&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;tmpfs&amp;lt;/code&amp;gt; built into Alpine&#039;s init script to allow changes in the rootfs which will be automatically reverted upon reboot.&amp;lt;br&amp;gt;&lt;br /&gt;
To make use this just add &amp;lt;code&amp;gt;overlaytmpfs&amp;lt;/code&amp;gt; to the kernel boot options in &amp;lt;code&amp;gt;refind.conf&amp;lt;/code&amp;gt;, e.g.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    initrd /current/0/@/boot/initramfs-lts&lt;br /&gt;
    options &amp;quot;root=UUID=b9ff5e7b-e128-4e64-861a-2fdd794a9828 rootfstype=btrfs rootflags=subvol=/current/0/@,ro,noatime resume=UUID=f0239163-9d46-47c1-67a4-3ee1d63d0676 overlaytmpfs quiet splash&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    submenuentry &amp;quot;Boot fallback 1&amp;quot; {&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Production_DataBases_:_mysql&amp;diff=21196</id>
		<title>Production DataBases : mysql</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Production_DataBases_:_mysql&amp;diff=21196"/>
		<updated>2021-12-31T14:20:50Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: /* File system notes about the databases managed */ add reference to btrfs page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://mariadb.org/ MariaDB] is a community-developed fork of the MySQL relational database management system intended to remain free under the GNU GPL. It is notable for being led by the original developers of MySQL, who forked it due to concerns over its acquisition by Oracle.&lt;br /&gt;
&lt;br /&gt;
This page assumed that you have a general knowledge about MariaDB, so if you are new to MySQL first take a look at the [[MariaDB|MariaDB wiki page]] for information about how are packaged for alpine linux.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Alpine Linux has dummy counterparts packages for those that are not close to that change from &#039;&#039;mysql&#039;&#039; to &#039;&#039;mariadb&#039;&#039; naming packages, please check the [[MariaDB|MariaDB wiki page]] for more information.&lt;br /&gt;
&lt;br /&gt;
Take in consideration that the user &amp;lt;code&amp;gt;mysql&amp;lt;/code&amp;gt; was created during instalation of packages, in the initialization section two users will be created in database init: &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;mysql&amp;lt;/code&amp;gt;, and in that point only if are in their respective system accounts, will be able to connect to the database service.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
apk add mysql mysql-client&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That will install the most used ones.. &amp;lt;code&amp;gt;mariadb-cient&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;mariadb-server&amp;lt;/code&amp;gt;, rest of packages are brief described here for more information, here are listed in orden of relevance for production server&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! MySQL name package !! Since Alpine: !! Brief usage !! Related package&lt;br /&gt;
|-&lt;br /&gt;
| mysql || v2 || it&#039;s a dummy package to easy install of mariadb || mariadb&lt;br /&gt;
|-&lt;br /&gt;
| mysql-client || v2 || it&#039;s a dummy package to easy install of commands tools || mariadb-client&lt;br /&gt;
|-&lt;br /&gt;
| mariadb || v2 || server equivalent to mysql-server || mariadb-common&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-client || v2 || connection command line and tools || mariadb-common&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-doc || v3.0 || manpages are there! || man man-pages&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-connector-odbc || edge || coding or making OS level connections, to any DB without libs install || .&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-connector-c || v3.8 || coding connection on C sources || mariadb-connector-c-dev&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-backup || v3.8 || to external backup devices, not widely used, in past was inside mariadb package || .&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-server-utils || v3.8 || server commands not widely used, in past was inside mariadb package || .&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-dev || v3.1 || Need for compilations depends on source code || .&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-test || v3.3 || testing suite from MariaDB tools || .&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-mytop || v3.9 || data performance monitoring || .&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-plugin-rocksdb || v3.9 || plain key-value event relational for data || .&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-static || v3.8 || static libs for static non depends linking in builds || .&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-embedded || v3.9 || the libmysqld identical interface as the C client || mariadb-embedded-dev&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-embedded-dev || v3.9 ||  use the normal mysql.h and link with libmysqld instead of libmysqlclient || mariadb-dev&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-openrc || v3.8 || separate scripts, in past was embebed on server package || .&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
The alpine package of MySQL/MariaDB are like normal tarball of MySQL one, admins must be know what they want.. there&#039;s no automatic window-like here.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;datadir&#039;&#039; are located to &amp;lt;code&amp;gt;/var/lib/mysql&amp;lt;/code&amp;gt; must be owned by the mysql user and group. You can modify this behavior but must edit the service file at &amp;lt;code&amp;gt;/etc/init.d&amp;lt;/code&amp;gt; directory. Also, you need to set &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;datadir=&amp;lt;YOUR_DATADIR&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; under section &amp;lt;code&amp;gt;[mysqld]&amp;lt;/code&amp;gt; at the config file.&lt;br /&gt;
&lt;br /&gt;
# Initialize the main mysql database, and the data dir as standardized to &amp;lt;code&amp;gt;/var/lib/mysql&amp;lt;/code&amp;gt; by the rc script&lt;br /&gt;
# Then initialize the service, root account and socket connection are enabled without password at this point&lt;br /&gt;
# Setup the root account by asignes a proper password, this are purely paranoid. due next step already do that!&lt;br /&gt;
# Setup and init the installation by running the &amp;lt;code&amp;gt;mysql_secure_installation&amp;lt;/code&amp;gt;&lt;br /&gt;
# Setup permissions for manage others users and databases&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
mysql_install_db --user=mysql --datadir=/var/lib/mysql&lt;br /&gt;
&lt;br /&gt;
rc-service mariadb start&lt;br /&gt;
&lt;br /&gt;
mysqladmin -u root password toor&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After that, all are initializated to proceed with configuration, now can be done using the &amp;lt;code&amp;gt;&lt;br /&gt;
mysql_secure_installation&amp;lt;/code&amp;gt; script at the next section:&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
In order to finish setup into &#039;&#039;&#039;MariaDB&#039;&#039;&#039; now provide &#039;&#039;&#039;this script called &amp;lt;code&amp;gt;mysql_secure_instalation&amp;lt;/code&amp;gt; that also are present as &amp;lt;code&amp;gt;mariadb-secure-installation&amp;lt;/code&amp;gt;&#039;&#039;&#039;, too. This script provides minimal and security setup to the database, and here are the questions made explained:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Enter current password for root (enter for none):&#039;&#039;&#039; this are if you previously setup as we done in previous section a root password, just provide it and press enter, &#039;&#039;&#039;must be provided due we already set previously&#039;&#039;&#039; and from now, this sript will access to the engine and alter many setting on the database. Correct respond are &amp;lt;code&amp;gt;OK, successfully used password, moving on...&amp;lt;/code&amp;gt;&lt;br /&gt;
#  &#039;&#039;&#039;Switch to unix_socket authentication [Y/n]&#039;&#039;&#039; Setting the root password or using the unix_socket ensures that only admins can log into engine database. Since mysql 5.6 and mariadb 10.2 a new auth mechanish are set, by socket authentiaction, when system user are same as mysql/mariadb user, in this case, no password are need. In production servers this are not the case and must be disabled, &#039;&#039;&#039;so answer NO&#039;&#039;&#039;, and response will be &amp;lt;code&amp;gt;... skipping.&amp;lt;/code&amp;gt;&lt;br /&gt;
# &#039;&#039;&#039;Change the root password? [Y/n]&#039;&#039;&#039; this answer are here only if the first one are just enter, or if can provide a better passowrd if no unix socket are set. Just press &amp;quot;n&amp;quot; only if you provided a good password, otherwise just &lt;br /&gt;
# &#039;&#039;&#039;Remove anonymous users? [Y/n]&#039;&#039;&#039; this permits remove the anonymous user created to log using socket authentication, only working on unix-like system. In any case, &#039;&#039;&#039;production system must remove it, so answer Y&#039;&#039;&#039; and proper respond must be  &amp;lt;code&amp;gt;... Success!&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;Disallow root login remotely? [Y/n]&#039;&#039;&#039; Normally, root should only be allowed to connect from &#039;localhost&#039;. This ensures that someone cannot guess at the root password from the network. For sure answer Y&#039;&#039;&#039; and proper respond must be  &amp;lt;code&amp;gt;... Success!&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;Remove test database and access to it? [Y/n]&#039;&#039;&#039; By default, MariaDB comes with a database named &#039;test&#039; that anyone can access. This is also intended only for testing, and should be removed, so answer Y&#039;&#039;&#039; and proper respond must be  &amp;lt;code&amp;gt;... Success!&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;Reload privilege tables now? [Y/n]&#039;&#039;&#039; Reloading the privilege tables will ensure that all changes made so far will take effect immediately, so answer Y&#039;&#039;&#039; and proper respond must be  &amp;lt;code&amp;gt;... Success!&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
After reponse all the questions.. restart the service with &amp;lt;code&amp;gt;rc-service mariadb restart&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Configuration files ===&lt;br /&gt;
&lt;br /&gt;
Due today were influenced by systemd standardization, the famous &amp;lt;nowiki&amp;gt;my.cnf&amp;lt;/nowiki&amp;gt; are not more the main config file for the server engine. Now only few variables are defined there and all the settings are provided by independent files into the &amp;lt;code&amp;gt;/etc/my.cnf.d/&amp;lt;/code&amp;gt; directory, user own config files are under &amp;lt;code&amp;gt;~/.my.cnf&amp;lt;/code&amp;gt; config file of each home dir, and are read after global ones; so then we have:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Config file !! Path and name !! Versions of Alpine !! Contents to configure&lt;br /&gt;
|-&lt;br /&gt;
| my.cnf || &amp;lt;nowiki&amp;gt;/etc/mysql/my.cnf&amp;lt;/nowiki&amp;gt; || v2 to v3.8 || All the directives, Global config file&lt;br /&gt;
|-&lt;br /&gt;
| mariadb-server.cnf || /etc/my.cnf.d/mariadb-server.cnf || since 3.9 || First Global config file, main directives&lt;br /&gt;
|-&lt;br /&gt;
| .my.cnf || &amp;lt;nowiki&amp;gt;$HOME&amp;lt;/nowiki&amp;gt; || all || user name only config directives&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Production settings ===&lt;br /&gt;
&lt;br /&gt;
These setting are only recommended for some server settings, there are the recommendation for high production settings:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Config setting !! Default !! Recommended !! Explanation&lt;br /&gt;
|-&lt;br /&gt;
| main ram || 2G || 8G - 16G || MariaDB/MySQL can run with 512M or 1G of ram, high production must use minimun of 4G or more.&lt;br /&gt;
|-&lt;br /&gt;
| data dir disk type || any || SSD || MariaDB/MySQL must run with faster SSD if high request will be produced.&lt;br /&gt;
|-&lt;br /&gt;
| collation_server || utf8_unicode_ci || utf8mb4_unicode_ci || With 8mb4 some characters are able to use more than a single byte.&lt;br /&gt;
|-&lt;br /&gt;
| character_set_client || iso8859-1 || utf8 or utf8mb4 || Important due are standard, for left to right use 8mb4 flavor&lt;br /&gt;
|-&lt;br /&gt;
| max_connections || 151 || 100 || total_connections = total_processes * (total_threads + script_servers + 1)&lt;br /&gt;
|-&lt;br /&gt;
| max_heap_table_size || 16M || 32M || allocate more memory to memory tables, for memory storage engines&lt;br /&gt;
|-&lt;br /&gt;
| tmp_table_size || 16M || 32M || It allows the sub queries to remain more in memory, making them faster&lt;br /&gt;
|-&lt;br /&gt;
| join_buffer_size || 32M || 64M || It allows the join queries to remain more in memory rather in temp files&lt;br /&gt;
|-&lt;br /&gt;
| innodb_file_format || unset || Barracuda || will allow longer indexes for important most used tables&lt;br /&gt;
|-&lt;br /&gt;
| innodb_large_prefix || unset || 1 || Must set if Barracuda file format are choosen&lt;br /&gt;
|-&lt;br /&gt;
| innodb_buffer_pool_size || 128M || 456M || hold as much tables and indexes in system memory as is possible&lt;br /&gt;
|-&lt;br /&gt;
| innodb_read_io_threads || 16 || 32 || On high I/O systems, a value greater than 1 may allow the disk I/O to be more sequential&lt;br /&gt;
|-&lt;br /&gt;
| innodb_write_io_threads || 16 || 32 || Only if you have SSD storage for the data MySQL/MariaDB database and temp files&lt;br /&gt;
|-&lt;br /&gt;
| innodb_buffer_pool_instances || 1 || 2 or 4 || Only for older MySQL/MariaDB engines,&lt;br /&gt;
|-&lt;br /&gt;
| innodb_io_capacity || 200 || 1200 - 2600 || Only if you have SSD storage for the data MySQL/MariaDB database and temp files&lt;br /&gt;
|-&lt;br /&gt;
| innodb_io_capacity_max || 200 || 2400 - 5200 || Only if you have SSD storage for the data MySQL/MariaDB database and temp files&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If you have SSD disks, use the recommended suggestion, otherwise, use minimum suggested. If you have physical hard drives, use 2000 * the number of active drives in the array. If using NVMe or PCIe Flash, much larger numbers as high as 200000 can be used, but those lasted storage devices will be a short life of course.&lt;br /&gt;
&lt;br /&gt;
Newer system Alpine packages can set in independent files in any case those commands always works and where are not apply just will ignore the output:&lt;br /&gt;
&lt;br /&gt;
* On older Alpine system must set config files for MAX ALLOWED PACKETS to minimun proper amount:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
sed -i &amp;quot;s|.*max_allowed_packet\s*=.*|max_allowed_packet = 100M|g&amp;quot; /etc/mysql/my.cnf&lt;br /&gt;
sed -i &amp;quot;s|.*max_allowed_packet\s*=.*|max_allowed_packet = 100M|g&amp;quot; /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Only allow local connections on cases where there&#039;s only one server or no expected to connect from others:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
sed -i &amp;quot;s|.*bind-address\s*=.*|bind-address=127.0.0.1|g&amp;quot; /etc/mysql/my.cnf&lt;br /&gt;
sed -i &amp;quot;s|.*bind-address\s*=.*|bind-address=127.0.0.1|g&amp;quot; /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* If are not in domain controller, dont search for hostnames to improve performance responses (ideal for local only servers):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
sed -i &amp;quot;s|.*skip-networking.*|skip-networking|g&amp;quot; /etc/mysql/my.cnf&lt;br /&gt;
sed -i &amp;quot;s|.*skip-networking.*|skip-networking|g&amp;quot; /etc/my.cnf.d/mariadb-server.cnf&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Set default charset to UTF8MB4, in newer versions (since Alpine v3.9), just added a new file to added thus customization, but older versions (below Alpine v3.8)of the package does not have a charset section, so you must added manually to the main configuration in each respective section:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
cat &amp;gt; /etc/my.cnf.d/mariadb-server-default-charset.cnf &amp;lt;&amp;lt; EOF&lt;br /&gt;
[client]&lt;br /&gt;
default-character-set = utf8mb4&lt;br /&gt;
&lt;br /&gt;
[mysqld]&lt;br /&gt;
collation_server = utf8mb4_unicode_ci&lt;br /&gt;
character_set_server = utf8mb4&lt;br /&gt;
&lt;br /&gt;
[mysql]&lt;br /&gt;
default-character-set = utf8mb4&lt;br /&gt;
EOF&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Updating or comming from upgrading ==&lt;br /&gt;
&lt;br /&gt;
Mayor Upgrades beetween Alpine linux version are so easy as change the repository version, but the MySQL/MariaDB  engine need some extra steps when this are performed:&lt;br /&gt;
&lt;br /&gt;
Upgrade databases on major releases&lt;br /&gt;
Upon a major version release of mariadb (for example mariadb-10.1.10-1 to mariadb-10.1.18-1), it is wise to upgrade databases:&lt;br /&gt;
&lt;br /&gt;
# keep the old database (mysql sheme) structure of the engine daemon, currently this are not more the case, today this not make sense anymore&lt;br /&gt;
# upgrade the MariaDB/MySQL packages, of course with must be done if the upgrade process to mayor alpine version does not!&lt;br /&gt;
# run the &amp;lt;code&amp;gt;mysql_upgrade -u root -p&amp;lt;/code&amp;gt; script, providing the password or root, (from the new package version) against the old still-running database (mysql sheme). This will produce some error messages; however, the upgrade will succeed.&lt;br /&gt;
# Restart the service&lt;br /&gt;
&lt;br /&gt;
If are unable to run &#039;&#039;mysql_upgrade&#039;&#039; because MySQL cannot start try run MySQL in safemode with &amp;lt;code&amp;gt;mysqld_safe --datadir=/var/lib/mysql/&amp;lt;/code&amp;gt; command and then run the &amp;lt;code&amp;gt;mysql_upgrade -u root -p&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
= Relevant important notes =&lt;br /&gt;
&lt;br /&gt;
== File system notes about the databases managed ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BTRFS Notes&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
If the database (in &amp;lt;code&amp;gt;/var/lib/mysql&amp;lt;/code&amp;gt;) resides on a [[BTRFS|btrfs]] file system, you should consider disabling &#039;&#039;&#039;Copy-on-Write&#039;&#039;&#039; for the directory before creating any database (schemes), after initialization you can enabled again. But .. on every database creation (scheme creation), you must disabled again, to avoid corrupted data.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ZFS Bock sizes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
ZFS, unlike most other file systems, has a variable record size, or what is commonly referred to as a block size. By default, the recordsize on ZFS is 128KiB, which means it will dynamically allocate blocks of any size from 512B to 128KiB depending on the size of file being written. Most RDBMSes work in 8KiB-sized blocks by default. Although the block size is tunable for MySQL/MariaDB use an 8KiB block size by default.&lt;br /&gt;
&lt;br /&gt;
It is usually desirable to tune ZFS instead to accommodate the databases, using a command such as &amp;lt;code&amp;gt;zfs set recordsize=8K /var/lib/mysql&amp;lt;/code&amp;gt; (or change /var/lib/mysql to the mount point where /var/lib/mysql resides) and in the interest of saving memory, it is best to simply disable ZFS&#039;s caching of the database&#039;s file data and let the database do its own job  with &amp;lt;code&amp;gt;zfs set primarycache=metadata /var/lib/mysql&amp;lt;/code&amp;gt; (or change /var/lib/mysql to the mount point where /var/lib/mysql resides).&lt;br /&gt;
&lt;br /&gt;
But beware, these kinds of tuning parameters are only if RDBMSes are setup in dedicated partitions, if your root and of course database are all in one partition, dont do that. Separate ones.&lt;br /&gt;
&lt;br /&gt;
== Restore root password ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
rc-service mysql stop&lt;br /&gt;
&lt;br /&gt;
kill  `cat /run/mysqld/mysqld.pid`&lt;br /&gt;
&lt;br /&gt;
/usr/bin/mysqld --datadir=/var/lib/mysql --pid-file=/run/mysqld/mysqld.pid --skip-grant-tables --skip-networking &amp;amp;&lt;br /&gt;
&lt;br /&gt;
mysql -e &amp;quot;ALTER USER &#039;root&#039;@&#039;localhost&#039; IDENTIFIED BY &#039;MyNewPass&#039;;FLUSH PRIVILEGES;ALTER USER &#039;root&#039;@&#039;localhost&#039; IDENTIFIED BY &#039;MyNewPass&#039;;FLUSH PRIVILEGES;set password = password(&#039;MyNewPass&#039;);&amp;quot;&lt;br /&gt;
&lt;br /&gt;
kill  `cat /run/mysqld/mysqld.pid`&lt;br /&gt;
&lt;br /&gt;
rc-service mariadb restart&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= See Also =&lt;br /&gt;
&lt;br /&gt;
* [[MariaDB|MariaDB wiki page]]&lt;br /&gt;
* [[Production LAMP system: Lighttpd + PHP + MySQL]]&lt;br /&gt;
* [[Alpine newbie developer]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Newbie]]&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Database]]&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Security]]&lt;br /&gt;
[[Category:Production]]&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Bootloaders&amp;diff=21195</id>
		<title>Bootloaders</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Bootloaders&amp;diff=21195"/>
		<updated>2021-12-31T14:20:17Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: /* Installing Syslinux */ add reference to btrfs page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
This page shows the basic steps you need to perform, if you for any reason want to switch bootloaders or apply some manual configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rEFInd&amp;lt;/code&amp;gt; is an easy to use EFI boot menu that allows booting different operating systems.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;Syslinux&amp;lt;/code&amp;gt; is the default light-weight bootloader used in Alpine.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;Grub&amp;lt;/code&amp;gt; is a standard linux boot loader.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;EFI Boot Stub&amp;lt;/code&amp;gt; allows booting linux directly from a motherboard supporting UEFI or another bootloader.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= rEFIind =&lt;br /&gt;
&lt;br /&gt;
For (U)EFI systems, the &amp;lt;code&amp;gt;refind&amp;lt;/code&amp;gt; package can provide a graphical EFI boot menu that allows to boot operating systems that are found on the available partitions.&lt;br /&gt;
&lt;br /&gt;
If &amp;lt;code&amp;gt;refind&amp;lt;/code&amp;gt; is not yet available in the used alpine release, it may be installed in another dual/multi-booted linux distribution.&lt;br /&gt;
&lt;br /&gt;
For example, with a Debian based distribution, it can be installed to the EFI partition like this:&lt;br /&gt;
 &lt;br /&gt;
 apt install refind             # installs the debian package&lt;br /&gt;
 refind-install --alldrivers    # installs refind to the EFI partitioon&lt;br /&gt;
&lt;br /&gt;
(The --alldrivers option includes all filesystem drivers instead of only the one needed to load the currently running kernel, to allow finding and booting operating systems from more partitions.)&lt;br /&gt;
&lt;br /&gt;
And a first (default) boot menu line needs to be configured with Alpine&#039;s default boot parameters. Assuming the bootable partition is mounted at &amp;lt;code&amp;gt;/media/sdXY&amp;lt;/code&amp;gt; it can be done like this (at time of writing):&lt;br /&gt;
 echo &#039;&amp;quot;Alpine&amp;quot; &amp;quot;modules=loop,squashfs,sd-mod,usb-storage quiet initrd=\boot\intel-ucode.img initrd=\boot\amd-ucode.img initrd=\boot\initramfs-lts&amp;quot;&#039; &amp;gt; /media/sdXY/boot/refind_linux.conf&lt;br /&gt;
&lt;br /&gt;
{{Note|&lt;br /&gt;
&lt;br /&gt;
# At the time of writing, it was still needed to use backslashes in the .conf file. &lt;br /&gt;
# The path in the config file needs to be relative to the partition that the kernel resides on. If &amp;lt;code&amp;gt;/boot&amp;lt;/code&amp;gt; resides on its own separate partition, then &amp;lt;code&amp;gt;\boot&amp;lt;/code&amp;gt; needs to be removed from the paths.                                                                                               }}&lt;br /&gt;
&lt;br /&gt;
= Installing Syslinux =&lt;br /&gt;
&lt;br /&gt;
If you want to switch from another bootloader back to Syslinux, or if you for some reason want to install Syslinux manually, the following steps are required.&lt;br /&gt;
&lt;br /&gt;
Install the &amp;lt;code&amp;gt;syslinux&amp;lt;/code&amp;gt; package:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apk add syslinux&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you&#039;re using GPT partitions, install the GPT MBR onto the drive you want to install the bootloader on (in this case &amp;lt;code&amp;gt;/dev/sda&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd bs=440 count=1 conv=notrunc if=/usr/share/syslinux/gptmbr.bin of=/dev/sda&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if you&#039;re using DOS partitions, install the DOS MBR instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dd bs=440 count=1 conv=notrunc if=/usr/share/syslinux/mbr.bin of=/dev/sda&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- See also: http://www.syslinux.org/wiki/index.php?title=Mbr --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next install the required Syslinux binaries. Despite being called &amp;lt;code&amp;gt;extlinux&amp;lt;/code&amp;gt;, Syslinux supports booting from FAT12/16/32, NTFS, ext2/3/4, [[BTRFS|btrfs]], XFS, and UFS/FFS filesystems.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;extlinux --install /boot&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The configuration file is located in &amp;lt;code&amp;gt;/boot/extlinux.conf&amp;lt;/code&amp;gt;.&lt;br /&gt;
Alpine ships with a script called &amp;lt;code&amp;gt;update-extlinux&amp;lt;/code&amp;gt; which automatically (re)generates this file, for example on updates to Syslinux.&lt;br /&gt;
The settings for this script can be found in &amp;lt;code&amp;gt;/etc/update-extlinux.conf&amp;lt;/code&amp;gt;, including the option to disable automatic overwriting of &amp;lt;code&amp;gt;/boot/extlinux.conf&amp;lt;/code&amp;gt;.&lt;br /&gt;
You can also place additional menu entries in the &amp;lt;code&amp;gt;/etc/update-extlinux.d/&amp;lt;/code&amp;gt; directory, e.g. for dual booting.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== EFI ===&lt;br /&gt;
&lt;br /&gt;
{{Todo|Work in progress. This should at least get you started.}}&lt;br /&gt;
&lt;br /&gt;
Assuming &amp;lt;code&amp;gt;/mnt&amp;lt;/code&amp;gt; is a FAT32 partition of type EF00 and &amp;lt;code&amp;gt;/boot&amp;lt;/code&amp;gt; belongs to the rootfs created after running &amp;lt;code&amp;gt;setup-disk&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir -p /mnt/EFI/syslinux&lt;br /&gt;
cp /usr/share/syslinux/efi64/* /mnt/EFI/syslinux/&lt;br /&gt;
cp /boot/extlinux.conf /mnt/EFI/syslinux/syslinux.cfg&lt;br /&gt;
cp /boot/vmlinuz* /mnt/&lt;br /&gt;
cp /boot/initramfs* /mnt/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You may need to modify &amp;lt;code&amp;gt;/mnt/EFI/syslinux/syslinux.cfg&amp;lt;/code&amp;gt; to change the paths to absolute paths (just add a / in front of the vmlinuz/initramfs entries),&lt;br /&gt;
or copy the files to &amp;lt;code&amp;gt;/mnt/EFI/syslinux&amp;lt;/code&amp;gt; instead (XXX: untested).&lt;br /&gt;
&lt;br /&gt;
= GRUB =&lt;br /&gt;
&lt;br /&gt;
To install GRUB in BIOS mode, (optionally) remove the Syslinux package and install the required GRUB packages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apk del syslinux&lt;br /&gt;
apk add grub grub-bios&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For EFI, install Grub&#039;s EFI package instead. Note that &amp;lt;code&amp;gt;/boot&amp;lt;/code&amp;gt; has to be an EFI compatible filesystem like FAT32.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apk add grub-efi&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next install the MBR and GRUB binaries to disk for BIOS mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;grub-install /dev/vda&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For EFI mode:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;grub-install --target=x86_64-efi --efi-directory=/boot&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
GRUB ships with an automatic config generator, including some automatic detection of other operating systems installed on the device:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;grub-mkconfig -o /boot/grub/grub.cfg&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This script can be configured via the &amp;lt;code&amp;gt;/etc/default/grub&amp;lt;/code&amp;gt; file.&lt;br /&gt;
See [https://www.gnu.org/software/grub/manual/html_node/Simple-configuration.html] for a list of available options.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= EFI Boot Stub =&lt;br /&gt;
&lt;br /&gt;
To boot directly from your motherboard&#039;s UEFI boot menu, a boot entry needs&lt;br /&gt;
to be created with either a UEFI shell or &#039;&#039;efibootmgr&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== efibootmgr ==&lt;br /&gt;
&lt;br /&gt;
Install efibootmgr:&lt;br /&gt;
&amp;lt;pre&amp;gt;apk add efibootmgr&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a boot entry. It&#039;s recommended to do this in a script, as efibootmgr&lt;br /&gt;
does not allow editing entries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
params=&amp;quot;root=/dev/sdXZ rw \&lt;br /&gt;
  initrd=\intel-ucode.img \&lt;br /&gt;
  initrd=\initramfs-lts&amp;quot;&lt;br /&gt;
&lt;br /&gt;
efibootmgr --create --label &amp;quot;Alpine Linux&amp;quot; \&lt;br /&gt;
  --disk /dev/sdX --part Y \&lt;br /&gt;
  --loader /vmlinuz-lts \&lt;br /&gt;
  --unicode &amp;quot;${params}&amp;quot; \&lt;br /&gt;
  --verbose&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;/dev/sdXY&amp;lt;/code&amp;gt; contains the EFI partition and &amp;lt;code&amp;gt;/dev/sdXZ&amp;lt;/code&amp;gt; contains the root partition. If you are using {{Pkg|linux-edge}}, replace &amp;lt;code&amp;gt;lts&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;edge&amp;lt;/code&amp;gt; in the script&lt;br /&gt;
&lt;br /&gt;
{{Note|&lt;br /&gt;
The kernel contains the [https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/init/do_mounts.c#n254 exhaustive list] of ways to specify the block device. For a more robust boot entry, it is recommended to use a persistent name such as the PARTUUID.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Optionally, set the newly created entry as the default:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;efibootmgr -n XXXX&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;XXXX&amp;lt;/code&amp;gt; is the boot number of the new entry.&lt;br /&gt;
&lt;br /&gt;
{{Note|&lt;br /&gt;
The loader and initrd file arguments are relative to the EFI partition. In a default installation, alpine places these files in &amp;lt;code&amp;gt;/boot/&amp;lt;/code&amp;gt;, while EFI is mounted to &amp;lt;code&amp;gt;/boot/efi/&amp;lt;/code&amp;gt;. You can either update fstab to mount EFI at &amp;lt;code&amp;gt;/boot/&amp;lt;/code&amp;gt;, or manually copy them to &amp;lt;code&amp;gt;/boot/efi/&amp;lt;/code&amp;gt;.                                                                                           }}&lt;br /&gt;
&lt;br /&gt;
= External Links =&lt;br /&gt;
* [https://www.denx.de/wiki/U-Boot/ReleaseCycle U-Boot Release Cycle]&lt;br /&gt;
&lt;br /&gt;
[[Category:Installation]]&lt;br /&gt;
[[Category:Booting]]&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Alpine_configuration_management_scripts&amp;diff=21194</id>
		<title>Alpine configuration management scripts</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Alpine_configuration_management_scripts&amp;diff=21194"/>
		<updated>2021-12-31T14:19:35Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: /* setup-disk */ add reference to btrfs page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Feature descriptions for available Alpine Linux setup scripts ({{Path|/sbin/setup-*}}).&lt;br /&gt;
&lt;br /&gt;
These scripts can be installed from alpine-conf package using apk.&lt;br /&gt;
&lt;br /&gt;
(Some particular example usages can be seen at [[Alpine_newbie_install_manual#Ways_to_install_Alpine_into_machines_or_virtuals|Alpine for new users install manuals]].)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== setup-alpine ==&lt;br /&gt;
&lt;br /&gt;
This is the main Alpine configuration and installation script.&lt;br /&gt;
&lt;br /&gt;
The script interactively walks the user through executing several auxiliary &amp;lt;code&amp;gt;setup-*&amp;lt;/code&amp;gt; scripts, in the order shown below.&lt;br /&gt;
&lt;br /&gt;
The bracketed options represent example configuration choices, formatted as they may be supplied when manually calling the auxiliary setup scripts, or using a &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; &amp;quot;answerfile&amp;quot; (see below).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;code&amp;gt;setup-keymap&amp;lt;/code&amp;gt; [us us]&lt;br /&gt;
# [[#setup-hostname|setup-hostname]] [-n alpine-test]&lt;br /&gt;
# [[#setup-interfaces|setup-interfaces]] [-i &amp;lt; interfaces-file]&lt;br /&gt;
# &amp;lt;code&amp;gt;/etc/init.d/networking --quiet start &amp;amp;&amp;lt;/code&amp;gt;&lt;br /&gt;
# if none of the networking interfaces were configured using dhcp, then: &amp;lt;code&amp;gt;[[#setup-dns|setup-dns]]&amp;lt;/code&amp;gt; [-d example.com -n &amp;quot;192.168.0.1 [...]&amp;quot;]&lt;br /&gt;
# set the root password&lt;br /&gt;
# if not in quick mode, then: &amp;lt;code&amp;gt;[[#setup-timezone|setup-timezone]]&amp;lt;/code&amp;gt; [-z UTC | -z America/New_York | -p EST+5]&lt;br /&gt;
# enable the new hostname (&amp;lt;code&amp;gt;/etc/init.d/hostname --quiet restart&amp;lt;/code&amp;gt;)&lt;br /&gt;
# add &amp;lt;code&amp;gt;networking&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;urandom&amp;lt;/code&amp;gt; to the &#039;&#039;&#039;boot&#039;&#039;&#039; rc level, and &amp;lt;code&amp;gt;acpid&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;crond&amp;lt;/code&amp;gt; to the &#039;&#039;&#039;default&#039;&#039;&#039; rc level, and start the &#039;&#039;&#039;boot&#039;&#039;&#039; and &#039;&#039;&#039;default&#039;&#039;&#039; rc services&lt;br /&gt;
# extract the fully-qualified domain name and hostname from {{Path|/etc/resolv.conf}} and &amp;lt;code&amp;gt;hostname&amp;lt;/code&amp;gt;, and update {{Path|/etc/hosts}}&lt;br /&gt;
# &amp;lt;code&amp;gt;[[#setup-proxy|setup-proxy]]&amp;lt;/code&amp;gt; [-q &amp;lt;nowiki&amp;gt;&amp;quot;http://webproxy:8080&amp;quot;&amp;lt;/nowiki&amp;gt;], and activate proxy if it was configured&lt;br /&gt;
# &amp;lt;code&amp;gt;setup-apkrepos&amp;lt;/code&amp;gt; [-r (to select a mirror randomly)]&lt;br /&gt;
# if not in quick mode, then: &amp;lt;code&amp;gt;[[#setup-sshd|setup-sshd]]&amp;lt;/code&amp;gt; [-c openssh | dropbear | none]&lt;br /&gt;
# if not in quick mode, then: &amp;lt;code&amp;gt;setup-ntp&amp;lt;/code&amp;gt; [-c chrony | openntpd | busybox | none]&lt;br /&gt;
# if not in quick mode, then: &amp;lt;code&amp;gt;DEFAULT_DISK=none&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;[[#setup-disk|setup-disk]]&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;-q&amp;lt;/code&amp;gt; [-m data /dev/sda] (see [[Installation#Installation_Overview]] about the disk modes)&lt;br /&gt;
# if installation mode selected during setup-disk was &amp;quot;data&amp;quot; instead of &amp;quot;sys&amp;quot;, then: &amp;lt;code&amp;gt;setup-lbu&amp;lt;/code&amp;gt; [/media/sdb1]&lt;br /&gt;
# if installation mode selected during setup-disk was &amp;quot;data&amp;quot; instead of &amp;quot;sys&amp;quot;, then: &amp;lt;code&amp;gt;setup-apkcache&amp;lt;/code&amp;gt; [/media/sdb1/cache | none]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; itself accepts the following command-line switches&lt;br /&gt;
&lt;br /&gt;
{{Define|-h|Shows the up-to-date usage help message.}}&lt;br /&gt;
&lt;br /&gt;
{{Define|-a|Create an overlay file: this creates a temporary directory and saves its location in ROOT; however, the script doesn&#039;t export this variable so I think this feature isn&#039;t currently functional.}}&lt;br /&gt;
;-c &amp;lt;var&amp;gt;answerfile&amp;lt;/var&amp;gt;&lt;br /&gt;
:Create a new &amp;quot;answerfile&amp;quot;, with default choices. You can edit the file and then invoke &amp;lt;code&amp;gt;setup-alpine -f &amp;lt;var&amp;gt;answerfile&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
;-f &amp;lt;var&amp;gt;answerfile&amp;lt;/var&amp;gt;&lt;br /&gt;
:Use an existing &amp;quot;answerfile&amp;quot;, which may override some or all of the interactive prompts.&lt;br /&gt;
{{Define|-q|Run in &amp;quot;quick mode&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-hostname ==&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;setup-hostname&amp;lt;/code&amp;gt; [-h] [-n hostname]&lt;br /&gt;
&lt;br /&gt;
Options:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-h&#039;&#039;&#039; &amp;lt;var&amp;gt;Show help&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-n&#039;&#039;&#039; &amp;lt;var&amp;gt;Specify hostname&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This script allows quick and easy setup of the system hostname by writing it to {{Path|/etc/hostname}}.  The script prevents you from writing an invalid hostname (such as one that used invalid characters or starts with a &#039;-&#039; or is too long).&lt;br /&gt;
The script can be invoked manually or is called as part of the &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-interfaces ==&lt;br /&gt;
{{Cmd|setup-interfaces [-i &amp;amp;lt; &amp;lt;var&amp;gt;interfaces-file&amp;lt;/var&amp;gt;]}}&lt;br /&gt;
&lt;br /&gt;
Note that the contents of &amp;lt;var&amp;gt;interfaces-file&amp;lt;/var&amp;gt; has to be supplied as stdin, rather than naming the file as an additional argument. The contents should have the format of {{Path|/etc/network/interfaces}}, such as:&lt;br /&gt;
&lt;br /&gt;
 auto lo&lt;br /&gt;
 iface lo inet loopback&lt;br /&gt;
 &lt;br /&gt;
 auto eth0&lt;br /&gt;
 iface eth0 inet dhcp&lt;br /&gt;
     hostname alpine-test&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-dns ==&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;setup-dns&amp;lt;/code&amp;gt; [-h] [-d domain name] [-n name server]&lt;br /&gt;
&lt;br /&gt;
Options:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-h&#039;&#039;&#039; &amp;lt;var&amp;gt;Show help&amp;lt;/var&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-d&#039;&#039;&#039; &amp;lt;var&amp;gt;specify search domain name&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-n&#039;&#039;&#039; &amp;lt;var&amp;gt;name server IP&amp;lt;/var&amp;gt; &lt;br /&gt;
&lt;br /&gt;
The setup-dns script is stored in {{Path|/sbin/setup-dns}} and allows quick and simple setup of DNS servers (and a DNS search domain if required).  Simply running &amp;lt;code&amp;gt;setup-dns&amp;lt;/code&amp;gt; will allow interactive use of the script, or the options can be specified.&lt;br /&gt;
&lt;br /&gt;
The information fed to this script is written to {{Path|/etc/resolv.conf}}&lt;br /&gt;
&lt;br /&gt;
Example usage (with 192.168.0.1 being the local router/dns-forwarder): {{Cmd|setup-dns -d example.org -n 192.168.0.1}}&lt;br /&gt;
&lt;br /&gt;
Example {{Path|/etc/resolv.conf}}:&lt;br /&gt;
&lt;br /&gt;
 search example.org&lt;br /&gt;
 nameserver 192.168.0.1&lt;br /&gt;
&lt;br /&gt;
It can be run manually but is also invoked in the &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; script unless interfaces are configured for DHCP.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-timezone ==&lt;br /&gt;
:&amp;lt;code&amp;gt;setup-timezone&amp;lt;/code&amp;gt; [-z UTC | -z America/New_York | -p EST+5]&lt;br /&gt;
&lt;br /&gt;
Can pre-select the timezone using either of these switches:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-z&#039;&#039;&#039; &amp;lt;var&amp;gt;subfolder of&amp;lt;/var&amp;gt; {{Path|/usr/share/zoneinfo}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-p&#039;&#039;&#039; &amp;lt;var&amp;gt;POSIX TZ format&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-proxy ==&lt;br /&gt;
:&amp;lt;code&amp;gt;setup-proxy&amp;lt;/code&amp;gt; [-hq] [PROXYURL]&lt;br /&gt;
&lt;br /&gt;
Options:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-h&#039;&#039;&#039; &amp;lt;var&amp;gt;Show help&amp;lt;/var&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-q&#039;&#039;&#039; &amp;lt;var&amp;gt;Quiet mode&amp;lt;/var&amp;gt; prevents changes from taking effect until after reboot&lt;br /&gt;
&lt;br /&gt;
This script requests the system proxy to use in the form &amp;lt;code&amp;gt;http://&amp;lt;proxyurl&amp;gt;:&amp;lt;port&amp;gt;&amp;lt;/code&amp;gt; for example:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;http://10.0.0.1:8080&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To set no system proxy use &amp;lt;code&amp;gt;none&amp;lt;/code&amp;gt;.&lt;br /&gt;
This script exports the following environmental variables: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;http_proxy=$proxyurl&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;https_proxy=$proxyurl&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ftp_proxy=$proxyurl&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;code&amp;gt;$proxyurl&amp;lt;/code&amp;gt; is the value input.  &lt;br /&gt;
If &amp;lt;code&amp;gt;none&amp;lt;/code&amp;gt; was chosen then the value it is set to a blank value (and so no proxy is used).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-apkrepos ==&lt;br /&gt;
:&amp;lt;code&amp;gt;setup-apkrepos&amp;lt;/code&amp;gt; [-fhr] [REPO...]&lt;br /&gt;
&lt;br /&gt;
Setup &amp;lt;code&amp;gt;apk&amp;lt;/code&amp;gt; repositories.&lt;br /&gt;
&lt;br /&gt;
options:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-f&#039;&#039;&#039;  &amp;lt;var&amp;gt;Detect and add fastest mirror&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-r&#039;&#039;&#039;  &amp;lt;var&amp;gt;Add a random mirror and do not prompt&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-1&#039;&#039;&#039;  &amp;lt;var&amp;gt;Add first mirror on the list (normally a CDN)&amp;lt;/var&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is run as part of the &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-sshd ==&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;setup-sshd&amp;lt;/code&amp;gt; [-h] [-c choice of SSH daemon]&lt;br /&gt;
&lt;br /&gt;
Options:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-h&#039;&#039;&#039; &amp;lt;var&amp;gt;Show help&amp;lt;/var&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;-c&#039;&#039;&#039; &amp;lt;var&amp;gt;SSH daemon&amp;lt;/var&amp;gt; where SSH daemon can be one of the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;openssh&amp;lt;/code&amp;gt; install the {{Pkg|openSSH}} daemon&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;dropbear&amp;lt;/code&amp;gt; install the {{Pkg|dropbear}} daemon&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;none&amp;lt;/code&amp;gt; Do not install an SSH daemon&lt;br /&gt;
&lt;br /&gt;
Example usage: {{Cmd|setup-sshd -c dropbear}}&lt;br /&gt;
&lt;br /&gt;
The setup-sshd script is stored in {{Path|/sbin/setup-sshd}} and allows quick and simple setup of either the OpenSSH or Dropbear SSH daemon &amp;amp; client. &lt;br /&gt;
It can be run manually but is also invoked in the &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-ntp ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;From [https://en.wikipedia.org/wiki/Network_Time_Protocol Wikipedia]&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Network Time Protocol (NTP)&#039;&#039;&#039; is a networking protocol for clock synchronization between computer systems over packet-switched, variable-latency data networks. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Cmd|usage: setup-ntp [-h] [-c choice of NTP daemon]&lt;br /&gt;
&lt;br /&gt;
Setup NTP time synchronization&lt;br /&gt;
&lt;br /&gt;
options:&lt;br /&gt;
 -h  Show this help&lt;br /&gt;
 -c  Choice of NTP daemon: busybox openntpd chrony none}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;setup-ntp&amp;lt;/code&amp;gt; script is stored in {{Path|/sbin/setup-ntp}} and allows quick and simple setup of the NTP client,&lt;br /&gt;
It can be run manually but is also invoked in the &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-disk ==&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;DEFAULT_DISK=none setup-disk -q&amp;lt;/code&amp;gt; [-m data | sys] [&amp;lt;var&amp;gt;mountpoint directory&amp;lt;/var&amp;gt; | /dev/sda ...]&lt;br /&gt;
&lt;br /&gt;
In &amp;quot;sys&amp;quot; mode, it&#039;s an installer, it permanently installs Alpine on the disk, in &amp;quot;data&amp;quot; mode, it provides a larger and persistent /var volume.&lt;br /&gt;
&lt;br /&gt;
This script accepts the following command-line switches:&lt;br /&gt;
&lt;br /&gt;
;-k &amp;lt;var&amp;gt;kernel flavor&amp;lt;/var&amp;gt;&lt;br /&gt;
;-o &amp;lt;var&amp;gt;apkovl file&amp;lt;/var&amp;gt;&lt;br /&gt;
:Restore system from &amp;lt;var&amp;gt;apkovl file&amp;lt;/var&amp;gt;&lt;br /&gt;
;-m data | sys&lt;br /&gt;
:Don&#039;t prompt for installation mode. With &#039;&#039;&#039;-m data&#039;&#039;&#039;, the supplied devices are formatted to use as a {{Path|/var}} volume.&lt;br /&gt;
{{Define|-r|Use RAID1 with a single disk (degraded mode)}}&lt;br /&gt;
{{Define|-L|Create and use volumes in a LVM group}}&lt;br /&gt;
;-s &amp;lt;var&amp;gt;swap size in MB&amp;lt;/var&amp;gt;&lt;br /&gt;
:Use 0 to disable swap&lt;br /&gt;
{{Define|-q|Exit quietly if no disks are found}}&lt;br /&gt;
{{Define|-v|Verbose mode}}&lt;br /&gt;
&lt;br /&gt;
The script also honors the following environment variables:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;BOOT_SIZE&amp;lt;/code&amp;gt;&lt;br /&gt;
:Size of the boot partition in MB; defaults to 100. Only used if &#039;&#039;&#039;-m sys&#039;&#039;&#039; is specified or interactively selected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SWAP_SIZE&amp;lt;/code&amp;gt;&lt;br /&gt;
:Size of the swap volume in MB; set to 0 to disable swap. If not specified, will default to twice RAM, up to 4096, but won&#039;t be more than 1/3 the size of the smallest disk, and if less than 64 will just be 0. Only used if &#039;&#039;&#039;-m sys&#039;&#039;&#039; is specified or interactively selected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ROOTFS&amp;lt;/code&amp;gt;&lt;br /&gt;
:Filesystem to use for the / volume; defaults to ext4. Only used if &#039;&#039;&#039;-m sys&#039;&#039;&#039; is specified or interactively selected. Supported filesystems are: ext2 ext3 ext4 [[BTRFS|btrfs]] xfs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;BOOTFS&amp;lt;/code&amp;gt;&lt;br /&gt;
:Filesystem to use for the /boot volume; defaults to ext4. Only used if &#039;&#039;&#039;-m sys&#039;&#039;&#039; is specified or interactively selected. Supported filesystems are: ext2 ext3 ext4 [[BTRFS|btrfs]] xfs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VARFS&amp;lt;/code&amp;gt;&lt;br /&gt;
:Filesystem to use for the /var volume; defaults to ext4. Only used if &#039;&#039;&#039;-m data&#039;&#039;&#039; is specified or interactively selected. Supported filesystems are: ext2 ext3 ext4 [[BTRFS|btrfs]] xfs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SYSROOT&amp;lt;/code&amp;gt;&lt;br /&gt;
:Mountpoint to use when creating volumes and doing traditional disk install (&#039;&#039;&#039;-m sys&#039;&#039;&#039;). Defaults to {{Path|/mnt}}.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MBR&amp;lt;/code&amp;gt;&lt;br /&gt;
:Path of MBR binary code, defaults to {{Path|/usr/share/syslinux/mbr.bin}}.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;BOOTLOADER&amp;lt;/code&amp;gt;&lt;br /&gt;
:Bootloader to use, defaults to syslinux. Supported bootloaders are: grub syslinux zipl.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;DISKLABEL&amp;lt;/code&amp;gt;&lt;br /&gt;
:Disklabel to use, defaults to dos. Supported disklabels are: dos gpt eckd.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Writes to /tmp/ovlfiles, /tmp/alpine-install-diskmode.out, and /tmp/sfdisk.out but that never seems to be used elsewhere. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Partitioning ===&lt;br /&gt;
&lt;br /&gt;
If you have complex partitioning needs, that go beyond above alpine-disk options, you can partition, format, and mount your volumes manually, and then just supply the root mountpoint to &amp;lt;code&amp;gt;setup-disk&amp;lt;/code&amp;gt;. Doing so implicitly behaves as though &#039;&#039;&#039;-m sys&#039;&#039;&#039; had also been specified.&lt;br /&gt;
&lt;br /&gt;
See [[Setting up disks manually]] for more information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== RAID ====&lt;br /&gt;
&amp;lt;code&amp;gt;setup-disk&amp;lt;/code&amp;gt; will automatically build a RAID array if you supply the &#039;&#039;&#039;-r&#039;&#039;&#039; switch, or if you specify more than one device. The array will always be [https://en.m.wikipedia.org/wiki/Standard_RAID_levels#RAID_1 RAID1] (and [https://raid.wiki.kernel.org/index.php/RAID_superblock_formats#The_version-0.90_Superblock_Format --metadata=0.90]) for the /boot volumes, but will be [https://en.m.wikipedia.org/wiki/Standard_RAID_levels#RAID_5 RAID5] (and [https://raid.wiki.kernel.org/index.php/RAID_superblock_formats#The_version-1_Superblock_Format --metadata=1.2] for non-boot volumes when 3 or more devices are supplied.&lt;br /&gt;
&lt;br /&gt;
If you instead want to build your RAID array manually, see [[Setting up a software RAID array]]. Then format and mount the disks, and supply the root mountpoint to &amp;lt;code&amp;gt;setup-disk&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== LVM ====&lt;br /&gt;
&amp;lt;code&amp;gt;setup-disk&amp;lt;/code&amp;gt; will automatically build and use volumes in a LVM group if you supply the &#039;&#039;&#039;-L&#039;&#039;&#039; switch. The group and volumes created by the script will have the following names:&lt;br /&gt;
&lt;br /&gt;
* volume group: &#039;&#039;&#039;vg0&#039;&#039;&#039;&lt;br /&gt;
* swap volume: &#039;&#039;&#039;lv_swap&#039;&#039;&#039; (only created when swap size &amp;gt; 0)&lt;br /&gt;
* root volume: &#039;&#039;&#039;lv_root&#039;&#039;&#039; (only created when &#039;&#039;&#039;-m sys&#039;&#039;&#039; is specified or interactively selected)&lt;br /&gt;
* var volume: &#039;&#039;&#039;lv_var&#039;&#039;&#039; (only created when &#039;&#039;&#039;-m data&#039;&#039;&#039; is specified or interactively selected)&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;lv_var&#039;&#039;&#039; or &#039;&#039;&#039;lv_root&#039;&#039;&#039; volumes are created to occupy all remaining space in the volume group.&lt;br /&gt;
&lt;br /&gt;
If you need to change any of these settings, you can use &amp;lt;code&amp;gt;vgrename&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lvrename&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lvreduce&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;lvresize&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you instead want to build your LVM system manually, see [[Setting up Logical Volumes with LVM]]. Then format and mount the disks, and supply the root mountpoint to &amp;lt;code&amp;gt;setup-disk&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
=Setup-Disk Usage=&lt;br /&gt;
&lt;br /&gt;
usage: setup-disk [-hqr] [-k kernelflavor] [-m MODE] [-o apkovl] [-s SWAPSIZE]&lt;br /&gt;
		  [MOUNTPOINT | DISKDEV...]&lt;br /&gt;
&lt;br /&gt;
Install alpine on harddisk.&lt;br /&gt;
&lt;br /&gt;
If MOUNTPOINT is specified, then do a traditional disk install with MOUNTPOINT&lt;br /&gt;
as root.&lt;br /&gt;
&lt;br /&gt;
If DISKDEV is specified, then use the specified disk(s) without asking. If&lt;br /&gt;
multiple disks are specified then set them up in a RAID array. If there are&lt;br /&gt;
mode than 2 disks, then use raid level 5 instead of raid level 1.&lt;br /&gt;
&lt;br /&gt;
options:&lt;br /&gt;
 -h  Show this help&lt;br /&gt;
 -m  Use disk for MODE without asking, where MODE is either &#039;data&#039; or &#039;root&#039;&lt;br /&gt;
 -o  Restore system from given apkovl file&lt;br /&gt;
 -k  Use kernelflavor instead of $KERNEL_FLAVOR&lt;br /&gt;
 -L  Use LVM to manage partitions&lt;br /&gt;
 -q  Exit quietly if no disks are found&lt;br /&gt;
 -r  Enable software RAID1 with single disk&lt;br /&gt;
 -s  Use SWAPSIZE MB instead of $SWAP_SIZE MB for swap (Use 0 to disable swap)&lt;br /&gt;
 -v  Be more verbose about what is happening&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Disk Install Styles==&lt;br /&gt;
&lt;br /&gt;
You can select between &#039;sys&#039; or &#039;data&#039;.&lt;br /&gt;
&lt;br /&gt;
sys:&lt;br /&gt;
  This mode is a traditional disk install. The following partitions will be&lt;br /&gt;
  created on the disk: /boot, / (filesystem root) and swap.&lt;br /&gt;
    &lt;br /&gt;
  This mode may be used for development boxes, desktops, virtual servers, etc.&lt;br /&gt;
&lt;br /&gt;
data:&lt;br /&gt;
  This mode uses your disk(s) for data storage, not for the operating system.&lt;br /&gt;
  The system itself will run from tmpfs (RAM).&lt;br /&gt;
&lt;br /&gt;
  Use this mode if you only want to use the disk(s) for a mailspool, databases,&lt;br /&gt;
  logs, etc.&lt;br /&gt;
&lt;br /&gt;
none:&lt;br /&gt;
  Run without installing to disk.&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-lbu ==&lt;br /&gt;
&lt;br /&gt;
This script will only be invoked for by &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; when installing &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; installation types (ramdisk)&lt;br /&gt;
&lt;br /&gt;
It configures where &amp;lt;code&amp;gt;lbu commit&amp;lt;/code&amp;gt; will store the .apkovl backup. See [[Alpine local backup]] for more information.&lt;br /&gt;
&lt;br /&gt;
When started, &amp;lt;code&amp;gt;setup-lbu&amp;lt;/code&amp;gt; will prompt where to store your data. The options it will prompt for will be taken from the directories found in &amp;lt;code&amp;gt;/media&amp;lt;/code&amp;gt; (except for &amp;lt;code&amp;gt;cdrom&amp;lt;/code&amp;gt;). [not sure how these are mounted: are they automatically mounted by setup-lbu? Does the user have to manually mount using another tty?]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-apkcache ==&lt;br /&gt;
&lt;br /&gt;
This script will only be invoked for by &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; when installing &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; installation types (ramdisk)&lt;br /&gt;
&lt;br /&gt;
It configures where to save the apk package files. The apkcache is where apk stores downloaded packages, such that the system does not need to download them again on each reboot, and doesn&#039;t have to depend on the network. See [[Local APK cache]] for a detailed explanation.&lt;br /&gt;
&lt;br /&gt;
You should be able to use a partition that you set up in the previous steps.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-bootable ==&lt;br /&gt;
This is a standalone script; it&#039;s not invoked by &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; but must be run manually.&lt;br /&gt;
&lt;br /&gt;
It allows to create boot media that boots the system running from RAM memory (diskless) like the installation images, but using a writable (i.e. not iso9660) filesystem. So that it can also serve to store local customizations (e.g. apkovl files and cached packages). &lt;br /&gt;
&lt;br /&gt;
First, the script copies files from an ISO image (as file on a CD/DVD/USB etc.) onto a USB-Stick/CompactFlash/SDCard etc., or harddisk partition. And then, it installs the syslinux bootloader to make the device bootable.&lt;br /&gt;
&lt;br /&gt;
However, its current syslinux installation seems to fail on non-FAT32 partitions. So in these cases, you may start over with a FAT32 filesystem, or rather with the desired filesystem and using &amp;lt;code&amp;gt;setup-bootable&amp;lt;/code&amp;gt; only with the &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt; option, to skip the syslinux install, and then refer to the [[Create_a_Bootable_Device#Manually_copying_Alpine_files|manual method]] to fix the problem, or use one of the other bootloader options, instead.&lt;br /&gt;
&lt;br /&gt;
{{Tip| The [[Bootloaders]] page shows different ways to setup booting, and multi-boot menus!}}  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The setup-bootable script accepts the following arguments and command-line switches (you can run &amp;lt;code&amp;gt;setup-bootable -h&amp;lt;/code&amp;gt; to see a usage message).&lt;br /&gt;
&lt;br /&gt;
{{Cmd|setup-bootable &amp;lt;var&amp;gt;source&amp;lt;/var&amp;gt; [&amp;lt;var&amp;gt;dest&amp;lt;/var&amp;gt;]}}&lt;br /&gt;
&lt;br /&gt;
The argument &amp;lt;var&amp;gt;source&amp;lt;/var&amp;gt; can be a directory or an ISO (will be mounted to &amp;lt;code&amp;gt;MNT&amp;lt;/code&amp;gt; or {{Path|/mnt}}) or a URL (will be downloaded with &amp;lt;code&amp;gt;WGET&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;wget&amp;lt;/code&amp;gt;). The argument &amp;lt;var&amp;gt;dest&amp;lt;/var&amp;gt; can be a directory mountpoint, or will default to {{Path|/media/usb}} if not supplied.&lt;br /&gt;
&lt;br /&gt;
{{Define|-k|Keep alpine_dev in {{Path|syslinux.cfg}}; otherwise, replace with UUID.}}&lt;br /&gt;
{{Define|-u|Upgrade mode: keep existing {{Path|syslinux.cfg}} and don&#039;t run &amp;lt;code&amp;gt;syslinux&amp;lt;/code&amp;gt;}}&lt;br /&gt;
{{Define|-f|Overwrite {{Path|syslinux.cfg}} even if &#039;&#039;&#039;-u&#039;&#039;&#039; was specified.}}&lt;br /&gt;
{{Define|-s|Force the running of &amp;lt;code&amp;gt;syslinux&amp;lt;/code&amp;gt; even if &#039;&#039;&#039;-u&#039;&#039;&#039; was specified.}}&lt;br /&gt;
{{Define|-v|Verbose mode}}&lt;br /&gt;
&lt;br /&gt;
The script will ensure that &amp;lt;var&amp;gt;source&amp;lt;/var&amp;gt; and &amp;lt;var&amp;gt;dest&amp;lt;/var&amp;gt; are available; will copy the contents of &amp;lt;var&amp;gt;source&amp;lt;/var&amp;gt; to &amp;lt;var&amp;gt;dest&amp;lt;/var&amp;gt;, ensuring first that there&#039;s enough space; and unless &#039;&#039;&#039;-u&#039;&#039;&#039; was specified, will make &amp;lt;var&amp;gt;dest&amp;lt;/var&amp;gt; bootable.&lt;br /&gt;
&lt;br /&gt;
Suppose the target device is /dev/sdXY, then this partition can be prepared for booting with&lt;br /&gt;
{{Cmd|# setup-bootable -v /media/&amp;lt;installation-media-device&amp;gt; /dev/sdXY&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
For the manual way to set up boot media see [[Create_a_Bootable_Device#Manually_copying_Alpine_files|Manually_copying_Alpine_files]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== setup-xorg-base ==&lt;br /&gt;
&lt;br /&gt;
This is a standalone script; it&#039;s not invoked by &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; but must be run manually.&lt;br /&gt;
&lt;br /&gt;
It configures a graphical environment, installing basic Xorg packages and udev (replacing mdev), and is also required for Wayland sessions.&lt;br /&gt;
&lt;br /&gt;
The script installs, among other packages, e.g.: &amp;lt;code&amp;gt;xorg-server xf86-input-libinput xinit udev&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Additional packages to install may be supplied as arguments.&lt;br /&gt;
{{cmd|setup-xorg-base [additional package(s) to install]}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Video packages (optional) ====&lt;br /&gt;
&lt;br /&gt;
You may install specific xf86 xorg driver packages for your video card&#039;s chipset, as they may support specific features, effects and acceleration modes, and avoid error messages during X initialization.&lt;br /&gt;
&lt;br /&gt;
However, the most basic X features should work fine with just using the default kernel video-modesetting drivers.&lt;br /&gt;
&lt;br /&gt;
Info about the particular video cards that are installed in the computer may be found in the list of PCI devices:&lt;br /&gt;
{{cmd|# apk add pciutils&lt;br /&gt;
$ lspci}}&lt;br /&gt;
&lt;br /&gt;
To see available video driver packages run:&lt;br /&gt;
{{cmd|$ apk search xf86-video}}&lt;br /&gt;
&lt;br /&gt;
For example, &lt;br /&gt;
* For an Sis video chipset install &#039;xf86-video-sis&#039;.&lt;br /&gt;
{{Cmd|# apk add xf86-video-sis}}&lt;br /&gt;
&lt;br /&gt;
Others:&lt;br /&gt;
* For Intel video chipsets install &#039;xf86-video-intel&#039; and see [[Intel Video]].&lt;br /&gt;
{{Tip|In some cases, freezes on suspend/resume stop happening when changing the video port the monitor is connected to.}}&lt;br /&gt;
* For AMD Radeon Video see [[Radeon_Video]]&lt;br /&gt;
* For Alix1D use xf86-video-geode.&lt;br /&gt;
* In KVM/QEMU guests see [[QEMU#Using_Xorg_inside_Qemu|Xorg within KVM/QEMU]]&lt;br /&gt;
* In VirtualBox guests use xf86-video-vboxvideo, and install the [[VirtualBox_guest_additions|VirtualBox guest additions]] as well. They contain important parts for the driver.&lt;br /&gt;
* In VMware guests use xf86-video-vmware&lt;br /&gt;
* In Hyper-V guests use xf86-video-fbdev and install the [[Hyper-V_guest_services|Hyper-V guest services]] as well.&lt;br /&gt;
&lt;br /&gt;
==== Input packages ====&lt;br /&gt;
&lt;br /&gt;
If the &amp;lt;b&amp;gt;Numlock&amp;lt;/b&amp;gt; settings are not working, or getting &amp;lt;b&amp;gt;&#039;setleds not found&#039;&amp;lt;/b&amp;gt; errors:&lt;br /&gt;
&lt;br /&gt;
{{cmd|# apk add kbd}}&lt;br /&gt;
&lt;br /&gt;
If some input device is not working at all, the available xf86-input drivers can be listed with:&lt;br /&gt;
{{cmd|$ apk search xf86-input}}&lt;br /&gt;
&lt;br /&gt;
Typical legacy drivers:&lt;br /&gt;
&lt;br /&gt;
{{cmd|# apk add xf86-input-mouse xf86-input-keyboard}}&lt;br /&gt;
&lt;br /&gt;
And for touchpad tapping support on many laptops, also:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|# apk add xf86-input-synaptics}}&lt;br /&gt;
&lt;br /&gt;
==== Configure xorg-server (optional) ====&lt;br /&gt;
&lt;br /&gt;
On most systems, xorg should be able to autodetect all devices. However you can still configure xorg-server by hand by launching:&lt;br /&gt;
{{Cmd|# Xorg -configure}}&lt;br /&gt;
This will create a `/root/xorg.conf.new` file. You can modify this file to fit your needs.&amp;lt;BR&amp;gt;&lt;br /&gt;
(When finished modifying and testing the above configuration file, move it to `/etc/X11/xorg.conf` for normal usage.)&lt;br /&gt;
&lt;br /&gt;
==== Keyboard Layout (optional) ====&lt;br /&gt;
&lt;br /&gt;
If you use a keyboard layout different than &amp;quot;us&amp;quot;, and you are using a window manager or desktop environment that does not support to configure the keyboard layout itself, then you need to&lt;br /&gt;
&lt;br /&gt;
* [[Enable_Community_Repository#Using_community_repositories|Enable the &amp;quot;community&amp;quot; repository]]&lt;br /&gt;
&lt;br /&gt;
and install setxkbmap:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|# apk add setxkbmap}}&lt;br /&gt;
&lt;br /&gt;
Then try&lt;br /&gt;
 # setxkbmap &amp;lt;%a language layout from /usr/share/X11/xkb/rules/xorg.lst%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In order to make it persistent add this section to /etc/X11/xorg.conf:&lt;br /&gt;
{{Cmd|Section &amp;quot;InputClass&amp;quot;&lt;br /&gt;
	Identifier	&amp;quot;Keyboard Default&amp;quot;&lt;br /&gt;
	MatchIsKeyboard	&amp;quot;yes&amp;quot;&lt;br /&gt;
	Option		&amp;quot;XkbLayout&amp;quot; &amp;quot;&amp;lt;%a language layout from /usr/share/X11/xkb/rules/xorg.lst%&amp;gt;&amp;quot;&lt;br /&gt;
EndSection&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Another way to change the keymap when logging into X is to use ~/.xinitrc.  The following example loads a British keymap, simply add this line to the beginning of the file:&lt;br /&gt;
&amp;lt;code&amp;gt;setxkbmap gb &amp;amp;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you need to create the ~/.xinitrc file, you may also want to add a second line like &amp;lt;code&amp;gt;exec openbox-session&amp;lt;/code&amp;gt; to still start the window manager with &amp;lt;code&amp;gt;startx&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;xinit&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Documentation needed ==&lt;br /&gt;
&lt;br /&gt;
=== setup-xen-dom0 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== setup-mta ===&lt;br /&gt;
Uses ssmtp.&lt;br /&gt;
&lt;br /&gt;
This is a standalone script; it&#039;s not invoked by &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; but must be run manually.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== setup-acf ===&lt;br /&gt;
This is a standalone script; it&#039;s not invoked by &amp;lt;code&amp;gt;setup-alpine&amp;lt;/code&amp;gt; but must be run manually.&lt;br /&gt;
&lt;br /&gt;
This script was named &amp;lt;code&amp;gt;setup-webconf&amp;lt;/code&amp;gt; before Alpine 1.9 beta 4.&lt;br /&gt;
&lt;br /&gt;
See [[:Category:ACF|ACF pages]] for more information.&lt;br /&gt;
&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Installation]]&lt;br /&gt;
* [[Alpine newbie]]&lt;br /&gt;
* [[Post installation]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Installation]]&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Filesystems&amp;diff=21193</id>
		<title>Filesystems</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Filesystems&amp;diff=21193"/>
		<updated>2021-12-31T14:18:31Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: /* Install */ Add BTRFS reference&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Documentation how to use the Alpine distro to format HD/Floppy/Other.&lt;br /&gt;
&lt;br /&gt;
= Install =&lt;br /&gt;
Alpine has multiple storage media formatting packages available. Different packages/programs are used to format different types of filesystems.&lt;br /&gt;
* {{Pkg|btrfs-progs}} - For [[BTRFS]]&lt;br /&gt;
* {{Pkg|dosfstools}} - For FAT12/FAT16/FAT32&lt;br /&gt;
* {{Pkg|e2fsprogs}} - For ext3/ext4&lt;br /&gt;
* {{Pkg|f2fs-tools}} - For F2FS&lt;br /&gt;
* {{Pkg|jfsutils}} - For JFS&lt;br /&gt;
* {{Pkg|ntfs-3g}} - For NTFS (Note: ntfs-3g is a FUSE driver)&lt;br /&gt;
* {{Pkg|xfsprogs}} - For XFS&lt;br /&gt;
&lt;br /&gt;
= Format =&lt;br /&gt;
Here are some examples on how to use the formatting tools:&lt;br /&gt;
&lt;br /&gt;
{{Note|&#039;&#039;&#039;/dev/sda1&#039;&#039;&#039; is used as a example}}&lt;br /&gt;
&lt;br /&gt;
==== btrfs-progs ====&lt;br /&gt;
{{Cmd|# mkfs.btrfs /dev/sda1}}&lt;br /&gt;
&lt;br /&gt;
==== dosfstools ====&lt;br /&gt;
{{Cmd|# mkfs.vfat /dev/sda1}}&lt;br /&gt;
&lt;br /&gt;
==== e2fsprogs ====&lt;br /&gt;
{{Cmd|# mkfs.ext2 /dev/sda1}}&lt;br /&gt;
{{Cmd|# mkfs.ext3 /dev/sda1}}&lt;br /&gt;
{{Cmd|# mkfs.ext4 /dev/sda1}}&lt;br /&gt;
&lt;br /&gt;
==== f2fs-tools ====&lt;br /&gt;
&lt;br /&gt;
{{Cmd|# mkfs.f2fs /dev/sda1}}&lt;br /&gt;
&lt;br /&gt;
= Partitions =&lt;br /&gt;
If you need to change or make a partition table on a Hard Drive you want to format, you can use:&lt;br /&gt;
&lt;br /&gt;
==== fdisk ====&lt;br /&gt;
{{Cmd|# fdisk /dev/sda}}&lt;br /&gt;
&lt;br /&gt;
==== cfdisk ====&lt;br /&gt;
{{Cmd|# cfdisk /dev/sda}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Storage]]&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Alpine_Package_Keeper&amp;diff=21192</id>
		<title>Alpine Package Keeper</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Alpine_Package_Keeper&amp;diff=21192"/>
		<updated>2021-12-31T14:17:51Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: Add reference to BTRFS page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--For searching: apk, APK--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{TOC right}}&lt;br /&gt;
&lt;br /&gt;
Because Alpine Linux is designed to run from RAM, package management involves two phases:&lt;br /&gt;
* Installing / Upgrading / Deleting packages on a running system.&lt;br /&gt;
* Restoring a system to a previously configured state (e.g. after reboot), including all previously installed packages and locally modified configuration files. &#039;&#039;&#039;(RAM-Based Installs Only)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;apk&#039;&#039;&#039; is the tool used to install, upgrade, or delete software on a running system.&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;lbu&#039;&#039;&#039; is the tool used to capture the data necessary to restore a system to a previously configured state.&lt;br /&gt;
&lt;br /&gt;
This page documents the [https://git.alpinelinux.org/apk-tools/ apk tool] - See the [[Alpine_local_backup|Alpine Local Backup page]] for the lbu tool.&lt;br /&gt;
&lt;br /&gt;
= Overview =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;apk&#039;&#039;&#039; tool supports the following operations:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
| [[#Add a Package|add]] &lt;br /&gt;
| Add new packages or upgrade packages to the running system&lt;br /&gt;
|-&lt;br /&gt;
| [[#Remove a Package|del]]&lt;br /&gt;
| Delete packages from the running system&lt;br /&gt;
|-&lt;br /&gt;
| fix &lt;br /&gt;
| Attempt to repair or upgrade an installed package &lt;br /&gt;
|-&lt;br /&gt;
| [[#Update the Package list|update]] &lt;br /&gt;
| Update the index of available packages&lt;br /&gt;
|-&lt;br /&gt;
| [[#Information on Packages|info]]&lt;br /&gt;
| Prints information about installed or available packages&lt;br /&gt;
|-&lt;br /&gt;
| [[#Search for Packages|search]] &lt;br /&gt;
| Search for packages or descriptions with wildcard patterns&lt;br /&gt;
|-&lt;br /&gt;
| [[#Upgrade a Running System|upgrade]]&lt;br /&gt;
| Upgrade the currently installed packages&lt;br /&gt;
|-&lt;br /&gt;
| [[#Cache maintenance|cache]]&lt;br /&gt;
| Maintenance operations for locally cached package repository&lt;br /&gt;
|-&lt;br /&gt;
| version &lt;br /&gt;
| Compare version differences between installed and available packages&lt;br /&gt;
|-&lt;br /&gt;
| index &lt;br /&gt;
| create a repository index from a list of packages&lt;br /&gt;
|-&lt;br /&gt;
| fetch &lt;br /&gt;
| download (but not install) packages&lt;br /&gt;
|-&lt;br /&gt;
| audit &lt;br /&gt;
| List changes to the file system from pristine package install state&lt;br /&gt;
|-&lt;br /&gt;
| verify &lt;br /&gt;
| Verify a package signature&lt;br /&gt;
|- &lt;br /&gt;
| dot&lt;br /&gt;
| Create a [http://graphviz.org/ graphviz] graph description for a given package&lt;br /&gt;
|- &lt;br /&gt;
| [[#apk_policy|policy]]&lt;br /&gt;
| Display the repository that updates a given package, plus repositories that also offer the package&lt;br /&gt;
|- &lt;br /&gt;
| stats &lt;br /&gt;
| Display statistics, including number of packages installed and available, number of directories and files, etc.&lt;br /&gt;
|- &lt;br /&gt;
| manifest&lt;br /&gt;
| Display checksums for files contained in a given package&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Packages and Repositories =&lt;br /&gt;
&lt;br /&gt;
Software packages for Alpine Linux are digitally signed tar.gz archives containing programs, configuration files, and dependency metadata. They have the extension &amp;lt;code&amp;gt;.apk&amp;lt;/code&amp;gt;, and are often called &amp;quot;a-packs&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The packages are stored in one or more &#039;&#039;repositories&#039;&#039;. A repository is simply a directory with a collection of *.apk files.  The directory must include a special index file, named {{Path|APKINDEX.tar.gz}} to be considered a repository.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;apk&#039;&#039;&#039; utility can install packages from multiple repositories.  The list of repositories to check is stored in {{Path|/etc/apk/repositories}}, one repository per line. If you booted from a USB stick ({{Path|/media/sda1}}) or CD-ROM ({{Path|/media/cdrom}}), your repository file probably looks something like this:&lt;br /&gt;
&lt;br /&gt;
{{Cat|/etc/apk/repositories|/media/sda1/apks/}}&lt;br /&gt;
&lt;br /&gt;
In addition to local repositories, the &#039;&#039;&#039;apk&#039;&#039;&#039; utility uses &#039;&#039;&#039;busybox wget&#039;&#039;&#039; to fetch packages using &#039;&#039;http:&#039;&#039;, &#039;&#039;https:&#039;&#039; or &#039;&#039;ftp:&#039;&#039; protocols. The following is a valid repository file:&lt;br /&gt;
&lt;br /&gt;
{{Cat|/etc/apk/repositories|&lt;br /&gt;
/media/sda1/apks&lt;br /&gt;
http://dl-3.alpinelinux.org/alpine/v2.6/main&lt;br /&gt;
https://dl-3.alpinelinux.org/alpine/v2.6/main&lt;br /&gt;
ftp://dl-3.alpinelinux.org/alpine/v2.6/main&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Note|  A list of public repositories is in [https://mirrors.alpinelinux.org/ mirrors.alpinelinux.org].  Accepted protocols vary.}}&lt;br /&gt;
&lt;br /&gt;
== Repository pinning ==&lt;br /&gt;
&lt;br /&gt;
You can specify additional &amp;quot;tagged&amp;quot; repositories in {{Path|/etc/apk/repositories}}:&lt;br /&gt;
&lt;br /&gt;
{{Cat|/etc/apk/repositories|&lt;br /&gt;
http://nl.alpinelinux.org/alpine/v3.7/main&lt;br /&gt;
http://nl.alpinelinux.org/alpine/v3.7/community&lt;br /&gt;
@edge http://nl.alpinelinux.org/alpine/edge/main&lt;br /&gt;
@edgecommunity http://nl.alpinelinux.org/alpine/edge/community&lt;br /&gt;
@testing http://nl.alpinelinux.org/alpine/edge/testing&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
After which you can &amp;quot;pin&amp;quot; dependencies to these tags using:&lt;br /&gt;
&lt;br /&gt;
{{cmd|apk add stableapp newapp@edge bleedingapp@testing}}&lt;br /&gt;
&lt;br /&gt;
Apk will now by default only use the untagged repositories, but adding a tag to specific package:&lt;br /&gt;
&lt;br /&gt;
1. will prefer the repository with that tag for the named package, even if a later version of the package is available in another repository&lt;br /&gt;
&lt;br /&gt;
2. &#039;&#039;allows&#039;&#039; pulling in dependencies for the tagged package from the tagged repository (though it &#039;&#039;prefers&#039;&#039; to use untagged repositories to satisfy dependencies if possible)&lt;br /&gt;
&lt;br /&gt;
== Commandline repository options ==&lt;br /&gt;
&lt;br /&gt;
By default, the &#039;&#039;&#039;apk&#039;&#039;&#039; utility will use the system repositories for all operations. This behavior can be overridden by the following options:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
| --repositories-file REPOFILE&lt;br /&gt;
| Override the system repositories by specifying a repositories file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;-X|--repository REPO&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| Specify a supplemental repository that will be used in addition to the system repositories. This option can be provided multiple times.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Update the Package list =&lt;br /&gt;
&lt;br /&gt;
Remote repositories change as packages are added and upgraded.   To get the latest list of available packages, use the &#039;&#039;update&#039;&#039; command.  The command downloads the {{Path|APKINDEX.tar.gz}} from each repository and stores it in the local cache, typically {{Path|/var/cache/apk/}}, {{Path|/var/lib/apk/}} or {{Path|/etc/apk/cache/}}.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk update}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
fetch http://dl-3.alpinelinux.org/alpine/v2.1/main/APKINDEX.tar.gz&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Adding the &amp;lt;code&amp;gt;--update-cache&amp;lt;/code&amp;gt;, or for short &amp;lt;code&amp;gt;-U&amp;lt;/code&amp;gt; switch to another apk command, as in &amp;lt;code&amp;gt;apk --update-cache upgrade&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;apk -U add ...&amp;lt;/code&amp;gt;, the command has the same effect as first running &amp;lt;code&amp;gt;apk update&amp;lt;/code&amp;gt; before the other apk command.&lt;br /&gt;
&lt;br /&gt;
{{Tip|With remote repositories, it is a good idea to always do an &#039;&#039;&#039;update&#039;&#039;&#039; right &#039;&#039;&#039;before&#039;&#039;&#039; doing an &#039;&#039;&#039;upgrade or add&#039;&#039;&#039; command. That way the command will install the latest available packages.}}&lt;br /&gt;
&lt;br /&gt;
= Add a Package =&lt;br /&gt;
&lt;br /&gt;
Use &#039;&#039;&#039;add&#039;&#039;&#039; to install packages from a repository. Any necessary dependencies are also installed. If you have multiple repositories, the &#039;&#039;&#039;add&#039;&#039;&#039; command installs the newest package.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk add openssh&lt;br /&gt;
apk add openssh openntp vim}}&lt;br /&gt;
&lt;br /&gt;
If you only have the main repository enabled in your configuration, apk will not include packages from the other repositories. To install a package from the edge/testing repository without changing your repository configuration file, use the command below. This will tell apk to use that particular repository.&lt;br /&gt;
&lt;br /&gt;
{{cmd|apk add cherokee --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing/ --allow-untrusted}}&lt;br /&gt;
&lt;br /&gt;
{{Note|Be careful when using third-party or the testing repository. Your system can go down.}}&lt;br /&gt;
&lt;br /&gt;
= Add a local Package =&lt;br /&gt;
&lt;br /&gt;
To install a locally available apk package, for example if this device has no internet access but you can upload apk packages directly to it, use the &#039;&#039;&#039;--allow-untrusted&#039;&#039;&#039; flag:&lt;br /&gt;
&lt;br /&gt;
{{cmd|apk add --allow-untrusted /path/to/file.apk}}&lt;br /&gt;
&lt;br /&gt;
Note that multiple packages can be given.  When installing a local package, all dependencies should also be specified.  For example:&lt;br /&gt;
&lt;br /&gt;
{{cmd|apk add --allow-untrusted /var/tig-2.2-r0.apk /var/git-2.11.1-20.apk}}&lt;br /&gt;
&lt;br /&gt;
= Remove a Package  =&lt;br /&gt;
Use &#039;&#039;&#039;del&#039;&#039;&#039; to remove a package (and dependencies that are no longer needed.)  &lt;br /&gt;
&lt;br /&gt;
{{cmd|apk del openssh&lt;br /&gt;
apk del openssh openntp vim}}&lt;br /&gt;
&lt;br /&gt;
= Upgrade a Running System =&lt;br /&gt;
&lt;br /&gt;
=== Packages in general ===&lt;br /&gt;
&lt;br /&gt;
To get the latest security upgrades and bugfixes available for the &#039;&#039;installed&#039;&#039; packages of a running system, first &#039;&#039;&#039;update&#039;&#039;&#039; the list of available packages and then &#039;&#039;&#039;upgrade&#039;&#039;&#039; the installed packages:&lt;br /&gt;
&lt;br /&gt;
{{cmd|apk update&lt;br /&gt;
apk upgrade&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Or, combining the same into one single command:&lt;br /&gt;
&lt;br /&gt;
{{cmd|apk -U upgrade&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Here is an example, showing the procedure on a system that has several additional [[#Repository_pinning|repositories pinned]]:&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 fetch &amp;lt;nowiki&amp;gt;http://dl-3.alpinelinux.org/alpine/v3.6/main/x86_64/APKINDEX.tar.gz&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 fetch &amp;lt;nowiki&amp;gt;http://dl-3.alpinelinux.org/alpine/v3.6/community/x86_64/APKINDEX.tar.gz&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 fetch &amp;lt;nowiki&amp;gt;http://dl-3.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 fetch &amp;lt;nowiki&amp;gt;http://dl-3.alpinelinux.org/alpine/edge/community/x86_64/APKINDEX.tar.gz&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 fetch &amp;lt;nowiki&amp;gt;http://dl-3.alpinelinux.org/alpine/edge/testing/x86_64/APKINDEX.tar.gz&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 v3.6.2-191-gf98d79930f &amp;lt;nowiki&amp;gt;[http://dl-3.alpinelinux.org/alpine/v3.6/main]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 v3.6.2-190-ga5d68c47df &amp;lt;nowiki&amp;gt;[http://dl-3.alpinelinux.org/alpine/v3.6/community]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 v3.6.0-4618-g0bf77c9821 &amp;lt;nowiki&amp;gt;[http://dl-3.alpinelinux.org/alpine/edge/main]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 v3.6.0-4605-g85ed51dd83 &amp;lt;nowiki&amp;gt;[http://dl-3.alpinelinux.org/alpine/edge/community]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 v3.6.0-4624-g11f1b9c8ab &amp;lt;nowiki&amp;gt;[http://dl-3.alpinelinux.org/alpine/edge/testing]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 OK: 20118 distinct packages available&lt;br /&gt;
 &lt;br /&gt;
 # apk upgrade&lt;br /&gt;
 (1/2) Upgrading extra-cmake-modules@testing (5.38.0-r0 -&amp;gt; 5.39.0-r0)&lt;br /&gt;
 (2/2) Upgrading extra-cmake-modules-doc@testing (5.38.0-r0 -&amp;gt; 5.39.0-r0)&lt;br /&gt;
 Executing mdocml-apropos-1.14.1-r0.trigger&lt;br /&gt;
 OK: 2635 MiB in 803 packages&lt;br /&gt;
&lt;br /&gt;
To upgrade only &#039;&#039;specific&#039;&#039; packages, use the &#039;&#039;-u&#039;&#039; or &#039;&#039;--upgrade&#039;&#039; option of the &#039;&#039;&#039;add&#039;&#039;&#039; command:&lt;br /&gt;
&lt;br /&gt;
{{cmd|apk update&lt;br /&gt;
apk add --upgrade busybox &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To enable unattended, automatic upgrades of packages, see the {{pkg|apk-autoupdate}} package.&lt;br /&gt;
&lt;br /&gt;
To upgrade to a newer release, refer to the corresponding release notes and [[Upgrading_Alpine]].&lt;br /&gt;
&lt;br /&gt;
=== Upgrading &amp;quot;diskless&amp;quot; and &amp;quot;data&amp;quot; disk mode installs ===&lt;br /&gt;
&lt;br /&gt;
If booting a &amp;quot;diskless&amp;quot; system from a read-only device, or iso image on writable media, it&#039;s not possible to update the boot files (kernel, modules, firmware, ...) that reside on that device.&lt;br /&gt;
&lt;br /&gt;
It becomes possible to update the boot files, though, if using a boot device that is writable and has been prepared with &amp;lt;code&amp;gt;[[Alpine_setup_scripts#setup-bootable|setup-bootable]]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
However, even then, the kernel, with its modules and firmware files, can still not be updated directly through regular packages updates. Instead, there is the &amp;lt;code&amp;gt;update-kernel&amp;lt;/code&amp;gt; script that can generate initfs images and install them together with upgraded kernels.&lt;br /&gt;
&lt;br /&gt;
Upgrading can be done as follows.&lt;br /&gt;
{{cmd|apk add mkinitfs&lt;br /&gt;
}}&lt;br /&gt;
This package is required for the generation of the initial filesystem used during boot.&lt;br /&gt;
* Additional initfs features that are missing in the default configuration, like the [[BTRFS|btrfs]] filesystem support (at the time of writing, to allow loading .apkovl configs and package cache during boot), may be enabled in &amp;lt;code&amp;gt;/etc/mkinitfs/mkinitfs.conf&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Available initfs features may be listed with &amp;lt;code&amp;gt;ls /etc/mkinitfs/features.d&amp;lt;/code&amp;gt;&lt;br /&gt;
{{cmd|ls /etc/mkinitfs/features.d&lt;br /&gt;
apk add nano&lt;br /&gt;
nano /etc/mkinitfs/mkinitfs.conf&lt;br /&gt;
lbu commit&lt;br /&gt;
}}&lt;br /&gt;
Finally update the kernel and its boot environment.&lt;br /&gt;
{{cmd|update-kernel /media/sdXY/boot/&lt;br /&gt;
}}&lt;br /&gt;
* An &amp;lt;code&amp;gt;update-kernel&amp;lt;/code&amp;gt; run needs at least 8 GB free ram memory to avoid a broken modloop-image.&lt;br /&gt;
* See &amp;lt;code&amp;gt;update-kernel --help&amp;lt;/code&amp;gt; for options to manually add additional module or firmware packages.&lt;br /&gt;
&lt;br /&gt;
= Search for Packages =&lt;br /&gt;
The &#039;&#039;&#039;search&#039;&#039;&#039; command searches the repository Index files for installable packages. &lt;br /&gt;
&lt;br /&gt;
The return format is &#039;&#039;&#039;Package&#039;&#039;&#039;-&#039;&#039;&#039;Version&#039;&#039;&#039;. Omit &#039;&#039;&#039;Version&#039;&#039;&#039; for &#039;&#039;apk add &#039;&#039;&#039;Package&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
* To list all packages available, along with their descriptions: {{cmd|apk search -v}}&lt;br /&gt;
* To list all packages are part of the ACF system: {{cmd|apk search -v &#039;acf*&#039; }}&lt;br /&gt;
* To list all packages that list NTP as part of their description, use the &#039;&#039;-d&#039;&#039; or &#039;&#039;--description&#039;&#039; option: {{cmd|apk search -v --description &#039;NTP&#039; }}&lt;br /&gt;
&lt;br /&gt;
= Information on Packages =&lt;br /&gt;
&lt;br /&gt;
== apk info ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;info&#039;&#039;&#039; command provides information on the contents of packages, their dependencies, and which files belong to a package.&lt;br /&gt;
&lt;br /&gt;
For a given package, each element can be chosen (for example, &#039;&#039;-w&#039;&#039; to show just the webpage information), or all information displayed with the &#039;&#039;-a&#039;&#039; command.&lt;br /&gt;
&lt;br /&gt;
Example: {{cmd|apk info -a zlib}}&lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;zlib-1.2.5-r1 description:&#039;&#039;&#039;&lt;br /&gt;
 A compression/decompression Library&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;&#039;zlib-1.2.5-r1 webpage:&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;http://zlib.net&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;&#039;zlib-1.2.5-r1 installed size:&#039;&#039;&#039;&lt;br /&gt;
 94208&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;&#039;zlib-1.2.5-r1 depends on:&#039;&#039;&#039;&lt;br /&gt;
 libc0.9.32&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;&#039;zlib-1.2.5-r1 is required by:&#039;&#039;&#039;&lt;br /&gt;
 libcrypto1.0-1.0.0-r0&lt;br /&gt;
 apk-tools-2.0.2-r4&lt;br /&gt;
 openssh-client-5.4_p1-r2&lt;br /&gt;
 openssh-5.4_p1-r2&lt;br /&gt;
 libssl1.0-1.0.0-r0&lt;br /&gt;
 freeswitch-1.0.6-r6&lt;br /&gt;
 atop-1.25-r0 &lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;&#039;zlib-1.2.5-r1 contains:&#039;&#039;&#039;&lt;br /&gt;
 lib/libz.so.1.2.5&lt;br /&gt;
 lib/libz.so.1&lt;br /&gt;
 lib/libz.so &lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;&#039;zlib-1.2.5-r1 triggers:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
As shown in the example you can determine&lt;br /&gt;
* The &#039;&#039;&#039;description&#039;&#039;&#039; of the package (&#039;&#039;-d&#039;&#039; or &#039;&#039;--description&#039;&#039;)&lt;br /&gt;
* The &#039;&#039;&#039;webpage&#039;&#039;&#039; where the application is hosted (&#039;&#039;-w&#039;&#039; or &#039;&#039;--webpage&#039;&#039;)&lt;br /&gt;
* The &#039;&#039;&#039;size&#039;&#039;&#039; the package will require once installed (in bytes) (&#039;&#039;-s&#039;&#039; or &#039;&#039;--size&#039;&#039;)&lt;br /&gt;
* What packages are required to use this one  (&#039;&#039;&#039;depends&#039;&#039;&#039;) (&#039;&#039;-R&#039;&#039; or &#039;&#039;--depends&#039;&#039;)&lt;br /&gt;
* What packages require this one to be installed (&#039;&#039;&#039;required by&#039;&#039;&#039;) (&#039;&#039;-r&#039;&#039; or &#039;&#039;--rdepends&#039;&#039;)&lt;br /&gt;
* The &#039;&#039;&#039;contents&#039;&#039;&#039; of the package, that is, which files it installs (&#039;&#039;-L&#039;&#039; or &#039;&#039;--contents&#039;&#039;)&lt;br /&gt;
* Any &#039;&#039;&#039;triggers&#039;&#039;&#039; this package sets. (&#039;&#039;-t&#039;&#039; or &#039;&#039;--triggers&#039;&#039;) Listed here are directories that are watched; if a change happens to the directory, then the trigger script is run at the end of the apk add/delete. For example, doing a depmod once after installing all packages that add kernel modules.&lt;br /&gt;
&lt;br /&gt;
{{Tip|The &#039;&#039;&#039;info&#039;&#039;&#039; command is also useful to determine which package a file belongs to.  For example: {{cmd|apk info --who-owns /sbin/lbu}} will display&lt;br /&gt;
&lt;br /&gt;
 /sbin/lbu is owned by alpine-conf-x.x-rx&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Listing installed packages ===&lt;br /&gt;
&lt;br /&gt;
To list all installed packages, use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apk info&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To list all installed packages in alphabetical order, with a description of each, do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;apk -vv info|sort&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The apk tool does not have a subcommand to list manually-installed packages that do not have reverse dependencies. To get this information on a traditional system that is not using [[Alpine local backup|lbu]], try this script. Note that this approach will also list core packages like alpine-base that should not be removed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#!/bin/sh&lt;br /&gt;
apk info | grep -ve &#039;-doc$&#039; | sort | while read pkg&lt;br /&gt;
        do&lt;br /&gt;
                rdep=`apk info -qr &amp;quot;$pkg&amp;quot;`&lt;br /&gt;
                [ -z &amp;quot;$rdep&amp;quot; ] &amp;amp;&amp;amp; echo $pkg&lt;br /&gt;
        done&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== apk policy ==&lt;br /&gt;
&lt;br /&gt;
To display the repository a package was installed from and will be updated from, plus any [[#Repository_pinning|tagged]] or enabled repositories where it is also offered, if any, for this architecture - its &#039;&#039;&#039;policy&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
 apk policy &#039;&#039;package&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $ apk policy vlc&lt;br /&gt;
 vlc policy:&lt;br /&gt;
  2.2.6-r1:&lt;br /&gt;
    lib/apk/db/installed&lt;br /&gt;
    http://dl-3.alpinelinux.org/alpine/v3.7/community&lt;br /&gt;
  3.0.0_rc2-r1:&lt;br /&gt;
    @edgecommunity http://dl-3.alpinelinux.org/alpine/edge/community&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional apk Commands =&lt;br /&gt;
In progress...&lt;br /&gt;
&lt;br /&gt;
= Local Cache =&lt;br /&gt;
&lt;br /&gt;
{{:Local_APK_cache}}&lt;br /&gt;
&lt;br /&gt;
= Advanced APK Usage =&lt;br /&gt;
&lt;br /&gt;
== Holding a specific package back ==&lt;br /&gt;
&lt;br /&gt;
In certain cases, you may want to upgrade a system, but keep a specific package at a back level. It is possible to add &amp;quot;sticky&amp;quot; or versioned dependencies. For instance, to hold the &#039;&#039;asterisk&#039;&#039; package to the 1.6.2 level or lower:&lt;br /&gt;
{{cmd|1=apk add asterisk=1.6.0.21-r0}}&lt;br /&gt;
or&lt;br /&gt;
{{cmd|apk add &#039;asterisk&amp;lt;1.6.1&#039;}}&lt;br /&gt;
&lt;br /&gt;
after which a {{cmd|apk upgrade}}&lt;br /&gt;
&lt;br /&gt;
will upgrade the entire system, keeping the asterisk package at the 1.6.0 or lower level&lt;br /&gt;
&lt;br /&gt;
To later upgrade to the current version,&lt;br /&gt;
&lt;br /&gt;
{{cmd|apk add &#039;asterisk&amp;gt;1.6.1&#039;}}&lt;br /&gt;
&lt;br /&gt;
will ensure that 1.6.1 is the minimum version used.&lt;br /&gt;
&lt;br /&gt;
You can also use &amp;quot;fuzzy&amp;quot; version matching to pin the version to a major/minor release.  For example:&lt;br /&gt;
&lt;br /&gt;
{{cmd|1=apk add &#039;asterisk=~1.6&#039;}}&lt;br /&gt;
&lt;br /&gt;
will match any version of asterisk that starts with 1.6 (such as 1.6.0.21-r0 or 1.6.9.31-r9)  &amp;lt;ref&amp;gt;[https://git.alpinelinux.org/apk-tools/commit/?id=693b4bcdb0f22904a521a7c8ac4f13e697dc4d71 Alpine source commit message]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you desire deterministic, repeatable package installation (such as with containerized environments) via package pinning, it is important to understand your package repo&#039;s version retention rules.  For example, most Alpine package repos contain an &amp;quot;edge&amp;quot; branch, which may drop package versions that are not deemed fit to make it into a stable branch.  This means that pinning to a version on the edge branch may stop working after the package version is revoked from the repo.  Always pin to a package version that is intended for your current Alpine Linux version.&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;apk-tools is old&amp;quot; == &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;apk update&#039;&#039;&#039;, &#039;&#039;&#039;apk upgrade&#039;&#039;&#039; or &#039;&#039;&#039;apk add&#039;&#039;&#039; may report the following: &lt;br /&gt;
 WARNING: This apk-tools is OLD! Some packages might not function properly&lt;br /&gt;
&lt;br /&gt;
This may happen if you are running Alpine Linux stable version with a certain edge/main, edge/community or testing package(s) also installed.  One resolution is to consider upgrading {{pkg|apk-tools}}.  If edge is already [https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management#Repository_pinning tagged] in your repositories, then try:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo apk add --upgrade apk-tools@edge&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= External Links =&lt;br /&gt;
* [https://www.cyberciti.biz/faq/10-alpine-linux-apk-command-examples/ 10 Alpine Linux apk Command Examples]  Vivek Gite 2019&lt;br /&gt;
&lt;br /&gt;
[[Category:Package Manager]]&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Btrfs&amp;diff=21191</id>
		<title>Btrfs</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Btrfs&amp;diff=21191"/>
		<updated>2021-12-31T14:14:46Z</updated>

		<summary type="html">&lt;p&gt;Garritfra: Add BTRFS entry&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Documentation how to use BTRFS on Alpine Linux.&lt;br /&gt;
&lt;br /&gt;
== Install ==&lt;br /&gt;
&lt;br /&gt;
Installing [https://de.wikipedia.org/wiki/Btrfs BTRFS] is relatively straight forward. Install the package and tell Alpine to load the module on startup:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk add btrfs-progs&lt;br /&gt;
echo btrfs &amp;gt;&amp;gt; /etc/modules}}&lt;br /&gt;
&lt;br /&gt;
To load the module right away, you can use the following command:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|modprobe btrfs}}&lt;br /&gt;
&lt;br /&gt;
== Mounting a volume ==&lt;br /&gt;
&lt;br /&gt;
To mount a volume on boot, add a new entry to your fstab:&lt;br /&gt;
&lt;br /&gt;
 UUID=abcdef-0055-4958-990f-1413ed1186ec  /var/data  btrfs   defaults,nofail,subvol=@  0  0&lt;br /&gt;
&lt;br /&gt;
More information about mounting can be found in the official [https://btrfs.wiki.kernel.org/index.php/Main_Page BTRFS wiki]&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
=== Mount failed ===&lt;br /&gt;
&lt;br /&gt;
If you try mounting a btrfs volume via your /etc/fstab and it doesn&#039;t show up, it could be because BTRFS does not know about the drives during boot.&lt;br /&gt;
&lt;br /&gt;
To work around this, you can create an OpenRC service that runs a &#039;&#039;btrfs scan&#039;&#039; to detect the drives. To do so, create a new service under /etc/init.d/btrfs-scan with the following content:&lt;br /&gt;
&lt;br /&gt;
 #!/sbin/openrc-run&lt;br /&gt;
 &lt;br /&gt;
 name=&amp;quot;btrfs-scan&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 depend() {&lt;br /&gt;
   before localmount&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 start() {&lt;br /&gt;
   /sbin/btrfs device scan&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Make the service executable and register it:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|chmod +x /etc/init.d/btrfs-scan&lt;br /&gt;
rc-update add btrfs-scan boot&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
The volume should mount correctly after a reboot.&lt;br /&gt;
&lt;br /&gt;
== Other Resources ==&lt;br /&gt;
&lt;br /&gt;
# [https://garrit.xyz/posts/2021-12-31-btrfs-on-alpine BTRFS on Alpine Linux]&lt;br /&gt;
# [https://nparsons.uk/blog/using-btrfs-on-alpine-linux Using BTRFS on Alpine Linux]&lt;br /&gt;
# [https://gitlab-test.alpinelinux.org/alpine/aports/-/issues/9539 Can&#039;t mount BTRFS volume using fstab]&lt;/div&gt;</summary>
		<author><name>Garritfra</name></author>
	</entry>
</feed>