Files
main-desktop/README.md
T
2026-07-30 09:54:44 -04:00

9.5 KiB

main-desktop

Custom Bazzite DX image for my desktop, defined with BlueBuild. There is no published image — clone this repo and build it yourself; bluebuild switch rebases the running system straight onto the local build.

  • Base: ghcr.io/ublue-os/bazzite-dx-nvidia — Bazzite DX, KDE Plasma, NVIDIA open kernel modules. There is no separate -open DX image anymore: DX NVIDIA is open-driver-only, which is exactly what the RTX 5090 (Blackwell) requires. Current stable ships driver 610.x (open).
  • Pinned to Fedora 44 via image-version: stable-44 in recipes/recipe.yml. No surprise major upgrades; bump to stable-45 deliberately.
  • This image layers almost nothing. The base already includes Steam and the gaming stack, Flatpak, Docker CE + CLI, Podman, VS Code, Homebrew, and nvidia-container-toolkit with automatic CDI setup (ublue-nvctk-cdi.service regenerates /etc/cdi/nvidia.yaml each boot). What this recipe adds: a declarative first-boot Flatpak set (and a dormant signing policy). That's it — by design.

Why BlueBuild instead of a raw Containerfile: the whole custom layer is "install these Flatpaks on first boot", which the default-flatpaks module expresses declaratively — and bluebuild switch gives a one-command build-and-rebase with no registry involved.

Getting onto this image (fresh desktop rebuild)

  1. Install stock Bazzite DX (NVIDIA) from the official ISO at bazzite.gg and boot into it.

  2. Install the BlueBuild CLI and switch:

    git clone https://git.lazypugs.com/ckoch/main-desktop.git && cd main-desktop
    podman run --pull always --rm ghcr.io/blue-build/cli:latest-installer | bash
    bluebuild switch recipes/recipe.yml   # add --reboot to reboot when done
    

    switch builds the image locally, stores it as an oci-archive under /etc/bluebuild/, and rebases rpm-ostree onto it. First build pulls the multi-GB base — give it time and disk (~25 GB free).

  3. Reboot. Done — the first-boot service then installs the Flatpak list below (needs a few minutes on first login; check with flatpak list --system).

Alternatively, bluebuild generate-iso recipes/recipe.yml can produce installer media with the custom image baked in, skipping step 1's stock install.

Updating later (pulls the newest Bazzite stable-44 base plus any recipe changes):

cd main-desktop && git pull && bluebuild update recipes/recipe.yml --reboot

Roll back anytime with rpm-ostree rollback (or pick the previous deployment in the boot menu).

Note on signing: local oci-archive rebases are inherently unsigned (ostree-unverified-image), so cosign doesn't apply here. The recipe keeps the signing module and cosign.pub so that publishing signed images to a registry later is just a bluebuild build --push away.

Install-time checklist

  1. Driver sanity: nvidia-smi reports driver ≥ 580 (currently 610.x) and the RTX 5090 is listed. Confirm open kernel modules: modinfo -F license nvidia should say Dual MIT/GPL (the proprietary module says NVIDIA). Blackwell only works on the open modules.
  2. Deployment: rpm-ostree status shows the booted deployment is the local build (ostree-unverified-image:oci-archive:/etc/bluebuild/...) with the expected base version.
  3. Flatpaks: all installed (flatpak list --system — 22 apps from the list below). The first-boot install is sequential and multi-GB; on slow links it can take 15+ minutes after first login. Progress: journalctl -b --grep flatpak -f.
  4. Docker group: run ujust dx-group (adds you to docker and friends), then log out/in.
  5. GPU in containers: run the one-liner test in the next section.

GPU in containers (CUDA on the 5090)

nvidia-container-toolkit is already in the image and a boot service generates the CDI spec automatically. CDI is the shipped mechanism:

# Podman — works out of the box:
podman run --rm --device nvidia.com/gpu=all docker.io/nvidia/cuda:12.8.0-base-ubuntu24.04 nvidia-smi

# Docker — CDI device syntax also works on current Docker CE:
docker run --rm --device nvidia.com/gpu=all nvidia/cuda:12.8.0-base-ubuntu24.04 nvidia-smi

If you want the classic docker run --gpus all syntax, that needs a one-time runtime hookup (this writes to /etc/docker/daemon.json, which is mutable and survives updates):

sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

First-boot Flatpaks

Installed system-wide from Flathub by the default-flatpaks module. All IDs verified against Flathub (2026-07).

Official / verified listings: Bambu Studio, Bitwarden, Discord, Firefox, Thunderbird, FreeCAD, GIMP, HandBrake, LibreOffice, Moonlight, PCSX2 (net.pcsx2.PCSX2 — the official build), Podman Desktop, Prism Launcher, Warzone 2100, XIVLauncher (dev.goats.xivlauncher).

Community / unverified listings — know what you're running:

App ID Note
Android Studio com.google.AndroidStudio Community packaging of Google's IDE (not verified)
GitHub Desktop io.github.shiftey.Desktop Community Linux fork; the "shiftey" spelling is the real ID
MakeMKV com.makemkv.MakeMKV Community packaging of the proprietary app
GeForce NOW io.github.hmlendea.geforcenow-electron Unofficial Electron wrapper, not an NVIDIA product
Spotify com.spotify.Client Community packaging of the proprietary client
VLC org.videolan.VLC No verified badge on Flathub (still the VideoLAN-maintained build)
Godot org.godotengine.Godot No verified badge on Flathub

GeForce NOW on the 32:9 monitor: the service only streams 16:9 (and some 21:9) aspect ratios, so expect pillarboxing at 5120x1440 — that's a service limitation, not a config problem.

Development setup

All 29 projects in ~/Documents/Development were scanned for toolchain needs — the full mapping (what the image covers, mise versions, the native-build distrobox, hardware udev rules) is in DEVELOPMENT.md. After first boot, run scripts/dev-setup.sh to set it all up.

Post-install steps (manual by design — don't automate these)

PIA VPN — native WireGuard, not the app

The PIA desktop app installs into /usr and breaks on the read-only filesystem. Skip it:

  1. Log in at PIA's OpenVPN config generator (or generate a WireGuard config via their API/support flow) and download configs for your preferred regions.
  2. KDE System Settings → Network → Connections → Add (+) → Import VPN connection…, pick the downloaded file, and enter your PIA credentials.
  3. This is plain NetworkManager — it lives in /etc, survives every update, and gets a connect/disconnect toggle in the system tray.

Microsoft Teams — PWA via Edge

No native Linux client. Install Microsoft Edge specifically (corporate conditional access / Intune compatibility): flatpak install flathub com.microsoft.Edge, sign in to https://teams.microsoft.com, then menu → Apps → Install this site as an app.

Claude desktop — PWA

No official Linux app. Open https://claude.ai in Edge (or any Chromium browser) and use Install this site as an app the same way.

AnythingLLM — not on Flathub

No Flatpak exists (verified 2026-07: zero Flathub search hits). Options: the official desktop AppImage from anythingllm.com (works fine on atomic distros — keep it in ~/Apps and use e.g. Gear Lever to integrate it), or run the server edition in a container: docker run -p 3001:3001 mintplexlabs/anythingllm (add --device nvidia.com/gpu=all for 5090 acceleration).

Proton-GE

Already handled by Bazzite: use the preinstalled ProtonUp-Qt GUI (or browse ujust — run ujust with no arguments to list recipes). Don't install anything extra.

Node / toolchains — not in the image

Node, npm, etc. are deliberately not layered. Use per-project versions instead:

brew install mise         # Homebrew ships in the base image
mise use node@22          # per-project .mise.toml; `mise use -g node@22` for a global default

(Plain brew install node also works if you just want one global Node.)

Display note

The 49" 32:9 (5120x1440) ultrawide needs nothing at the image layer. Post-install: set scale and refresh rate in KDE System Settings → Display; KDE's window tiling (Meta+drag, or a tiler like Polonium) is worth setting up at this width. VMs are remote via Remmina — there is intentionally no local hypervisor tooling in this image.

Maintenance

  • Change the Flatpak list / packages: edit recipes/recipe.yml, commit, and re-run bluebuild switch. (Removing an app from the list does not uninstall it from the machine; flatpak uninstall it once by hand.)
  • Jump Fedora majors: change image-version: stable-44stable-45 in the recipe when ready, then bluebuild switch.
  • Reclaim build disk: bluebuild prune cleans build caches.
  • Publishing later: if this ever moves to a registry + signed rebases, the pieces are in place — cosign.pub is committed, the signing module is in the recipe, and bluebuild build --push --registry <host> --registry-namespace <ns> does the rest (note: as of CLI v0.9.36, local build runs bake the signing policy for localhost — a registry push should be done from CI or with a bluebuild generate-based two-step).