Alexander Gromnitsky's Blog<br>:: 2026-05-28<br>:: Making Debian or Fedora persistent live images
Making Debian or Fedora persistent live images
Latest update: 2026-05-31 19:51:45
When you download a 'live' ISO, dd it to a USB drive, you notice that<br>all your tweaks or installed packages vanish after a reboot. If you<br>think about how most such 'live' ISOs work, it becomes apparent<br>why:
$ parted -s Fedora-Xfce-Live-44-1.7.x86_64.iso print free | grep '^[PN ]'<br>Partition Table: gpt<br>Number Start End Size File system Name Flags<br>1 32.8kB 2897MB 2897MB ISO9660 hidden, msftdata<br>2 2897MB 2929MB 31.5MB fat16 Appended2 boot, esp<br>2929MB 2929MB 512B Free Space
ISO9660 is a read-only filesystem, & the fact it was written onto a<br>writable medium is irrelevant: its fs driver contains no<br>implementation for writing data blocks, & the Linux VFS layer immediately<br>returns EROFS (code 30, Read-only file system) when it sees that a<br>fs was mounted read-only.
A common workaround is to use OverlayFS; in the case of 'live' ISOs, to<br>do an overlay with a chunk of RAM.
Obviously, you can do an overlay with a filesystem that supports write<br>operations instead, like ext4, but inside the Live ISO there isn't<br>one, & hence there is nothing to do an overlay with.
While you can always create an ext4 partition manually, how do you tell<br>the 'live' OS to use it during boot? This distro corner has no<br>standardisation whatsoever, & everybody is doing it in their own<br>unique way. E.g., Debian & Ubuntu have diverged so much throughout the<br>years that even the kernel parameters for their 'persistence'<br>implementations differ. While it may seem logical to an impartial<br>spectator to keep at least the user-facing interface the same between the<br>distros, it's not how it is done in practice.
Ubuntu
Kernel parameter: "persistent".
An (empty) partition must have the label "casper-rw".
What is annoying is that it's surprisingly non-obvious to detect<br>whether such a trick worked: if your partition is /dev/sda4, &<br>Ubuntu does not show it as mounted, & /cow is roughly the size of<br>/dev/sda4:
$ df -h | grep cow<br>/cow 9.8G 161M 9.2G 2% /
then persistence is on. If, on the other hand, you see this:
$ df -h | grep casper<br>/dev/disk/by-label/casper-rw 9.8G 161M 9.2G 2% /var/log
you most likely mistyped the word persistent.
The next issue is how to save grub parameters in the .iso. As it's<br>absolutely useless to mount it to modify files, you can either extract<br>everything from the .iso, edit what you want in grub.cfg, & recreate<br>the image, or, alternatively, do a simple 12-byte to 12-byte swap:
$ export LANG=C<br>$ sed -i 's/quiet splash/persistent /' xubuntu-26.04-desktop-amd64.iso
It's amusingly hacky, but works. If your replacement string is not equal<br>in length to the pattern, you'll corrupt the ISO9660 filesystem, &<br>grub will refuse to boot the kernel.
(See a github sample for a script that does all this; it assumes a<br>Linux host & injects an ext4 partition into a copy of an .iso. You can<br>always resize the partition (& its filesystem) in real time using the<br>Disks utility that the .iso ships with.)
Debian
Kernel parameter: "persistence".
A partition must have:<br>the label "persistence";
a file named persistence.conf in the root of the partition with<br>a line akin to "/ union".
Notice that it was "persistent " for Ubuntu, but it's<br>"persistence " for Debian. Why not.
The same mechanism of rude byte swapping in the .iso applies here<br>too:
$ export LANG=C<br>$ sed -i 's/splash quiet/persistence /' debian-live-13.5.0-amd64-xfce.iso
Detecting a successful overlay is easier:
$ mount | grep sda3<br>/dev/sda3 on /run/live/persistence/sda3 type ext4 (rw,noatime)<br>overlay on / type overlay (rw,noatime,lowerdir=/run/live/rootfs/filesystem.squashfs/,upperdir=/run/live/persistence/sda3/rw,workdir=/run/live/persistence/sda3/work,redirect_dir=on)
Fedora
Kernel parameters: "selinux=0 rd.live.overlay=LABEL=foo:/bar".
A partition must have:<br>a label "foo" (choose whatever you want, but it must correspond to<br>the value in the kernel parameter);
a "bar" directory (again, see the kernel parameter);
an "ovlwork" directory (this is a hardcoded name).
To check:
$ df -h | grep sdb1<br>/dev/sdb1 9.8G 134M 9.1G 2% /run/initramfs/overlayfs<br>$ mount | grep Live<br>LiveOS_rootfs on / type overlay (rw,relatime,lowerdir=/run/rootfsbase,upperdir=/run/overlayfs,workdir=/run/ovlwork)<br>$ file /run/overlayfs<br>/run/overlayfs: symbolic link to /run/initramfs/overlayfs/bar
In the case of Fedora, this is all mostly useless. Its 'linux' loader<br>command in grub.cfg menu entries contains no space to sacrifice for<br>a different 40-byte-long string. You, of course, can delete one menu<br>entry completely & substitute it with your own, but this would be<br>rather fragile: if, in the next version of Fedora, the size of<br>grub.cfg changes, your script will corrupt the underlying ISO9660<br>filesystem.
If the only reliable way here is to extract the rootfs from the .iso<br>to edit it, why bother with overlays then? This is what Fedora...