Maintenance of templates

Hi guys,

Wanted to collect ideas and practices others are using with respect to templates. The approach I’m currently using is installing a template, and keeping clean as a reference. Then I’d clone templates for a particular group of VMs, e.g. I’d have a clone template for sys VMs, a clone for dev VMs, etc. Even though I have to keep updating multiple templates, i like that it allows for a quicker clean up, since i can throw it away, create a new clone and reinstall only required packages. What I’d like to be able to do, is to have snapshots, so that I can revert modifications I may end up making to a template.

So, wondering, how are you guys using templates, one for all VMs, or bunch of templates? How are you maintaining them. How are you upgrading (including dist upgrades)?

I have lots of different kinds of templates, starting with a copy of debian-11-minimal; I clone that and add just a few things to it; then clone that and add more; I have a whole “ancestral tree” of templates deriving from clones of previous templates.

I used to automate it all with scripts; I’ve switched to using salt (but still invoked by scripts). (The way I have salt set up, actually, I could basically generate any one of my qubes without having to create its ancestors since each salt installation formula includes the ones of its ancestors.)

Certainly one template/multiple appvms works, but I just don’t like the idea of having a template include ALL of the software I use on it (plus a bunch I don’t use); that’s how I got started on the path of minimal templates.

1 Like

I have a whole “ancestral tree” of templates deriving from clones of previous templates.

How do you track parent-child relationship? Do you “encode” that in the template name?

I’ll suggest and repeat here. use minimals, thus you’ll reduce attack surface. Think before starting to clone:

  • What all other clones will have in common? Install that in your top minimal.
  • What all children will have in common in home directory with their minimal parent cloned template? Put that in etc/skel folder of your top minimal template. later add specifics to each cloned template.

Do I encode it in the template name? Well, somewhat, and not perfectly. The real tracker is a file full of notes; also the salt files that do the work have numbers that group things together. (Those numbers do not appear in the names of the templates.)

I doubt anyone would actually want to copy my scheme, but I’ll outline it since it may give you ideas you can use. It is complicated. Some of my templates are clones of clones of clones of clones of debian-11-minimal. (You’ll eventually want to lay out a tree diagram.)

Everything derives from debian-11-minimal; I first create deb11m-sys-base and put a bare minimum of things on it (like a particular xterm implementation, font that isn’t microscopic, and so fort). That’s number 00…the number appears in the names of the salt files that generate it.

My sys- qubes’ templates are all in the first group, they clone deb11m-sys-base to things like deb11m-usb (for sys-usb). I have other service qubes, their salt files are numbered 01-09.

Qubes that actually have user applications on them are named deb11a- (not m). [There’s enough on this qube I can’t quite call it minimal any more, but it’s still much smaller than the default debian-11 template.] They start with deb11a-base (numbered 10) which is cloned from deb11m-sys-base and their salt files are numbered 10, 20, etc through 90 for basic combinations of firefox and networking; then apps get installed, for instance, on 11 (deb11a-iso-vault) is the template for my vault qube. It has no networking and no browser so it’s in the 10s; but does have keepass installed. The template itself has “iso” in the name for “isolated” which tells me its one of the 10s.

So here’s a key thing: My salt files to generate deb11a-iso-vault are named “tmpl-11-iso-vault*” Note that the salt file names don’t include deb11a in them; that’s because I intend to reuse them for debian 12 when it comes out. The qube names do include the debian version, that way when debian 12 comes out, I can rerun all the salt files and generate a bunch of templates named deb12m and deb12a. Since they’ll have different names I can switch over to using them, at my leisure. What the templates and salt files have in common is “iso-vault.” Which tells me what the template is for and that it’s in the 10s because of “iso” in the name.

That’s probably confusing as hell, but I’ve already written this four times trying to make it clear without bogging you down in a ton of detail.

The MAIN point being that once you go the minimal route, you can pretty much decide for yourself how best to organize this; I know this is actually my third or fourth such scheme since I’ve been seeing what the drawbacks are.


May I ask how you get the ““font that isn’t microscopic”” in
the deb-11-minimals? All my deb minimals have such tiny
font size that the terminals are completely unusable for me.

In /etc/X11/Xresources/x11-common I added:

Xft.dpi: 96
XTerm*faceSize: 11
XTerm*faceName: DejaVu Mono

at the end. You can adjust the face size or the font name, but I believe DejaVu Mono is a pretty standard font.

(And of course for anyone else reading this, this must be done in the template.)

This is also a good place to set things like locale, which, if you don’t do it, doesn’t break anything but always prints obnoxious messages to your terminal if you start something from the command line. So in your template issue this command:

localedef -f UTF-8 -i en_US en_US.UTF-8

(Don’t use en_US if you’re not in the US, obviously).

You’ll likely also want to install qubes-core-agent-passwordless-root and at-spi2-core and if you use shutdown-on idle, qubes-app-shutdown-idle.

Other things I did were setting up aliases (definitely a very personal-preference thing), command prompt, and the default xterminal–which you might want too; issue on the command line:

update-alternatives --set x-terminal-emulator /usr/bin/xterm

Note these are all very minor additions to the original debian-11-minimum so it’s still a pretty minimal qube, but since I want to leave debian-11-minimum in its pristine state, I do all of these to my ancestral template, deb11m-sys-base. (I change my x terminal emulator to something graphical based in deb11a-base…but that’s downstream from here.)


This post was flagged by the community and is temporarily hidden.

Thank you SteveC! :grinning:

I am actually using minimal templates. I didn’t explicitly mention that in the post, because the question of maintaining them still applies. I totally get the idea of how fork clone for a particular use by a group of common VMs, and I am following the approach you describing. I think what I’m looking for mostly is ways of maintaining that set of templates once you created the hierarchy.

1 Like

Thank you for the write up. I think there are some good ideas that I’ll see how to adapt to my workflow.

I never practice in-place upgrade, although I have like 80-120 qubes. Always from the scratch, while using my notes that looks like this.

I never have anything to clean. When I want to test, I test it either in it’s disposable qube if it’s doable (doesn’t need restarting for example), or I just create a clone of a clone, test and once clear, delete CoC and set the original clone

Although it happens rarely since I do think trough in advance what my cloned template is aimed for and try to set it and forget it at the time just beoire and after cloning/creating it.

Aha, looks like people have very similar ways of tracking that, with some variations. In my case I’m maintaining a script that does that creates, installs necessary packages, and sets up some (but not all) templates that I’m using on a daily basis. Maybe should look into idea of doing that via salt, as SteveC suggested.

1 Like

This is good to read, for sanity check, mine at first, hahah.

Definitely, but while I tend to learn Salt, I like the idea of a “manufacture” just to stay fit :slight_smile:

That’s mostly my case too. However, I did hit a case where the question of cleanup popped up. One of the templates I have that was forked from a minimal template ended up taking up to 2 Gb of space, and that raised a question of why, and how to clean it up. I didn’t have list of required packages captures for this one. So I was debating myself, whether cleaning it up would be faster compared to recreating the list of packages.

Edit: I think I’m just dreaming of a tool to diff 2 templates. :slight_smile:

The very first thing upon creation and setting up I do is:
dnf repoquery --qf '%{name}' --installed | grep -v -- '-debuginfo$' | grep -v '^\(kernel-modules\|kernel\|kernel-core\|kernel-devel\)$' > pkgs.lst

This list is always in my vault.

What I do is just in case, beside above notes mentioned is to meld two of these lists, from both of previous and the new one template (say f36 and f37).

Only when I set it and test for a few weeks I delete previous template…

Hahah, just saw you edited this with what was at the time writing about… Meld is the best tool for that, if I were to be asked.

1 Like

Thank you for that cmd, going to borrow it.

Meld is the best tool for that, if I were to be asked.

Uhm, have to stop you right there. So many typos spelling vimdiff.

1 Like

Oh, and by the way…you don’t HAVE to use salt for that scheme to work, you can write bash scripts to create and install things on templates as well (and name them similarly). In fact I was doing that before I switched to salt.

Another thing to watch out for is that there is a 32 character limit on the length of qube names. And because the disp-mgmt qube fires up to do installs and updates, and creates a VM named disp-mgmt-, with the name being cut short if it is 32 characters long, for a few days I had two qubes whose disp-mgmt qubes were the same after being truncated…that led to problems with salt when it tried to run updates in parallel. I had to adjust names to make sure that the disp-mgmt qube name was unique.

One advantage to salt, though, is that the same script I use to install software on a template can be run to update what’s on the template. Salt will automatically check to see if the software is installed, and check the version; if it’s not the latest, it updates. If it’s the same, it just skips it. And of course if it’s something new (because you just added a package to your salt file), it installs it.

1 Like

Like Steve, I use salt to configure my system, and i use minimal
templates extensively.
I do not “do” anything directly in templates, but always salt them. That
way I have a self documenting system.

Unlike Steve I use a simple naming scheme.
To track inheritance, (where it is not obvious) I use the template name
from qvm-features.
When you clone a template, qvm-features in the clone will return the
template-name of the parent template.
If I clone again, by default template-name will show the
grand-parent, so I adjust this to show the parent, at the time I
clone. I leave the template-summary as it is, so this always shows the
summary description of the ultimate root of a clone chain.

When using multiple templates it is useful to use a caching proxy for
updates instead of the standard tinyproxy. This reduces the amount
downloaded and speeds up updates and installs.
I recommend apt-cacher-ng, and provide a preconfigured package here

I never presume to speak for the Qubes team. When I comment in the Forum or in the mailing lists I speak for myself.

I had actually spotted this template name feature the last time I reformed the way I was doing things, and thought about pursuing it. However, I was not only concentrating on something else at the time, I already had ways to track inheritance [i.e., the methods already descrbed] so I didn’t pursue it then, and forgot to come back to it later.

This is probably pretty easy to automate given that my salt scripts specify the parent template already. I could go into the generic template-creator jinja include file and add one more line. As such I’m going to adopt it (without necessarily abandoning what I’m already doing).

Though my scheme is complicated, it does function by simply reading the name, with no need to open a command prompt (if one isn’t open) and issue qvm-features.

Although no one had yet complained about how much time (and download bandwidth) it takes to maintain all of this, the point about cacher is a good one; I agree with Unman’s recommendation to use one. If for some reason you can’t, however, properly planning your “inheritance” tree can still reduce downloadings…because ideally you would only download a package once, and from that point forward it would be ‘copied’ by cloning templates. (This will NOT help, though, when updating templates!)