Using Fedora Silverblue for development

I recently switched to Fedora Silverblue for my development machine. I want to document approximately how I do this (and why it’s awesome!).

Fedora Silverblue

This article is not an introduction to Fedora Silverblue, but a short summary is well-placed: Fedora Silverblue is an immutable operating system that upgrades atomically. Effectively, the root filesystem is mounted read-only, with the exception of /var, /home, and /etc. The system is upgraded by mounting a new read-only snapshot as the root filesystem.

There are three methods of installing software on Fedora Silverblue:

  • Expanding the immutable base image using rpm-ostree. The base image is intended to be reserved for system components, but you can technically put anything in this image.

  • Installing graphical applications using Flatpak. This is sometimes-sandboxed, sometimes-not-so-sandboxed, but generally quite stable. If a layman were to install Fedora Silverblue, this would be the only installation method they would care about, aside from updating the base image when prompted.

  • Installing CLI tools using toolbox. This is a Podman (read: Docker) container of Fedora that mounts the user’s home directory. Because it’s a Podman image, you can install any RPM using Fedora’s package manager, DNF.

This article by Fedora Magazine goes into slightly more detail.

The basic development workflow

Instead of littering the base operating system with all means of development tools, development takes place within a toolbox. This looks a little like:

carmenbianca@thinkpad-x395 ~ $ ls
Elŝutoj  Labortablo  Nextcloud  Projektoj  Publike  Ŝablonoj
carmenbianca@thinkpad-x395 ~ $ toolbox create my-project
Created container: my-project
Enter with: toolbox enter my-project
carmenbianca@thinkpad-x395 ~ $ toolbox enter my-project
[carmenbianca@toolbox ~]$
[carmenbianca@toolbox ~]$ ls
Elŝutoj  Labortablo  Nextcloud  Projektoj  Publike  Ŝablonoj
[carmenbianca@toolbox ~]$ # We're still in the same directory, which means
[carmenbianca@toolbox ~]$ # that we still have our GPG and SSH keys, and
[carmenbianca@toolbox ~]$ # other configuration files!
[carmenbianca@toolbox ~]$
[carmenbianca@toolbox ~]$ sudo dnf groupinstall "Development Tools"
[...]

The nice thing now is that you now have full freedom to mess with absolutely anything, carefree. If your program touches some files in /etc, you can mess with those files without affecting your operating system. If you want to test your program against a custom-built glibc, you can simply do that without fear of breaking your computer. At worst you’ll break the toolbox, from which you can easily recover by recreating it. And if you need more isolation from e.g. your home directory, you can do that inside of a non-toolbox Podman container.

The editor problem

There is a slight problem with the above workflow, however. Unless you install your code editor inside of the toolbox, the editor has no access to the development tools you’ve installed. Instead, the editor only has access to the tools that are available in the base system image, or the editor only has access to the tools in its Flatpak runtime.

There are several ways to get around this, but they’re dependent on the editor you use. I’ll document how I circumvented this problem.

VSCodium in a Flatpak

I use the Flatpak version of VSCodium. VSCodium has an integrated terminal emulator. Unfortunately the Flatpak shell is rather extremely barebones—it doesn’t even have vi! Fortunately, we can tell VSCodium that we want to run a different program as our shell. Change settings.json to include:

  [...]
  "terminal.integrated.shell.linux": "/usr/bin/env",
  "terminal.integrated.shellArgs.linux": [
    "--",
    "flatpak-spawn",
    "--host",
    "toolbox",
    "enter",
    "main-toolbox"
  ],
  [...]

main-toolbox here is an all-purpose toolbox that has heaps of tools installed. You can adjust these settings on a per-workspace or per-project level, so a given project might use a different toolbox than main-toolbox.

The way the above command works is a little roundabout. It breaks out of the flatpak and into the base installation using flatpak-spawn --host, and then enters a toolbox using toolbox enter. The end result is that you have an integrated terminal with a functional and feature-plenty shell.

This doesn’t solve everything, however. The editor itself also has some integration such as running tests. Because I mainly do Python development, it is fairly easy to bootstrap this functionality. The Flatpak runtime ships with Python 3.8. This means that I can create a Python 3.8 virtualenv and tell VSCodium to use this virtualenv for all of its Python stuff, which ends up working out just fine. The virtualenv is shared between the Flatpak and the toolbox, because both environments have access to the same file system.


For non-Python endeavours, Flatpak SDK extensions can be installed. This looks a little like:

$ flatpak install flathub org.freedesktop.Sdk.Extension.dotnet
$ flatpak install flathub org.freedesktop.Sdk.Extension.golang
$ FLATPAK_ENABLE_SDK_EXT=dotnet,golang flatpak run com.vscodium.codium

The final problem I ran into was using VSCodium to edit my Git commit messages. VSCodium has a tiny box in the UI where you can write commit messages, but it’s rather tiny and fiddly and not great. So instead I do git config --global --add core.editor 'codium --wait'. This should launch codium --wait path/to/git/commit/message when git commit is run, allow VSCodium to edit the message, and wait until the file is saved and exited to evaluate the message.

The problem is that codium only exists as an executable inside of the Flatpak. It does not exist in the toolbox or the base operating system.

I circumvented this problem by creating a custom script in .local/bin/codium. It tries to detect its current environment by checking whether a certain file exists, and tries to use that environment’s method of accessing the VSCodium Flatpak. This looks like:

#!/bin/bash

# Will still need to pass "--wait" to make it behave nicely.
# In order to get --wait to work in a Flatpak, run
# `flatpak override --user --env=TMPDIR=/var/tmp com.vscodium.codium`.

if [ -f /app/bin/codium ]
then
    exec /app/bin/codium "$@"
elif [ -f /usr/bin/codium ]
then
    exec /usr/bin/codium "$@"
elif [ -f /usr/bin/flatpak-spawn ]
then
    exec /usr/bin/flatpak-spawn --host flatpak run com.vscodium.codium "$@"
elif [ -f /usr/bin/flatpak ]
then
    exec /usr/bin/flatpak run com.vscodium.codium "$@"
else
    for arg do
        shift
        [ "$arg" = "--wait" ] && continue
        set -- "$@" "$arg"
    done
    exec vi "$@"
fi

This allows you to run codium [--wait] from anywhere and expect a functional editor to pop up. There’s a fallback to vi, which I’ve not yet hit.

I hope this helps anybody looking for solutions to these problems :) It’s more than a little bit of bother, but it’s incredibly reassuring to know that your operating system won’t ever break on you.

See also