Is Running Custom Init Scripts in Dom0 a Common Practice? Any Example/Template Scripts?

Hello Qubes OS Community,

I’m interested in knowing if it’s common practice among Qubes users to run custom initialization scripts in dom0 after a fresh installation. The goal would be to automate certain system customizations, making the setup process more streamlined, especially for highly complex setups on servers that will run dozens of specialized qubes.

I understand the security implications of running scripts in dom0 and want to proceed cautiously. Hence, I’m wondering if there are example scripts or guidelines available that the community commonly uses.

Examples of customizations might include:

Setting up custom themes or fonts
Configuring startup processes or applications
Customize qubes
Automating network settings or firewall rules
Additional system hardening or configurations
And more

Is this a common practice among advanced users? Are there example scripts or resources available that guide you through safely making such customizations?

Your insights and experience would be greatly appreciated.

I use salt to configure my Qubes OS, the files version are tracked by a revision control system and sync on a remote server, so my multiple Qubes OS can be almost identical and I never change anything manually.

1 Like

So do I, and so do a number of people to perform a variety of tasks.

The following topic is specifically about how to gets those “scripts” into dom0 if you don’t write them there (I use signed RPM packages), but the thread also contains links to my own notes about the process of writing and packaging Salt formulas (that’s how Salt scripts are called).

A search on this forum for “Salt” will yield a number of topics, and @unman’s formulas are a recurring resource :slightly_smiling_face:

Note that Bash scripts are a common complement or alternative to Salt, and preferences do vary. (I personally try to use Salt as soon as I plan on reusing something I set up, and avoid standalone Bash scripts, but YMMV.)

1 Like

https://svensemmler.org/notes/deb-min-templates

1 Like

I use a combination of Sven’s minimal templates and salt. Which is to say I followed Sven’s general method but then brought salt into the mixture.

However doing so forced me to face a fundamental limitation of salt.

Sven’s scheme operates by cloning a debian minimal template, adding some software to it, then (more than likely) cloning it again to add a specific application. I might clone debian-12-minimal to add some bare-minimum usability functionality (like font size, xterm, a favorite text editor), to create a debian-12-usable; I’d then clone that several times to add apps to the clones and have a debian-12-firefox, debian-12-keepass, debian-12-libreoffice…you get the idea. The point is you end up with a “tree” of clones, clones-of-clones, clones-of-clones-of-clones…etc.

Salt will not wait for the installation of software on a qube that you just cloned to be completed, before cloning it again. So you can’t write one big omnibus salt recipe that will generate ALL of your templates. You have to run it separately for each template–it will clone a template then install software on it, no problem, and when one template is done, then you can fire up salt for its “descendants.”

So I manage things on individual templates with salt, but if I want to do multiple templates, I have to use a bash script to invoke salt. (The salt command lines are very long and I am prone to typos.)

In any case, you’ve now heard from salt people, bash script people, and now one who does both. I’d suggest starting out with bash as salt has a VERY steep learning curve if you go beyond the absolute simplest cases.

did you specifically configure the salt jobs to wait for the template n-1 task to finish before they start?

I couldn’t find any way to do that. The problem is the qube creation is done by dom0 and the qube software install is done on the qube with the qube as a target. So dom0 creates qube A, then immediately clones B from A, possibly after causing the state where qube A installs its own software, to commence. I never found out how to get dom0 to hold its horses until qube A was done applying that state.

I even asked unman. He stated there was no way to do it in a single qubesctl call.

EDIT: It’s possible too that we can set up dom0 to not try to clone B off of A becuase A is running a state, but it won’t go back to dom0 afterwards. dom0 targets execute first; there doesn’t seem to be any way to switch between running dom0 targeted states and Qube A targeted states, then back to dom0 states.