Repository navigation
QubesOS Salt
Sketch for using Salt (via qubesctl in dom0) to automate template VM setup and qube configuration that currently requires manual steps.
Salt runs from dom0 and can manage both dom0 configuration and template VM contents. This covers the manual steps in the QubesOS wiki page that happen before chezmoi init --apply runs in the personal AppVM.
Currently manual (Qube Manager clicks + CLI):
# /srv/salt/qubes/personal-template.sls
# Clone fedora-42-xfce into fedora-42-xfce-clone-1
fedora-42-xfce-clone-1:
qvm.clone:
- source: fedora-42-xfce
# Set disk size on the template
fedora-42-xfce-clone-1-prefs:
qvm.prefs:
- name: fedora-42-xfce-clone-1
- maxmem: 0
- disk: 20G
# Configure personal qube
personal:
qvm.prefs:
- template: fedora-42-xfce-clone-1
- disk: 20G# /srv/salt/qubes/whonix-clones.sls
whonix-gateway-17-clone-1:
qvm.clone:
- source: whonix-gateway-17
whonix-workstation-17-clone-1:
qvm.clone:
- source: whonix-workstation-17
sys-whonix-template:
qvm.prefs:
- name: sys-whonix
- template: whonix-gateway-17-clone-1
anon-whonix-template:
qvm.prefs:
- name: anon-whonix
- template: whonix-workstation-17-clone-1Salt can install packages from dom0 without granting the template permanent network access (Salt uses qrexec, not the network):
# /srv/salt/template-packages.sls
install-dev-packages:
pkg.installed:
- pkgs:
# Core CLI tools
- wget
- jq
- ripgrep
- fd-find
- bat
- fzf
- git-delta
- zoxide
- yq
- du-dust
- tree-sitter
- hexyl
- lsd
- pandoc
- difftastic
- plocate
# Shell & prompt
- fish
- shfmt
- ShellCheck
# Editor & dev tools
- neovim
- tmux
- ctags
- direnv
- gitleaks
- automake
- clang-tools-extra
# Git tools
- git-credential-oauth
- gh
- glab
# Language runtimes & build tools
- rust-analyzer
- compat-lua
- luarocks
- ImageMagick
- ImageMagick-devel
# Desktop & window management
- rofi
- bemenu
- feh
- qt6ct
- xclip
- chafa
- foliate
# Web & chat
- weechat
# Misc
- dnf-plugins-core# /srv/salt/template-copr.sls
yazi-copr:
cmd.run:
- name: dnf copr enable -y lihaohong/yazi
- unless: dnf repolist | grep -q lihaohong-yazi
yazi-install:
pkg.installed:
- name: yazi
- require:
- cmd: yazi-copr
ghostty-copr:
cmd.run:
- name: dnf copr enable -y scottames/ghostty
- unless: dnf repolist | grep -q scottames-ghostty
ghostty-install:
pkg.installed:
- name: ghostty
- require:
- cmd: ghostty-copr# /srv/salt/template-chezmoi.sls
chezmoi-install:
cmd.script:
- name: salt://scripts/install-chezmoi.sh
- unless: which chezmoiWhere install-chezmoi.sh is the existing verification script (cosign + checksum) placed in /srv/salt/scripts/.
# /srv/salt/template-cosign.sls
cosign-install:
cmd.run:
- name: |
LATEST_VERSION=$(curl https://api.github.com/repos/sigstore/cosign/releases/latest | grep tag_name | cut -d : -f2 | tr -d "v\", ")
curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-${LATEST_VERSION}-1.x86_64.rpm"
rpm -ivh cosign-"${LATEST_VERSION}"-1.x86_64.rpm
- unless: which cosign# /srv/salt/personal-setup.top
base:
fedora-42-xfce-clone-1:
- template-packages
- template-copr
- template-cosign
- template-chezmoi
dom0:
- qubes.personal-template
- qubes.whonix-clonesFrom dom0:
# Create qubes and set preferences (dom0 only)
sudo qubesctl state.apply
# Install packages in the template
sudo qubesctl --targets=fedora-42-xfce-clone-1 state.apply
# Or do everything at once
sudo qubesctl --all state.applySome things can't or shouldn't be automated via Salt:
- electrum-ltc - requires interactive GPG key trust decisions
-
Whonix configuration -
systemcheck,repository-dist,upgrade-nonrootare interactive - Monero wallet isolation - complex multi-qube setup with GPG verification and manual trust decisions
-
i3 in dom0 -
qubes-dom0-update i3 i3-settings-qubescould be Salt, but the initial config generation is interactive - Clipboard shortcuts - GUI-only setting in Qube Manager
dom0 (Salt)
|
+-- manages qube creation, template cloning, qube preferences
+-- manages template VM packages (dnf, COPR, cosign, chezmoi)
|
v
personal AppVM (chezmoi hooks)
|
+-- manages user-level software (rustup, cargo crates, LSPs)
+-- manages dotfile-adjacent tools (debug adapters, feeds)
+-- manages dotfiles (chezmoi's core job)
Salt handles the infrastructure layer (qubes + template contents). Chezmoi handles the user layer (everything in $HOME inside the personal AppVM). They don't overlap.
Salt states live in the chezmoi source dir:
~/.local/share/chezmoi/
salt/ # copied to /srv/salt in dom0
qubes/
personal-template.sls
whonix-clones.sls
template-packages.sls
template-copr.sls
template-cosign.sls
template-chezmoi.sls
scripts/
install-chezmoi.sh
personal-setup.top
To deploy, copy the salt states into dom0:
# From dom0
qvm-copy-to-vm dom0 /home/user/.local/share/chezmoi/salt/
# Then move to /srv/salt/
sudo cp -r ~/QubesIncoming/personal/salt/* /srv/salt/
sudo qubesctl top.enable personal-setup
sudo qubesctl --all state.apply