Project GDL system extensions, applied using systemd-sysext
- Throne VPN client
- AmneziaVPN client
- v2rayN client
- Cloudflare WARP client
GDL is an atomic distribution. The base image is immutable and updated as a whole via rpm-ostree/bootc. Rebuilding the entire image for every VPN client that only part of the userbase wants is a bad trade-off:
- it bloats the base image for everyone, including users who don't need proxy clients at all;
- a bug in a third-party client would require rebuilding and shipping the whole image instead of patching one component; users prefer different clients (Throne, Hiddify, their own sing-box configs), and we don't want to pick a winner for them.
systemd-sysext solves this without reinventing a package manager:
Extensions live in /var/lib/extensions/, which is a persistent partition that rpm-ostree/bootc never touches during base image updates.
At boot, systemd-sysext merges them on top of /usr via an overlayfs mount. An extension is just a squashfs image with the expected directory layout inside (see the UAPI Extension Image spec). ID=_any in extension-release decouples extension compatibility from the exact base image version, so you can update the client and the OS independently.
Why not Flatpak? Some clients (GUIs backed by a setuid core binary like ThroneCore, which needs CAP_NET_ADMIN on a real network interface) don't fit well inside the Flatpak sandbox. You either lack TUN access or end up with workarounds that defeat the point of sandboxing in the first place. Flatpak is still the right call wherever it fits; for proxy clients specifically, sysext gives us plain network access without fighting the runtime.
Why not just ship it in the base image? That forces picking one client for everyone, or bundling several: both conflict with keeping the base image minimal on an atomic distro.