Qubes Salt Beginner's Guide revisions

Go back to topic: Qubes Salt Beginner's Guide

  1. v73 anchor; v73 full version
  2. v72 anchor; v72 full version
  3. v71 anchor; v71 full version
  4. v70 anchor; v70 full version
  5. v69 anchor; v69 full version
  6. Removing gui_user and corresponding qvm-appmenus commands v68 anchor; v68 full version
  7. v67 anchor; v67 full version
  8. v66 anchor; v66 full version
  9. v65 anchor; v65 full version
  10. v64 anchor; v64 full version
  11. v63 anchor; v63 full version
  12. v62 anchor; v62 full version
  13. v61 anchor; v61 full version
  14. v60 anchor; v60 full version
  15. v59 anchor; v59 full version
  16. v58 anchor; v58 full version
  17. v57 anchor; v57 full version
  18. v56 anchor; v56 full version
  19. v55 anchor; v55 full version
  20. v54 anchor; v54 full version
  21. v53 anchor; v53 full version
  22. v52 anchor; v52 full version
  23. v51 anchor; v51 full version
  24. v50 anchor; v50 full version
  25. v49 anchor; v49 full version
  26. v48 anchor; v48 full version
  27. v47 anchor; v47 full version
  28. v46 anchor; v46 full version
  29. v45 anchor; v45 full version
  30. v44 anchor; v44 full version
  31. v43 anchor; v43 full version
  32. v42 anchor; v42 full version
  33. v41 anchor; v41 full version
  34. v40 anchor; v40 full version
  35. v39 anchor; v39 full version
  36. v38 anchor; v38 full version
  37. v37 anchor; v37 full version
  38. v36 anchor; v36 full version
  39. v35 anchor; v35 full version
  40. v34 anchor; v34 full version
  41. v33 anchor; v33 full version
  42. v32 anchor; v32 full version
  43. v31 anchor; v31 full version
  44. v30 anchor; v30 full version
  45. v29 anchor; v29 full version
  46. v28 anchor; v28 full version
  47. v27 anchor; v27 full version
  48. v26 anchor; v26 full version
  49. v25 anchor; v25 full version
  50. v24 anchor; v24 full version
  51. v23 anchor; v23 full version
  52. v22 anchor; v22 full version
  53. v21 anchor; v21 full version
  54. v20 anchor; v20 full version
  55. v19 anchor; v19 full version
  56. v18 anchor; v18 full version
  57. v17 anchor; v17 full version
  58. v16 anchor; v16 full version
  59. v15 anchor; v15 full version
  60. v14 anchor; v14 full version
  61. v13 anchor; v13 full version
  62. v12 anchor; v12 full version
  63. v11 anchor; v11 full version
  64. v10 anchor; v10 full version
  65. v9 anchor; v9 full version
  66. v8 anchor; v8 full version
  67. v7 anchor; v7 full version
  68. v6 anchor; v6 full version
  69. v5 anchor; v5 full version
  70. v4 anchor; v4 full version
  71. v3 anchor; v3 full version
  72. v2 anchor; v2 full version

Revision #73

Edited on
2024-11-01
Edited by user
ben-grande
**Guides**:
* @unman['s notes](https://github.com/unman/notes/blob/master/salt/Index), a good reference on Salt written by a developer of Qubes OS * @unman['s notes](https://github.com/unman/notes/blob/master/salt/Index), a good reference on Salt written by a developer of Qubes OS **Formulas**: * [Shaker](https://github.com/unman/shaker) by @unman
* [qusal: Salt Formulas for Qubes OS](https://github.com/ben-grande/qusal) by Ben Grande * [qubes-for-journalists](https://github.com/kennethrrosen/qubes-for-journalists/), a simple journalist-oriented salt repo and wiki by @kenosen* [qusal: Salt Formulas for Qubes OS](https://github.com/ben-grande/qusal) by @ben-grande * [qubes-for-journalists](https://github.com/kennethrrosen/qubes-for-journalists/), a simple journalist-oriented salt repo and wiki by @kenosen **Videos**: * [How to architect your Qubes OS with SaltStack](https://www.youtube.com/watch?v=Ib8kVTuajl4) by @ben-grande

Revision #72

Edited on
2024-11-01
Edited by user
ben-grande

Revision #71

Edited on
2024-07-05
Edited by user
leo
{% from 'backup/map.jinja' import backup %} {% from 'backup/map.jinja' import backup %}

Revision #70

Edited on
2024-05-21
Edited by user
leo
{% if grains['id'] == 'dom0' %} {% if grains['id'] == 'dom0' %}

Revision #69

Edited on
2024-04-12
Edited by user
leo
* [qusal: Salt Formulas for Qubes OS](https://github.com/ben-grande/qusal) by Ben Grande* [qusal: Salt Formulas for Qubes OS](https://github.com/ben-grande/qusal) by Ben Grande * [qubes-for-journalists](https://github.com/kennethrrosen/qubes-for-journalists/), a simple journalist-oriented salt repo and wiki by @kenosen

Revision #68

Edited on
2024-04-06
Edited by user
parulin
Edit reason
Removing gui_user and corresponding qvm-appmenus commands
{% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %}
- menu-items: org.gnome.Terminal.desktop org.gnome.Nautilus.desktop disconnected--update-app-menu: cmd.run: - name: qvm-appmenus --update disconnected - runas: {{ gui_user }} - require: - qvm: disconnected--create-qube - menu-items: org.gnome.Terminal.desktop org.gnome.Nautilus.desktop
[details=Note on the "{}" characters] Note that by default, `cmd.run` makes Salt run commands as root. The command `qvm-appmenus` does not work as root, so we have to make Salt run this command as a regular user. To do so, in the first line of the file we use a templating language called [Jinja](https://jinja.palletsprojects.com/templates/) to retrieve our username, we save our username in the `gui_user` variable, and we use this variable when needed. Salt will always execute all the templating instructions between `{}` before running a state configuration file. [/details]
{% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %}
- menu-items: org.keepassxc.KeePassXC.desktop org.gnome.Terminal.desktop vault--update-app-menu: cmd.run: - name: qvm-appmenus --update vault - runas: {{ gui_user }} - require: - qvm: vault--create-qube - menu-items: org.keepassxc.KeePassXC.desktop org.gnome.Terminal.desktop
{% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %}
messaging--update-app-menu: cmd.run: - name: qvm-appmenus --update messaging - runas: {{ gui_user }} - require: - qvm: messaging--create-qube
{% if grains['id'] == 'dom0' %} {% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %} {% if grains['id'] == 'dom0' %}
conferencing--update-app-menu: cmd.run: - name: qvm-appmenus --update conferencing - runas: {{ gui_user }} - require: - qvm: conferencing--create-app-qube
{% from 'backup/map.jinja' import backup %} {% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %} {% from 'backup/map.jinja' import backup %}
- file: backup--install-wyng backup--update-app-menu: cmd.run: - name: qvm-appmenus --update sys-backup - runas: {{ gui_user }} - require: - qvm: backup--create-service-qube - file: backup--install-wyng
{% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %}
backup--update-app-menu: cmd.run: - name: qvm-appmenus --update sys-backup - runas: {{ gui_user }} - require: - qvm: backup--create-service-qube

Revision #67

Edited on
2024-04-06
Edited by user
parulin

Revision #66

Edited on
2024-03-26
Edited by user
leo
* [Qubes SaltStack configuration of Videos Playback VM](https://codeberg.org/brunoschroeder/qubes-salt-video-playback) (**didatic**) by @bruno_schroeder* [Qubes SaltStack configuration of Videos Playback VM](https://codeberg.org/brunoschroeder/qubes-salt-video-playback) (**didatic**) by @bruno_schroeder * [qusal: Salt Formulas for Qubes OS](https://github.com/ben-grande/qusal) by Ben Grande

Revision #65

Edited on
2024-01-24
Edited by user
bruno_schroeder
* [Qubes SaltStack configuration of Videos Playback VM](https://codeberg.org/brunoschroeder/qubes-salt-video-playback) by @bruno_schroeder* [Qubes SaltStack configuration of Videos Playback VM](https://codeberg.org/brunoschroeder/qubes-salt-video-playback) (**didatic**) by @bruno_schroeder

Revision #64

Edited on
2024-01-24
Edited by user
leo
* [Qubes configuration management](https://docs.gonzalobulnes.com/configuration_management.html), extensive docs by gonzalo-bulnes * [Qubes configuration management](https://docs.gonzalobulnes.com/configuration_management.html), extensive docs by @gonzalo-bulnes
* [unman's notes](https://github.com/unman/notes/blob/master/salt/Index), a good reference on Salt written by a developer of Qubes OS * @unman['s notes](https://github.com/unman/notes/blob/master/salt/Index), a good reference on Salt written by a developer of Qubes OS
[Wyng](https://github.com/tasket/wyng-backup/) is a backup software that we can use to make incremental backups of the contents of our qubes in a very efficient manner. Its project page gives a detailed explanation of how it works. It should be noted that a tool called [wyng-util-qubes](https://github.com/tasket/wyng-util-qubes/) is currently being developed and makes it very easy to use Wyng with Qubes OS. One of the advantages of using this tool is that, on top of backing up the contents of our qubes with Wyng, this tool also backs up their configuration. At the time of writing, however, wyng-util-qubes does not yet support installations of Qubes OS with a BTRFS partitioning scheme. For this reason, and because the configuration of our qubes is already saved in our Salt state configuration files, we are going to use Wyng directly instead of wyng-util-qubes. [Wyng](https://github.com/tasket/wyng-backup/) is a backup software written by @tasket that we can use to make incremental backups of the contents of our qubes in a very efficient manner. Its project page gives a detailed explanation of how it works. It should be noted that a tool called [wyng-util-qubes](https://github.com/tasket/wyng-util-qubes/) is also currently being developed and makes it very easy to use Wyng with Qubes OS. One of the advantages of using this tool is that, on top of backing up the contents of our qubes with Wyng, this tool also backs up their configuration. At the time of writing, however, wyng-util-qubes does not yet support installations of Qubes OS with a BTRFS partitioning scheme. For this reason, and because the configuration of our qubes is already saved in our Salt state configuration files, we are going to use Wyng directly instead of wyng-util-qubes.
* [Qubes configuration management](https://docs.gonzalobulnes.com/configuration_management.html), extensive docs by gonzalo-bulnes * [unman's notes](https://github.com/unman/notes/blob/master/salt/Index), a good reference on Salt written by a developer of Qubes OS * [Salt & Pepper](https://git.drkhsh.at/salt-n-pepper/file/README.md.html), drkhsh's Qubes SaltStack configuration for automated template deployments * [qubes-salt-examples](https://github.com/zaz/qubes-salt-examples) by zaz and kennethrrosen * [Qubes SaltStack configuration of Videos Playback VM](https://codeberg.org/brunoschroeder/qubes-salt-video-playback) by bruno_schroeder* [Qubes configuration management](https://docs.gonzalobulnes.com/configuration_management.html), extensive docs by @gonzalo-bulnes * @unman['s notes](https://github.com/unman/notes/blob/master/salt/Index), a good reference on Salt written by a developer of Qubes OS * [Salt & Pepper](https://git.drkhsh.at/salt-n-pepper/file/README.md.html), drkhsh's configuration for automated template deployments * [qubes-salt-examples](https://github.com/zaz/qubes-salt-examples) by @zaz and @kenosen * [Qubes SaltStack configuration of Videos Playback VM](https://codeberg.org/brunoschroeder/qubes-salt-video-playback) by @bruno_schroeder

Revision #63

Edited on
2024-01-23
Edited by user
leo
It took me quite a while to write this final part of the guide but I'm quite happy with the result. I tried to write it in a way that is easy to adapt to another Qubes install. Of course, feel free to ask if something needs clarification or doesn't work. Have a nice day.It took me quite a while to write this final part of the guide but I'm quite happy with the result. I tried to write it in a way that is easy to adapt to another Qubes install. Of course, feel free to ask if something needs clarification or doesn't work. Have a nice day. ## Appendix: Salt resources made by Qubes users * [Qubes configuration management](https://docs.gonzalobulnes.com/configuration_management.html), extensive docs by gonzalo-bulnes * [unman's notes](https://github.com/unman/notes/blob/master/salt/Index), a good reference on Salt written by a developer of Qubes OS * [Salt & Pepper](https://git.drkhsh.at/salt-n-pepper/file/README.md.html), drkhsh's Qubes SaltStack configuration for automated template deployments * [qubes-salt-examples](https://github.com/zaz/qubes-salt-examples) by zaz and kennethrrosen * [Qubes SaltStack configuration of Videos Playback VM](https://codeberg.org/brunoschroeder/qubes-salt-video-playback) by bruno_schroeder

Revision #62

Edited on
2024-01-13
Edited by user
leo
We run the command `sudo qubesctl state.sls qubes.user-dirs`. Salt applies the corresponding state, and tell us that some files and directories were created. Among these directories we can find `/srv/user_salt/`: this is the main directory where we'll place our own state configuration files. We run the command `sudo qubesctl state.sls qubes.user-dirs`. Salt applies the corresponding state, and tells us that some files and directories were created. Among these directories we can find `/srv/user_salt/`: this is the main directory where we'll place our own state configuration files.

Revision #61

Edited on
2023-10-04
Edited by user
leo
* The initial state `init.sls` makes sure that Wyng and the python libraries that are required for encryption and compression are installed in dom0, and creates the "sys-backup" service qube. We must run this state at least once before using the other states. We can run this state with: * The initial state `init.sls` makes sure that Wyng and the python libraries that are required for encryption and compression are installed in dom0, and creates the "sys-backup" service qube. **We must run this state at least once before using the other states.** We can run this state with:

Revision #60

Edited on
2023-10-03
Edited by user
leo
'passphrase': 'uyar!Nzvlio16', 'passphrase': 'my-backup-passphrase',

Revision #59

Edited on
2023-10-03
Edited by user
leo
Coming soon! We would like to configure Wyng to create encrypted incremental backups that we will directly upload to a remote [Nextcloud Server](https://docs.nextcloud.com/server/latest/user_manual/). To do so, we will use [rclone](https://rclone.org/) to mount the cloud storage in a [service qube](https://www.qubes-os.org/doc/glossary/#service-qube) called "sys-backup". **This method is not recommended for backing up large qubes**, because each backup has to be copied to a [virtual file system](https://rclone.org/commands/rclone_mount/#vfs-virtual-file-system) in the "sys-backup" qube before it can be uploaded to the remote. This means that the "sys-backup" qube must be large enough to hold an entire incremental backup, which may require too much disk space. We create the following files: [details=/srv/user_salt/backup/map.jinja] ```jinja {# This file holds the backup passphrase and general configuration #} {# The passphrase must not contain any single quote character (') #} {% import 'templates.jinja' as templates %} {% set backup = { 'passphrase': 'uyar!Nzvlio16', 'qubes': ['archive', 'personal', 'vault'], 'volumes': ['appvms/archive/private.img', 'appvms/personal/private.img', 'appvms/vault/private.img'], 'source': '/var/lib/qubes', 'directory': 'qubes.backup', 'remote': ':webdav,url="https://cloud.example.com/remote.php/webdav",vendor=nextcloud,user=username,pass=0o6e86yXVit3PLTQqrPW_3msNJWctCnf:', 'domain': 'cloud.example.com', 'timeout': 3600, } %} ``` [/details] [details=/srv/user_salt/backup/init.sls] ```yaml # Install Wyng and rclone and create the service qube "sys-backup" {% from 'backup/map.jinja' import backup %} {% if grains['id'] == 'dom0' %} {% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} backup--install-dependencies: pkg.installed: - pkgs: - python3-pycryptodomex - python3-zstd backup--install-wyng: file.managed: - names: - /usr/local/bin/wyng: - source: salt://backup/files/wyng - mode: 755 - /etc/wyng/wyng.ini: - source: salt://backup/files/wyng.ini - template: jinja - context: {{ backup|yaml }} - makedirs: True - require: - pkg: backup--install-dependencies backup--create-service-qube: qvm.vm: - name: sys-backup - present: - template: debian-12 - label: yellow - prefs: - template: debian-12 - label: yellow - provides-network: True # "service qube" (see Qubes issue #7298) - features: - set: - menu-items: org.gnome.Terminal.desktop org.gnome.Nautilus.desktop - require: - file: backup--install-wyng backup--update-app-menu: cmd.run: - name: qvm-appmenus --update sys-backup - runas: {{ gui_user }} - require: - qvm: backup--create-service-qube backup--set-volume-size: cmd.run: - name: qvm-volume extend sys-backup:private 10Gi - require: - qvm: backup--create-service-qube backup--set-firewall-rules: file.managed: - name: {{ backup.source }}/appvms/sys-backup/firewall.xml - source: salt://backup/files/firewall.xml - template: jinja - context: {{ backup|yaml }} - require: - qvm: backup--create-service-qube {% elif grains['id'] == 'debian-12' %} backup--install-rclone: pkg.installed: - pkgs: - rclone {% endif %} ``` [/details] [details=/srv/user_salt/backup/configure.sls] ```yaml # Create a backup archive and add the backed-up qubes to its configuration {% from 'backup/map.jinja' import backup %} backup.configure--create-mount-point: cmd.run: - name: qvm-run sys-backup 'sudo mkdir /mnt/remote && sudo chown user:user /mnt/remote' backup.configure--mount-remote: cmd.run: - name: | qvm-run --quiet sys-backup rclone mount --rc --vfs-cache-mode=writes '{{ backup.remote }}' /mnt/remote - bg: True - require: - cmd: backup.configure--create-mount-point backup.configure--wait-mounted: loop.until_no_eval: - name: cmd.run - expected: 'true' - args: - qvm-run --pass-io sys-backup 'rclone rc vfs/list | jq ".vfses | length == 1"' - require: - cmd: backup.configure--mount-remote backup.configure--create-archive: cmd.run: - name: | echo '{{ backup.passphrase }}' | wyng arch-init --unattended - require: - loop: backup.configure--wait-mounted - unless: - qvm-run sys-backup test -d /mnt/remote/{{ backup.directory }} backup.configure--wait-archive-sync: loop.until_no_eval: - name: cmd.run - expected: 'true' - timeout: {{ backup.timeout }} - args: - qvm-run --pass-io sys-backup 'rclone rc vfs/stats | jq "all(.diskCache | .[\"uploadsInProgress\", \"uploadsQueued\"]; . == 0)"' - require: - cmd: backup.configure--create-archive backup.configure--add-volumes: cmd.run: - name: | echo '{{ backup.passphrase }}' | wyng add {{ backup.volumes|join(' ') }} --unattended - require: - loop: backup.configure--wait-archive-sync backup.configure--wait-volumes-sync: loop.until_no_eval: - name: cmd.run - expected: 'true' - timeout: {{ backup.timeout }} - args: - qvm-run --pass-io sys-backup 'rclone rc vfs/stats | jq "all(.diskCache | .[\"uploadsInProgress\", \"uploadsQueued\"]; . == 0)"' - require: - cmd: backup.configure--add-volumes ``` [/details] [details=/srv/user_salt/backup/clear-cache.sls] This is identical to the homonymous state in [section 3.3](#h-33-making-local-backups-17). [/details] [details=/srv/user_salt/backup/send.sls] ```yaml # Create a backup and upload it to the archive through "sys-backup" {% from 'backup/map.jinja' import backup %} include: - backup.configure - backup.clear-cache backup.send--send-backup: cmd.run: - name: | echo '{{ backup.passphrase }}' | wyng send --all --unattended - require: - loop: backup.configure--wait-volumes-sync - qvm: backup.clear-cache--clear-cache backup.send--wait-backup-sync: loop.until_no_eval: - name: cmd.run - expected: 'true' - timeout: {{ backup.timeout }} - args: - qvm-run --pass-io sys-backup 'rclone rc vfs/stats | jq "all(.diskCache | .[\"uploadsInProgress\", \"uploadsQueued\"]; . == 0)"' - require: - cmd: backup.send--send-backup backup.send--shutdown-service-qube: qvm.shutdown: - name: sys-backup - require: - loop: backup.send--wait-backup-sync ``` [/details] [details=/srv/user_salt/backup/receive.sls] ```yaml # Overwrite current data with the most recent backup from the archive {% from 'backup/map.jinja' import backup %} include: - backup.configure backup.receive--shutdown-app-qubes: qvm.shutdown: - names: {{ backup.qubes|yaml }} - require: - loop: backup.configure--wait-volumes-sync backup.receive--receive-backup: cmd.run: - name: | echo '{{ backup.passphrase }}' | wyng receive --all --unattended - require: - qvm: backup.receive--shutdown-app-qubes backup.receive--wait-backup-sync: loop.until_no_eval: - name: cmd.run - expected: 'true' - timeout: {{ backup.timeout }} - args: - qvm-run --pass-io sys-backup 'rclone rc vfs/stats | jq "all(.diskCache | .[\"uploadsInProgress\", \"uploadsQueued\"]; . == 0)"' - require: - cmd: backup.receive--receive-backup backup.receive--shutdown-service-qube: qvm.shutdown: - name: sys-backup - require: - loop: backup.receive--wait-backup-sync ``` [/details] [details=/srv/user_salt/backup/files/wyng] This is Wyng's executable file which we copied to dom0 in [section 3.1](#h-31-downloading-wyng-15). [/details] [details=/srv/user_salt/backup/files/wyng.ini] ```ini {#- This file configures the default options for Wyng commands -#} [var-global-default] local = {{ source }} dest = qubes://sys-backup/mnt/remote/{{ directory }} ``` [/details] [details=/srv/user_salt/backup/files/firewall.xml] ```xml {#- This file sets up basic firewall rules for "sys-backup" -#} <firewall version="2"> <rules> <rule> <properties> <property name="action">accept</property> <property name="dsthost">{{ domain }}</property> </properties> </rule> <rule> <properties> <property name="action">accept</property> <property name="specialtarget">dns</property> </properties> </rule> <rule> <properties> <property name="action">accept</property> <property name="proto">icmp</property> </properties> </rule> <rule> <properties> <property name="action">drop</property> </properties> </rule> </rules> </firewall> ``` [/details] This gives us a general configuration file `map.jinja` where we can enter our encryption password as well as the list of qubes that we want to include in our backups, the rclone remote specification as a [connection string](https://rclone.org/docs/#connection-strings), and how much time we are willing to wait for each upload operation (in seconds). We also wrote the following Salt states: * The initial state `init.sls` makes sure that Wyng and the python libraries that are required for encryption and compression are installed in dom0, and installs rclone in the template "debian-12". It also creates the "sys-backup" service qube, and adds a firewall rule to prevent this qube from conecting to any IP address that does not correspond to the domain of the cloud storage. **We must run this state at least once before using the other states**. We can run this state with: ```sh sudo qubesctl --show-output --targets=debian-12 state.sls backup saltenv=user ``` * The state `configure.sls` mounts the cloud storage in "sys-backup", creates the backup archive if it doesn't exist, and ensures that all the backed-up qubes specified in the configuration file `map.jinja` are in the archive configuration. This state is automatically included in other states that require it, but we can also run it manually with: ```sh sudo qubesctl state.sls backup.configure saltenv=user ``` * The state `clear-cache.sls` shuts down all the backed-up qubes to make sure that there have no program running, then starts them one by one and removes their cache directory `/home/user/.cache` before shutting them down once again. Because it is important to clear the cache before making backups, this step is automatically included as part of the backup process when using the state `send.sls` to make backups. Nevertheless, if needed we can run this state manually with the command: ```sh sudo qubesctl state.sls backup.clear-cache saltenv=user ``` * The state `send.sls` first applies the state `configure.sls`, then clears the cache of all backed-up qubes by applying the state `clear-cache.sls`, and finally uploads a new backup to the archive through "sys-backup". **This is the state that we'll run the most.** We can run it with: ```sh sudo qubesctl state.sls backup.send saltenv=user ``` * The state `receive.sls` automatically applies the state `configure.sls`, then shuts down all the backed-up qubes and overwrites their data with the data downloaded from the latest backup found in the archive. It can be run with: ```sh sudo qubesctl state.sls backup.receive saltenv=user ``` [details=Tip: For very long operations, we can run Wyng manually to see progress in real-time.] Making backups manually requires performing more actions than simply applying the `send.sls` state file, but it is useful because it shows the output of Wyng in real time during the backup process. It can be done by running the following command (preceded by `sudo qubesctl state.sls backup.configure saltenv=user` in case the backup archive is not yet configured): ```sh sudo qubesctl state.sls backup.clear-cache saltenv=user && sudo wyng send --all ``` We must then run the following command periodically to see how many uploads are still in progress/queued: ```sh qvm-run --pass-io sys-backup rclone rc vfs/stats ``` The backup is complete when the properties "uploadsQueued" and "uploadsInProgress" returned by this command are both equal to zero. It is also possible to restore a backup manually by running the following command after shuting down all the backed-up qubes: ```sh sudo wyng receive --all ``` [/details]
* [docs for rclone](https://rclone.org/docs/), a tool to manage files in the cloud supportting many storage providers

Revision #58

Edited on
2023-10-03
Edited by user
leo

Revision #57

Edited on
2023-09-14
Edited by user
leo
* [Qubes configuration management](https://docs.gonzalobulnes.com/configuration_management.html), extensive docs by gonzalo-bulnes
* [unman's notes](https://github.com/unman/notes/blob/master/salt/Index), my first reference whenever I need help with Salt in Qubes OS * [Salt docs](https://docs.saltproject.io/en/latest/contents.html), great when looking for something specific but intimidating to start with * [unman's notes](https://github.com/unman/notes/blob/master/salt/Index), a good reference on Salt written by a developer of Qubes OS
* [Salt docs](https://docs.saltproject.io/en/latest/contents.html), great when looking for something specific but intimidating to start with

Revision #56

Edited on
2023-09-03
Edited by user
leo
Making backups manually requires performing more actions than simply applying the `send.sls` state file, but it is useful because it shows the output of Wyng in real time during the backup process. It can be done by running the following command (preceded by `sudo qubesctl state.sls backup.configure` in case the backup archive is not yet configured): Making backups manually requires performing more actions than simply applying the `send.sls` state file, but it is useful because it shows the output of Wyng in real time during the backup process. It can be done by running the following command (preceded by `sudo qubesctl state.sls backup.configure saltenv=user` in case the backup archive is not yet configured):
sudo qubesctl state.sls backup.clear-cache && sudo wyng send --all sudo qubesctl state.sls backup.clear-cache saltenv=user && sudo wyng send --all

Revision #55

Edited on
2023-09-02
Edited by user
leo
In the next part of this guide, we will learn how to make Salt perform automated backups of our qubes with [Wyng](https://github.com/tasket/wyng-backup/). In the final part of this guide, we will learn how to make Salt perform automated backups of our qubes with [Wyng](https://github.com/tasket/wyng-backup/).
This is the Wyng executable file that we have copied to dom0 in [section 3.1](#h-31-downloading-wyng-15). This is Wyng's executable file which we copied to dom0 in [section 3.1](#h-31-downloading-wyng-15).
Making backups manually requires performing more actions than simply applying the `send.sls` state file, but it is useful because it shows the real-time output of Wyng during the backup process. It can be done by running the following command (preceded by `sudo qubesctl state.sls backup.configure` in case the backup archive is not yet configured): Making backups manually requires performing more actions than simply applying the `send.sls` state file, but it is useful because it shows the output of Wyng in real time during the backup process. It can be done by running the following command (preceded by `sudo qubesctl state.sls backup.configure` in case the backup archive is not yet configured):
* [Wyng repository](https://github.com/tasket/wyng-backup), it gives detailed explanations for each command and their arguments * [Wyng repository](https://github.com/tasket/wyng-backup/), it gives detailed explanations for each command and their arguments
It took me quite a while to write this last part of the guide but I'm quite happy with the result. I tried to write it in a way that is easy to adapt to another Qubes install. Of course, feel free to ask if something needs clarification or doesn't work. Have a nice day.It took me quite a while to write this final part of the guide but I'm quite happy with the result. I tried to write it in a way that is easy to adapt to another Qubes install. Of course, feel free to ask if something needs clarification or doesn't work. Have a nice day.

Revision #54

Edited on
2023-09-02
Edited by user
leo
This state configuration file has two parts. In the first part, we wrote the instructions that Salt has to execute while running in the admin qube dom0, while the second part is about installing Telegram, which must be executed in the template debian-12. To have everything in the same file but ensure that the right part gets executed in the right qube, we decided to use a Jinja ["if statement"](https://jinja.palletsprojects.com/templates/#if) to modify the state configuration file depending on in what qube Salt is running the instructions for. This state configuration file has two parts. In the first part, we wrote the instructions that Salt has to execute while running in the admin qube dom0, while the second part is about installing Telegram, which must be executed in the template debian-12. To have everything in the same file but ensure that the right part gets executed in the right qube, we decided to use a Jinja ["if statement"](https://jinja.palletsprojects.com/templates/#if) to modify the state configuration file depending on what qube Salt is currently running the instructions for.
In the next part of this guide, we will learn how to make Salt perform automated backups of our qubes with [Wyng](https://github.com/tasket/wyng-backup). In the next part of this guide, we will learn how to make Salt perform automated backups of our qubes with [Wyng](https://github.com/tasket/wyng-backup/).

Revision #53

Edited on
2023-09-02
Edited by user
leo
As a beginner, [Salt](https://www.qubes-os.org/doc/salt/) seemed daunting to me at first. It took me some efforts to learn but it was worth it! I'm writing this guide for beginners who enjoy an hands-on introduction with examples. As a beginner, [Salt](https://www.qubes-os.org/doc/salt/) seemed daunting to me at first. It took some effort to learn but it was worth it! I'm writing this guide for beginners who enjoy an hands-on introduction with examples.
We can activate `qubes.user-dirs` to create personal state configuration directories. What is this, and how do we activate it? This is what we call a *state configuration*. It is a configuration file that tells Salt what to do to reach a particular state. We can activate `qubes.user-dirs` to create personal state configuration directories. What is `qubes.user-dirs`, and how do we activate it? This is what we call a *state configuration*. It is a configuration file that tells Salt what to do to reach a particular state.
We run the command `sudo qubesctl state.sls qubes.user-dirs`. Salt applies the corresponding state, and tell us that some files and directories were created. Among these directories we can find `/srv/user_salt/`: this is the main directory where we'll place our state configuration files. We run the command `sudo qubesctl state.sls qubes.user-dirs`. Salt applies the corresponding state, and tell us that some files and directories were created. Among these directories we can find `/srv/user_salt/`: this is the main directory where we'll place our own state configuration files.
Running the state `qubes.user-dirs` will also create the file `/srv/user_salt/top.sls`. Here is what this file looks like before we modify it ([GitHub link](https://github.com/QubesOS/qubes-mgmt-salt-base-config/blob/b3d2837/qubes/files/top.sls)): Running the state `qubes.user-dirs` also created the file `/srv/user_salt/top.sls`. Here is what this file looks like before we modify it ([GitHub link](https://github.com/QubesOS/qubes-mgmt-salt-base-config/blob/b3d2837/qubes/files/top.sls)):
If we were to uncomment those lines and run highstate, Salt would run in *all* targeted qubes (this is what is meant by the `*` character) the state `locale`, for which the state configuration file is either `/srv/user_salt/locale.sls` or `/srv/user_salt/locale/init.sls`. If we were to uncomment those lines and run highstate, Salt would run in *all* targeted qubes (this is what is meant by the `*` character) the state `locale`, for which the state configuration file can either be `/srv/user_salt/locale.sls` or `/srv/user_salt/locale/init.sls`.

Revision #52

Edited on
2023-08-31
Edited by user
leo
As a beginner, [Salt](https://www.qubes-os.org/doc/salt/) seemed daunting to me at first. It took me some efforts to learn but I love it now! I'm writing this guide for beginners who enjoy an hands-on introduction with examples. As a beginner, [Salt](https://www.qubes-os.org/doc/salt/) seemed daunting to me at first. It took me some efforts to learn but it was worth it! I'm writing this guide for beginners who enjoy an hands-on introduction with examples.
* [unman's notes](https://github.com/unman/notes/blob/master/salt/Index), my first reference whenever I need help with Salt in Qubes * [Salt user guide](https://docs.saltproject.io/salt/user-guide/en/latest/index.html), a complete overview of Salt targeted at beginners * [unman's notes](https://github.com/unman/notes/blob/master/salt/Index), my first reference whenever I need help with Salt in Qubes OS

Revision #51

Edited on
2023-08-31
Edited by user
leo
- https_proxy: http://127.0.0.1:8082 - https_proxy: http://localhost:8082

Revision #50

Edited on
2023-08-31
Edited by user
leo
``` We could also directly target all our templates with: ```sh sudo qubesctl --templates --show-output state.highstate

Revision #49

Edited on
2023-08-31
Edited by user
leo
sudo qubesctl --targets=nonfree --show-output state.sls messaging saltenv=user sudo qubesctl --targets=nonfree --show-output state.sls conferencing saltenv=user

Revision #48

Edited on
2023-08-31
Edited by user
leo
{% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} {% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %}
{% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} {% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %}
{% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} {% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %}
{% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} {% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %}
{% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} {% set gui_user = salt['cmd.shell']('groupmems --list --group qubes') %}

Revision #47

Edited on
2023-08-31
Edited by user
leo
We start by downloading the cryptographic key that signs the Skype repository. From a trusted qube called "disp2956" that is connected to the internet, we run the command: ```sh curl --output skype.asc https://repo.skype.com/data/SKYPE-GPG-KEY ``` We check the file's contents with the command `cat skype.asc` to make sure that the file is not malicious. Once we are completely sure that it is not malicious, we can [copy the file to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running: [details=Make sure to understand the risks of copying files to dom0 before executing this command.] ```sh qvm-run --pass-io disp2956 'cat skype.asc' > skype.asc ``` [/details] We can then convert the file to a GPG keyring format with: ```sh gpg --dearmor --output skype.gpg skype.asc ``` The keyring is ready to be used by Salt, so we can move it under a new directory at `/srv/user_salt/conferencing/skype.gpg`. For practical purposes, we will write our state configuration file under the same directory, at `/srv/user_salt/conferencing/init.sls`. The state configuration file reads: We write our state configuration file `/srv/user_salt/conferencing.sls` as follows:
conferencing--download-key: cmd.run: - name: curl --output /etc/apt/keyrings/skype.asc https://repo.skype.com/data/SKYPE-GPG-KEY - env: - https_proxy: http://127.0.0.1:8082 - creates: - /etc/apt/keyrings/skype.asc
- key_url: salt://conferencing/skype.gpg - key_url: /etc/apt/keyrings/skype.asc
- require: - cmd: conferencing--download-key

Revision #46

Edited on
2023-08-31
Edited by user
leo

Revision #45

Edited on
2023-08-29
Edited by user
leo
Running this state makes Salt create a "conferencing" app qube based on a new template called "nonfree", in which Salt makes sure that Skype is installed through the external repository. To run this state, we target our new "nonfree" template with the command: Running this state makes Salt create a "conferencing" app qube based on a new template called "nonfree", in which Salt makes sure that Skype is installed from its external repository. To run this state, we target our new "nonfree" template with the command:

Revision #44

Edited on
2023-08-29
Edited by user
leo
Note that by default, `cmd.run` makes Salt run commands as root. The command `qvm-appmenus` does not work as root, so we have to make Salt run this command as a regular user. To do so, in the first line of the file we use a templating language called [Jinja](https://jinja.palletsprojects.com/en/3.1.x/templates/) to retrieve our username, we save our username in the `gui_user` variable, and we use this variable when needed. Salt will always execute all the templating instructions between `{}` before running a state configuration file. Note that by default, `cmd.run` makes Salt run commands as root. The command `qvm-appmenus` does not work as root, so we have to make Salt run this command as a regular user. To do so, in the first line of the file we use a templating language called [Jinja](https://jinja.palletsprojects.com/templates/) to retrieve our username, we save our username in the `gui_user` variable, and we use this variable when needed. Salt will always execute all the templating instructions between `{}` before running a state configuration file.
This state configuration file has two parts. In the first part, we wrote the instructions that Salt has to execute while running in the admin qube dom0, while the second part is about installing Telegram, which must be executed in the template debian-12. To have everything in the same file, but ensure that the right part get executed in the right qube, we decided to use a Jinja ["if statement"](https://jinja.palletsprojects.com/en/3.0.x/templates/#if) to modify the state configuration file depending on in what qube Salt is running the instructions for. This state configuration file has two parts. In the first part, we wrote the instructions that Salt has to execute while running in the admin qube dom0, while the second part is about installing Telegram, which must be executed in the template debian-12. To have everything in the same file but ensure that the right part gets executed in the right qube, we decided to use a Jinja ["if statement"](https://jinja.palletsprojects.com/templates/#if) to modify the state configuration file depending on in what qube Salt is running the instructions for.
Similarly, we can also have Salt apply this state targeting both dom0 and debian-12 when running highstate. We add the following to the top file `/srv/user_salt/top.sls`: Similarly as in the previous section, we can have Salt apply this state while targeting both dom0 and debian-12 when running highstate. We add the following to the top file `/srv/user_salt/top.sls`:
As Skype is not from the official repository, we consider that there is a non-zero risk that it compromises the security of the template during its installation process. Because we want to [trust our default templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates), we decide to create a new "nonfree" template to install this proprietary software. As Skype is not in the official repository, we consider that there is a non-zero risk that it compromises the security of the template during its installation process. Because we want to [trust our default templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates), we decide to create a new "nonfree" template to install this proprietary software.
We check the file's contents with the command `cat skype.asc` to make sure that the file is not malicious. Only if we are completely sure that it is not malicious, we can [copy the file to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running: We check the file's contents with the command `cat skype.asc` to make sure that the file is not malicious. Once we are completely sure that it is not malicious, we can [copy the file to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running:
{% if grains['id'] == 'dom0' %}
{% if grains['id'] == 'dom0' %}
# Install Wyng and create the service qube `sys-backup` for storing backups # Install Wyng and create the service qube "sys-backup" for storing backups
# Create a backup and copy it to the archive in `sys-backup` # Create a backup and copy it to the archive in "sys-backup"

Revision #43

Edited on
2023-08-28
Edited by user
leo
- defaults: {{ backup|yaml }} - context: {{ backup|yaml }}

Revision #42

Edited on
2023-08-28
Edited by user
leo
- context: {{ backup|yaml }} - defaults: {{ backup|yaml }}
[details=Tip: For very long operations, we can run Wyng manually to see the progress in real-time.] [details=Tip: For very long operations, we can run Wyng manually to see progress in real-time.]

Revision #41

Edited on
2023-08-28
Edited by user
leo
* The state `configure.sls` creates the backup archive in sys-backup if it doesn't exist, and ensures that all the backed-up qubes defined in the configuration file `map.jinja` are in the archive configuration. This state is automatically included in other states that require it, but we can also run it manually with: * The state `configure.sls` creates the backup archive in sys-backup if it doesn't exist, and ensures that all the backed-up qubes specified in the configuration file `map.jinja` are in the archive configuration. This state is automatically included in other states that require it, but we can also run it manually with:
* The state `clear-cache.sls` shuts down all the backed-up qubes to make sure that there have no program running. It then starts them one by one and removes their cache directory `/home/user/.cache` before shutting them down once again. It is extremely important to clear the cache before making backups, and this is automatically included as part of the backup process when using the other state `send.sls` to make backups. Nevertheless, if necessary we can run this state manually with the command: * The state `clear-cache.sls` shuts down all the backed-up qubes to make sure that there have no program running, then starts them one by one and removes their cache directory `/home/user/.cache` before shutting them down once again. Because it is important to clear the cache before making backups, this step is automatically included as part of the backup process when using the state `send.sls` to make backups. Nevertheless, if needed we can run this state manually with the command:
* The state `send.sls` first applies the state `configure.sls`, then clears the cache of all backed-up qubes by applying `clear-cache.sls`, and finally creates a new backup in the archive in "sys-backup". **This is the state that we'll run the most.** We can run it with: * The state `send.sls` first applies the state `configure.sls`, then clears the cache of all backed-up qubes by applying the state `clear-cache.sls`, and finally creates a new backup in the archive in "sys-backup". **This is the state that we'll run the most.** We can run it with:
* The state `receive.sls` automatically applies the state `configure.sls`, then shuts down all backed-up qubes and overwrites their data with the data contained in the latest backup found in the archive. It can be run with: * The state `receive.sls` automatically applies the state `configure.sls`, then shuts down all the backed-up qubes and overwrites their data with the data contained in the latest backup found in the archive. It can be run with:

Revision #40

Edited on
2023-08-28
Edited by user
leo
The above method downloads the recommended version of Wyng, which is Wing v0.8beta at the time of writing. It might be that some parts of this guide stop working with a more recent version of Wyng, in which case the guide will have to be updated. The above command downloads the latest recommended version of Wyng, which is Wing v0.8beta at the time of writing. It might be that some parts of this guide stop working with a more recent version of Wyng, in which case the guide will have to be updated.
The file `wyng` is now in our home directory in dom0. We could mark this file as executable with the command `chmod +x wyng` and run Wyng directly from the command line, but we won't: we are going to use Salt! The file `wyng` is now in our home directory in dom0. We could mark this file as executable with the command `chmod +x wyng` and run Wyng directly from the command line, but we won't: we are going to use Salt! But first, we have to create a BTRFS subvolume.
When we installed Qubes OS on our machine, we decided to use BTRFS instead of the default partition scheme. To be able to use Wyng with BTRFS, the files that contain the filesystems of our qubes must be located inside of a BTRFS subvolume. This is not the case by default: the filesystems of our qubes are located under `/var/lib/qubes`, which is not a BTRFS subvolume but a regular directory. When we installed Qubes OS on our machine, we decided to use BTRFS instead of the default partition scheme. To be able to use Wyng with BTRFS, the files that contain the filesystems of our qubes must be located inside of a BTRFS subvolume. This is not the case by default: the files that contain the filesystems of our qubes are located under `/var/lib/qubes`, which is not a BTRFS subvolume but a regular directory.
We would like to configure Wyng to create encrypted incremental backups that we will save on our machine in a [service qube](https://www.qubes-os.org/doc/glossary/#service-qube) called "sys-backup". The idea is to back up our qubes regularly and, from time to time, we'll copy the backup archive from sys-backup to some external storage, or upload it to a remote server. We would like to configure Wyng to create encrypted incremental backups that we will save on our machine in a [service qube](https://www.qubes-os.org/doc/glossary/#service-qube) called "sys-backup". The idea is that we'll back up our qubes regularly and, from time to time, we'll copy the backup archive in sys-backup to some external storage, or upload it to a remote server.

Revision #39

Edited on
2023-08-28
Edited by user
leo
It should be noted that a tool called [wyng-util-qubes](https://github.com/tasket/wyng-util-qubes/) is currently being developed that makes it very easy to use Wyng with Qubes OS. One of the advantages of using this tool is that, on top of backing up the contents of our qubes with Wyng, this tool also backs up their configuration. At the time of writing, however, wyng-util-qubes does not yet support installations of Qubes OS with a BTRFS partitioning scheme. For this reason, and because the configuration of our qubes is already saved in our Salt state configuration files, we are going to use Wyng directly instead of wyng-util-qubes. It should be noted that a tool called [wyng-util-qubes](https://github.com/tasket/wyng-util-qubes/) is currently being developed and makes it very easy to use Wyng with Qubes OS. One of the advantages of using this tool is that, on top of backing up the contents of our qubes with Wyng, this tool also backs up their configuration. At the time of writing, however, wyng-util-qubes does not yet support installations of Qubes OS with a BTRFS partitioning scheme. For this reason, and because the configuration of our qubes is already saved in our Salt state configuration files, we are going to use Wyng directly instead of wyng-util-qubes.

Revision #38

Edited on
2023-08-28
Edited by user
leo
{# The passphrase must not contain any single quote character (') #}
'volumes': ['appvms/vault/private.img', 'appvms/messaging/private.img'],
{% set volumes = backup.qubes | map('regex_replace', '(.+)', 'appvms/\\1/private.img') | join(' ') %}
- name: echo '{{ backup.passphrase }}' | wyng arch-init --unattended - name: | echo '{{ backup.passphrase }}' | wyng arch-init --unattended
- name: echo '{{ backup.passphrase }}' | wyng add {{ volumes }} --unattended - name: | echo '{{ backup.passphrase }}' | wyng add {{ backup.volumes|join(' ') }} --unattended
- name: echo '{{ backup.passphrase }}' | wyng send --all --unattended - name: | echo '{{ backup.passphrase }}' | wyng send --all --unattended
- names: {{ backup.qubes }} - names: {{ backup.qubes|yaml }}
- name: echo '{{ backup.passphrase }}' | wyng receive --all --unattended - name: | echo '{{ backup.passphrase }}' | wyng receive --all --unattended

Revision #37

Edited on
2023-08-28
Edited by user
leo
- context: {{ backup }} - context: {{ backup|yaml }}
- names: {{ backup.qubes }} - names: {{ backup.qubes|yaml }}
- names: {{ backup.qubes }} - names: {{ backup.qubes|yaml }}

Revision #36

Edited on
2023-08-28
Edited by user
leo
- context: backup: {{ backup }} - context: {{ backup }}
local = {{ backup.source }} dest = qubes://sys-backup{{ backup.destination }} local = {{ source }} dest = qubes://sys-backup{{ destination }}

Revision #35

Edited on
2023-08-27
Edited by user
leo
{% set passphrase = 'my-backup-passphrase' %} {% set qubes = ['vault', 'messaging'] %} {% set source = '/var/lib/qubes' %} {% set destination = '/home/user/qubes.backup' %} {% set backup = { 'passphrase': 'my-backup-passphrase', 'qubes': ['vault', 'messaging'], 'source': '/var/lib/qubes', 'destination': '/home/user/qubes.backup', } %}
{% from 'backup/map.jinja' import backup %}
- context: backup: {{ backup }}
{% import 'backup/map.jinja' as backup %} {% from 'backup/map.jinja' import backup %}
{% import 'backup/map.jinja' as backup %} {% from 'backup/map.jinja' import backup %}
{% import 'backup/map.jinja' as backup %} {% from 'backup/map.jinja' import backup %}
{% import 'backup/map.jinja' as backup %} {% from 'backup/map.jinja' import backup %}
{%- import 'backup/map.jinja' as backup -%}

Revision #34

Edited on
2023-08-27
Edited by user
leo
This gives us a general configuration file `map.jinja` where we can enter our password, as well as the following Salt states: * The initial state `init.sls` makes sure that Wyng and the python libraries that are required for encryption and compression are installed in dom0, and creates the "sys-backup" service qube. We must run this state at least once before using the other states. This state can be run with: This gives us a general configuration file `map.jinja` where we can enter our password and the list of qubes that we want to include in our backups, as well as the following Salt states: * The initial state `init.sls` makes sure that Wyng and the python libraries that are required for encryption and compression are installed in dom0, and creates the "sys-backup" service qube. We must run this state at least once before using the other states. We can run this state with:
* The state `configure.sls` creates the backup archive in sys-backup if it doesn't exist, and ensures that all of the backed-up qubes defined in the configuration file `map.jinja` are in the archive configuration. This state is automatically included in states that require it, but can be run manually with: * The state `configure.sls` creates the backup archive in sys-backup if it doesn't exist, and ensures that all the backed-up qubes defined in the configuration file `map.jinja` are in the archive configuration. This state is automatically included in other states that require it, but we can also run it manually with:
* The state `clear-cache.sls` shuts down all the backed-up qubes to make sure that there have no running program. It then starts them one by one and removes the cache directory `/home/user/.cache` before shutting them down once again. It is extremely important to clear the cache before making backups, and this is automatically done when using the state `send.sls` to make backups. Nevertheless, this state can be run manually with the command: * The state `clear-cache.sls` shuts down all the backed-up qubes to make sure that there have no program running. It then starts them one by one and removes their cache directory `/home/user/.cache` before shutting them down once again. It is extremely important to clear the cache before making backups, and this is automatically included as part of the backup process when using the other state `send.sls` to make backups. Nevertheless, if necessary we can run this state manually with the command:
* The state `send.sls` first applies the state `configure.sls`, then clears the cache of all backed-up qubes by running the state `clear-cache.sls`, and finally creates a new backup in the archive in "sys-backup". **This is the state that we'll run the most.** We can run this state with: * The state `send.sls` first applies the state `configure.sls`, then clears the cache of all backed-up qubes by applying `clear-cache.sls`, and finally creates a new backup in the archive in "sys-backup". **This is the state that we'll run the most.** We can run it with:
[details=Tip: For very long operations, running Wyng manually displays the backup progress in real-time.] Making backups manually requires performing more actions than simply applying the `send.sls` state file, but it is useful because it shows the real-time output of Wyng during the backup. It can be done by running the following command, preceded by `sudo qubesctl state.sls backup.configure` in case the archive is not yet configured: [details=Tip: For very long operations, we can run Wyng manually to see the progress in real-time.] Making backups manually requires performing more actions than simply applying the `send.sls` state file, but it is useful because it shows the real-time output of Wyng during the backup process. It can be done by running the following command (preceded by `sudo qubesctl state.sls backup.configure` in case the backup archive is not yet configured):
It is also possible to restore a backup manually by running the following command after shuting down all the backed-up qubes manually: It is also possible to restore a backup manually by running the following command after shuting down all the backed-up qubes:
It took me quite a while to write this last part of the guide but I'm quite happy with the result. I tried to write it in a way that is easy to adapt to another Qubes instal. Of course, feel free to ask questions if something needs clarification or doesn't work. Have a nice day.It took me quite a while to write this last part of the guide but I'm quite happy with the result. I tried to write it in a way that is easy to adapt to another Qubes install. Of course, feel free to ask if something needs clarification or doesn't work. Have a nice day.

Revision #33

Edited on
2023-08-27
Edited by user
leo

Revision #32

Edited on
2023-08-27
Edited by user
leo
The entire Wyng program is contained in an executable file that is in the directory that we just created, at `wyng-backup-main/src/wyng`. We can follow the instructions shown on [its project page](https://github.com/tasket/wyng-backup/#verifying-code) to verify the authenticity of this file. Once we trust this file, we can [copy it to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running: The entire Wyng program is contained in the file `wyng-backup-main/src/wyng`, which is in the directory that we just created. We can follow the instructions shown on [the project page](https://github.com/tasket/wyng-backup/#verifying-code) to verify the authenticity of this file. Once we trust this file, we can [copy it to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running:
We use the following commands to create the subvolme: We use the following commands to create a BTRFS subvolme:
1. Shut down all qubes: ```sh qvm-shutdown --all --wait --force ``` 1. Shut down all qubes with `qvm-shutdown --all --wait --force`
3. Create a snapshot of the root subvolume at `/var/lib/qubes`: 3. Create a snapshot of the root subvolume at the location `/var/lib/qubes`:
sudo btrfs sub snap / /var/lib/qubes sudo btrfs subvolume snapshot / /var/lib/qubes
# Install Wyng and create a service qube called `sys-backup` to store backups # Install Wyng and create the service qube `sys-backup` for storing backups
# Remove the cache directory /home/user/.cache in each of the backed-up qubes # Remove the directory /home/user/.cache in each of the backed-up qubes

Revision #31

Edited on
2023-08-27
Edited by user
leo
shopt -s dotglob

Revision #30

Edited on
2023-08-27
Edited by user
leo
It should be noted that a tool called [wyng-util-qubes](https://github.com/tasket/wyng-util-qubes/) is currently being developed that makes it very easy to use Wyng with Qubes OS. One of the advantages of using this tool is that, on top of backing up the contents of qubes like Wyng does, it also backs up all of their configuration. At the time of writing, however, wyng-util-qubes does not yet support installations of Qubes OS with a BTRFS partitioning scheme. For this reason, and because the configuration of our qubes is already saved into our Salt state configuration files, we are going to use Wyng directly in this guide instead of using wyng-util-qubes. It should be noted that a tool called [wyng-util-qubes](https://github.com/tasket/wyng-util-qubes/) is currently being developed that makes it very easy to use Wyng with Qubes OS. One of the advantages of using this tool is that, on top of backing up the contents of our qubes with Wyng, this tool also backs up their configuration. At the time of writing, however, wyng-util-qubes does not yet support installations of Qubes OS with a BTRFS partitioning scheme. For this reason, and because the configuration of our qubes is already saved in our Salt state configuration files, we are going to use Wyng directly instead of wyng-util-qubes.
curl --location https://api.github.com/repos/tasket/wyng-backup/tarball | tar --extract --gzip curl --location https://github.com/tasket/wyng-backup/archive/refs/heads/main.tar.gz | tar --extract --gzip
The entire Wyng program is contained in an executable file that is in the directory that we just created, at `tasket-wyng-backup-e4b988a/src/wyng`. We can follow the instructions shown on [its project page](https://github.com/tasket/wyng-backup/#verifying-code) to verify the authenticity of this file. Once we trust this file, we can [copy it to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running: [details=Note on the version of Wyng used in this guide.] The above method downloads the recommended version of Wyng, which is Wing v0.8beta at the time of writing. It might be that some parts of this guide stop working with a more recent version of Wyng, in which case the guide will have to be updated. [/details] The entire Wyng program is contained in an executable file that is in the directory that we just created, at `wyng-backup-main/src/wyng`. We can follow the instructions shown on [its project page](https://github.com/tasket/wyng-backup/#verifying-code) to verify the authenticity of this file. Once we trust this file, we can [copy it to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running:
qvm-run --pass-io disp8265 'cat tasket-wyng-backup-e4b988a/src/wyng' > wyng qvm-run --pass-io disp8265 'cat wyng-backup-main/src/wyng' > wyng

Revision #29

Edited on
2023-08-27
Edited by user
leo
sudo rmdir /var/lib/qubes-old
[details=Tip: There is another longer and riskier method that does not involve moving files across subvolumes.] [details=Tip: There is a longer and riskier method that does not involve moving files across subvolumes.]
[details=Tip: For very long operations, running Wyng manually displays a real-time output of the backup process.] [details=Tip: For very long operations, running Wyng manually displays the backup progress in real-time.]

Revision #28

Edited on
2023-08-27
Edited by user
leo
[details=A malicious file or qube could compromise your system through this command!] [details=Make sure to understand the risks of copying files to dom0 before executing this command.]
In this part of the guide, we are going to describe how to set up fast incremental backups, using Salt to automate the process. In this part of the guide, we are going to create Salt states that can make fast incremental backups of our qubes.
[Wyng](https://github.com/tasket/wyng-backup/) is a backup software that we can use to make incremental qubes backups in a very efficient manner. The creator of Wyng made an topic on the forum with detailed explanations of how it works: https://forum.qubes-os.org/t/ann-wyng-incremental-backup-new-version/4303 To use Wyng, we first have to copy it to dom0. To do so, can we download and extract the [latest release](https://github.com/tasket/wyng-backup/tags) in a trusted qube called "disp8265" with the command: [Wyng](https://github.com/tasket/wyng-backup/) is a backup software that we can use to make incremental backups of the contents of our qubes in a very efficient manner. Its project page gives a detailed explanation of how it works. It should be noted that a tool called [wyng-util-qubes](https://github.com/tasket/wyng-util-qubes/) is currently being developed that makes it very easy to use Wyng with Qubes OS. One of the advantages of using this tool is that, on top of backing up the contents of qubes like Wyng does, it also backs up all of their configuration. At the time of writing, however, wyng-util-qubes does not yet support installations of Qubes OS with a BTRFS partitioning scheme. For this reason, and because the configuration of our qubes is already saved into our Salt state configuration files, we are going to use Wyng directly in this guide instead of using wyng-util-qubes. To use Wyng, we first have to copy it to dom0. To do so, can we download and extract the main branch of its repository in a trusted qube called "disp8265" with the command:
curl --location https://github.com/tasket/wyng-backup/archive/refs/tags/v0.8beta1.tar.gz | tar --extract --gzip curl --location https://api.github.com/repos/tasket/wyng-backup/tarball | tar --extract --gzip
The entire Wyng program is contained in an executable file that is in the directory that we just created, at `wyng-backup-0.8beta1/src/wyng`. Once we completely trust this file, we can [copy it to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running: [details=A malicious file or qube could compromise your system through this command!] The entire Wyng program is contained in an executable file that is in the directory that we just created, at `tasket-wyng-backup-e4b988a/src/wyng`. We can follow the instructions shown on [its project page](https://github.com/tasket/wyng-backup/#verifying-code) to verify the authenticity of this file. Once we trust this file, we can [copy it to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running: [details=Make sure to understand the risks of copying files to dom0 before executing this command.]
qvm-run --pass-io disp8265 'cat wyng-backup-0.8beta1/src/wyng' > wyng qvm-run --pass-io disp8265 'cat tasket-wyng-backup-e4b988a/src/wyng' > wyng
When we installed Qubes OS on our machine, we decided to use BTRFS instead of the default partition scheme. To be able to use Wyng with BTRFS, the files that contain the filesystems of our qubes must be located inside of a BTRFS subvolume. This is not the case by default: the filesystems of our qubes are located under `/var/lib/qubes`, which is not a BTRFS subvolume but a regular directory. To turn this directory into a subvolme, we can use a method proposed in the [linux-btrfs mailing list](https://www.spinics.net/lists/linux-btrfs/msg33253.html): [details=Any mistake here will permanently destroy you Qubes install!] When we installed Qubes OS on our machine, we decided to use BTRFS instead of the default partition scheme. To be able to use Wyng with BTRFS, the files that contain the filesystems of our qubes must be located inside of a BTRFS subvolume. This is not the case by default: the filesystems of our qubes are located under `/var/lib/qubes`, which is not a BTRFS subvolume but a regular directory. We use the following commands to create the subvolme: ```sh qvm-shutdown --all --wait --force sudo mv /var/lib/qubes /var/lib/qubes-old sudo btrfs subvolume create /var/lib/qubes sudo mv /var/lib/qubes-old/* /var/lib/qubes ``` [details=Tip: There is another longer and riskier method that does not involve moving files across subvolumes.]
2. Rename `/var/lib/qubes` to `/var/lib/qubes.old` 3. Create a snapshot of the root subvolume in `/var/lib/qubes`: 2. Rename `/var/lib/qubes` to `/var/lib/qubes-old` 3. Create a snapshot of the root subvolume at `/var/lib/qubes`:
4. Delete everything in the new subvolume `/var/lib/qubes` except the directory `/var/lib/qubes/var/lib/qubes.old` 5. Move the contents of `/var/lib/qubes/var/lib/qubes.old` to `/var/lib/qubes` (don't forget the hidden files) 6. Delete the now empty directory `/var/lib/qubes/var/lib/qubes.old` and its empty parents 4. Delete everything in the new subvolume `/var/lib/qubes` except the directory `/var/lib/qubes/var/lib/qubes-old` 5. Move the contents of `/var/lib/qubes/var/lib/qubes-old` to `/var/lib/qubes` (don't forget the hidden files) 6. Delete the now empty directory `/var/lib/qubes/var/lib/qubes-old` and its empty parents
* [wyng-util-qubes](https://github.com/tasket/wyng-util-qubes/), a tool that makes it easy to use Wyng with Qubes OS

Revision #27

Edited on
2023-08-26
Edited by user
leo
The `wyng` file is now in our home directory in dom0. We could now mark this file as executable with the command `chmod +x wyng` and run Wyng directly from the command line, but we won't: we are going to use Salt! The file `wyng` is now in our home directory in dom0. We could mark this file as executable with the command `chmod +x wyng` and run Wyng directly from the command line, but we won't: we are going to use Salt!
When we installed Qubes OS on our machine, we decided to use BTRFS instead of the default partition scheme. To be able to use Wyng with BTRFS, the files that contain the filesystems of our qubes must be located inside of a BTRFS subvolume. This is not the case by default: the filesystems of our qubes are located under `/var/lib/qubes`, which is not a BTRFS subvolume but a regular directory. To turn this directory into a subvolme, we can use a method from the [linux-btrfs mailing list](https://www.spinics.net/lists/linux-btrfs/msg33253.html): [details=Any mistake here would permanently destroy you Qubes install!] When we installed Qubes OS on our machine, we decided to use BTRFS instead of the default partition scheme. To be able to use Wyng with BTRFS, the files that contain the filesystems of our qubes must be located inside of a BTRFS subvolume. This is not the case by default: the filesystems of our qubes are located under `/var/lib/qubes`, which is not a BTRFS subvolume but a regular directory. To turn this directory into a subvolme, we can use a method proposed in the [linux-btrfs mailing list](https://www.spinics.net/lists/linux-btrfs/msg33253.html): [details=Any mistake here will permanently destroy you Qubes install!]
3. Create a snapshot of the root subvolume at `/var/lib/qubes`: 3. Create a snapshot of the root subvolume in `/var/lib/qubes`:
4. Delete everything in the new subvolume `/var/lib/qubes`, except the directory `/var/lib/qubes/var/lib/qubes.old` 4. Delete everything in the new subvolume `/var/lib/qubes` except the directory `/var/lib/qubes/var/lib/qubes.old`
{% set destination = 'qubes://sys-backup/home/user/qubes.backup' %} {% set destination = '/home/user/qubes.backup' %}
- provides-network: True # "service qube" (see qubes issue #7298) - provides-network: True # "service qube" (see Qubes issue #7298)
- qvm-run sys-backup test -d /home/user/qubes.backup - qvm-run sys-backup test -d {{ backup.destination }}
- cmd: rm --force --recursive /home/user/.cache - cmd: rm --recursive --force /home/user/.cache
This is the Wyng executable file that we have copied to the dom0 in [section 3.1](#h-31-downloading-wyng-15). This is the Wyng executable file that we have copied to dom0 in [section 3.1](#h-31-downloading-wyng-15).
{#- This file configures the default options for Wyng commands -#}
dest = {{ backup.destination }} dest = qubes://sys-backup{{ backup.destination }}
* [Wyng repository](https://github.com/tasket/wyng-backup), with detailed explanations for each command and their arguments * [Wyng repository](https://github.com/tasket/wyng-backup), it gives detailed explanations for each command and their arguments
* [Salt docs on Jinja](https://docs.saltproject.io/en/latest/topics/jinja/index.html), with descriptions of each built-in filter such as `regex_replace` * [Salt docs on Jinja](https://docs.saltproject.io/en/latest/topics/jinja/index.html), they include descriptions of all the built-in filters such as `regex_replace`

Revision #26

Edited on
2023-08-26
Edited by user
leo
## Part 3: Backing up qubes One of the biggest advantages of using Salt with Qubes OS is that we just need to copy and run our state configuration files and we can completely recreate our system. Saving those files would however not be sufficient for a backup, because that would not contain any our personal data. We could use the official [Qubes Backup](https://www.qubes-os.org/doc/how-to-back-up-restore-and-migrate/) tool to create full backups of our qubes, but [as of now](https://github.com/QubesOS/qubes-issues/issues/858) this tool does not support creating [incremental backups](https://en.wikipedia.org/wiki/Incremental_backup), which make the backup proccess much more performant. ## Part 3: Backing up Qubes One of the biggest advantages of using Salt with Qubes OS is that we would just need to copy and run our state configuration files to completely recreate our system. Saving those files would however not be sufficient for a backup, because that would not contain any our personal data. We could use the official [Qubes Backup](https://www.qubes-os.org/doc/how-to-back-up-restore-and-migrate/) tool to create full backups of our qubes, but [as of now](https://github.com/QubesOS/qubes-issues/issues/858) this tool does not support creating [incremental backups](https://en.wikipedia.org/wiki/Incremental_backup), which make the backup process much more performant.
[Wyng](https://github.com/tasket/wyng-backup/) is a backup software that we can use to make incremental qubes backups in a very efficient manner. There is already an topic on the forum with detailed detailed explanations on how it works: [Wyng](https://github.com/tasket/wyng-backup/) is a backup software that we can use to make incremental qubes backups in a very efficient manner. The creator of Wyng made an topic on the forum with detailed explanations of how it works:
The entire Wyng program is contained in an executable file that is in the directory that we just created, at `wyng-backup-0.8beta1/src/wyng`. If we completely trust this file, we can then [copy it to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running: The entire Wyng program is contained in an executable file that is in the directory that we just created, at `wyng-backup-0.8beta1/src/wyng`. Once we completely trust this file, we can [copy it to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running:
### 3.3 Configuring local backups ### 3.3 Making local backups
### 3.4 Configuring remote backups ### 3.4 Making remote backups

Revision #25

Edited on
2023-08-26
Edited by user
leo
> >
[details=Note on `saltenv=user`] [details=Note on "saltenv=user"]
[details=Note on the `{}` characters] [details=Note on the "{}" characters]
The next part of this guide will be about creating new templates and installing packages in them. See you soon! The next part of this guide will be about creating new templates and installing packages in them.
{% if grains['id'] == 'dom0' %}
{% if grains['id'] == 'dom0' %}
There you go! As we need to run the install process in the debian-12 template, we have to [target](https://forum.qubes-os.org/t/qubes-salt-beginners-guide/20126#h-13-targeting-qubes-5) debian-12 when we make Salt execute this state: `sudo qubesctl --targets=debian-12 --show-output state.sls messaging saltenv=user`. [details=Note on the `{% ... %}` syntax] There you go! As we need to run the install process in the debian-12 template, we have to [target](#h-13-targeting-qubes-5) debian-12 when we make Salt execute this state: `sudo qubesctl --targets=debian-12 --show-output state.sls messaging saltenv=user`. [details=Note on the "{% ... %}" syntax]
In the next part of this guide, we will learn how to make Salt perform automated backups of our qubes with [Wyng](https://github.com/tasket/wyng-backup)!In the next part of this guide, we will learn how to make Salt perform automated backups of our qubes with [Wyng](https://github.com/tasket/wyng-backup). ## Part 3: Backing up qubes One of the biggest advantages of using Salt with Qubes OS is that we just need to copy and run our state configuration files and we can completely recreate our system. Saving those files would however not be sufficient for a backup, because that would not contain any our personal data. We could use the official [Qubes Backup](https://www.qubes-os.org/doc/how-to-back-up-restore-and-migrate/) tool to create full backups of our qubes, but [as of now](https://github.com/QubesOS/qubes-issues/issues/858) this tool does not support creating [incremental backups](https://en.wikipedia.org/wiki/Incremental_backup), which make the backup proccess much more performant. In this part of the guide, we are going to describe how to set up fast incremental backups, using Salt to automate the process. ### 3.1 Downloading Wyng [Wyng](https://github.com/tasket/wyng-backup/) is a backup software that we can use to make incremental qubes backups in a very efficient manner. There is already an topic on the forum with detailed detailed explanations on how it works: https://forum.qubes-os.org/t/ann-wyng-incremental-backup-new-version/4303 To use Wyng, we first have to copy it to dom0. To do so, can we download and extract the [latest release](https://github.com/tasket/wyng-backup/tags) in a trusted qube called "disp8265" with the command: ```sh curl --location https://github.com/tasket/wyng-backup/archive/refs/tags/v0.8beta1.tar.gz | tar --extract --gzip ``` The entire Wyng program is contained in an executable file that is in the directory that we just created, at `wyng-backup-0.8beta1/src/wyng`. If we completely trust this file, we can then [copy it to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running: [details=A malicious file or qube could compromise your system through this command!] ```sh qvm-run --pass-io disp8265 'cat wyng-backup-0.8beta1/src/wyng' > wyng ``` [/details] The `wyng` file is now in our home directory in dom0. We could now mark this file as executable with the command `chmod +x wyng` and run Wyng directly from the command line, but we won't: we are going to use Salt! ### 3.2 Creating a BTRFS subvolume When we installed Qubes OS on our machine, we decided to use BTRFS instead of the default partition scheme. To be able to use Wyng with BTRFS, the files that contain the filesystems of our qubes must be located inside of a BTRFS subvolume. This is not the case by default: the filesystems of our qubes are located under `/var/lib/qubes`, which is not a BTRFS subvolume but a regular directory. To turn this directory into a subvolme, we can use a method from the [linux-btrfs mailing list](https://www.spinics.net/lists/linux-btrfs/msg33253.html): [details=Any mistake here would permanently destroy you Qubes install!] 1. Shut down all qubes: ```sh qvm-shutdown --all --wait --force ``` 2. Rename `/var/lib/qubes` to `/var/lib/qubes.old` 3. Create a snapshot of the root subvolume at `/var/lib/qubes`: ```sh sudo btrfs sub snap / /var/lib/qubes ``` 4. Delete everything in the new subvolume `/var/lib/qubes`, except the directory `/var/lib/qubes/var/lib/qubes.old` 5. Move the contents of `/var/lib/qubes/var/lib/qubes.old` to `/var/lib/qubes` (don't forget the hidden files) 6. Delete the now empty directory `/var/lib/qubes/var/lib/qubes.old` and its empty parents [/details] Once this is done, the output of the command `sudo btrfs subvolume list /` should contain a line that ends with `/var/lib/qubes`, and our system should function normally. ### 3.3 Configuring local backups We would like to configure Wyng to create encrypted incremental backups that we will save on our machine in a [service qube](https://www.qubes-os.org/doc/glossary/#service-qube) called "sys-backup". The idea is to back up our qubes regularly and, from time to time, we'll copy the backup archive from sys-backup to some external storage, or upload it to a remote server. We create the following files: [details=/srv/user_salt/backup/map.jinja] ```jinja {# This file holds the backup passphrase and general configuration #} {% set passphrase = 'my-backup-passphrase' %} {% set qubes = ['vault', 'messaging'] %} {% set source = '/var/lib/qubes' %} {% set destination = 'qubes://sys-backup/home/user/qubes.backup' %} ``` [/details] [details=/srv/user_salt/backup/init.sls] ```yaml # Install Wyng and create a service qube called `sys-backup` to store backups {% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} backup--install-dependencies: pkg.installed: - pkgs: - python3-pycryptodomex - python3-zstd backup--install-wyng: file.managed: - names: - /usr/local/bin/wyng: - source: salt://backup/files/wyng - mode: 755 - /etc/wyng/wyng.ini: - source: salt://backup/files/wyng.ini - template: jinja - makedirs: True - require: - pkg: backup--install-dependencies backup--create-service-qube: qvm.vm: - name: sys-backup - present: - template: debian-12 - label: yellow - prefs: - template: debian-12 - label: yellow - provides-network: True # "service qube" (see qubes issue #7298) - features: - set: - menu-items: org.gnome.Terminal.desktop org.gnome.Nautilus.desktop - require: - file: backup--install-wyng backup--update-app-menu: cmd.run: - name: qvm-appmenus --update sys-backup - runas: {{ gui_user }} - require: - qvm: backup--create-service-qube ``` [/details] [details=/srv/user_salt/backup/configure.sls] ```yaml # Create a backup archive and add the backed-up qubes to its configuration {% import 'backup/map.jinja' as backup %} {% set volumes = backup.qubes | map('regex_replace', '(.+)', 'appvms/\\1/private.img') | join(' ') %} backup.configure--create-archive: cmd.run: - name: echo '{{ backup.passphrase }}' | wyng arch-init --unattended - unless: - qvm-run sys-backup test -d /home/user/qubes.backup backup.configure--add-volumes: cmd.run: - name: echo '{{ backup.passphrase }}' | wyng add {{ volumes }} --unattended - require: - cmd: backup.configure--create-archive ``` [/details] [details=/srv/user_salt/backup/clear-cache.sls] ```yaml # Remove the cache directory /home/user/.cache in each of the backed-up qubes {% import 'backup/map.jinja' as backup %} backup.clear-cache--shutdown-app-qubes: qvm.shutdown: - names: {{ backup.qubes }} backup.clear-cache--clear-cache: qvm.vm: - names: {{ backup.qubes }} - actions: - run - shutdown - run: - cmd: rm --force --recursive /home/user/.cache - shutdown: [] - require: - qvm: backup.clear-cache--shutdown-app-qubes ``` [/details] [details=/srv/user_salt/backup/send.sls] ```yaml # Create a backup and copy it to the archive in `sys-backup` {% import 'backup/map.jinja' as backup %} include: - backup.configure - backup.clear-cache backup.send--send-backup: cmd.run: - name: echo '{{ backup.passphrase }}' | wyng send --all --unattended - require: - cmd: backup.configure--add-volumes - qvm: backup.clear-cache--clear-cache backup.send--shutdown-service-qube: qvm.shutdown: - name: sys-backup - require: - cmd: backup.send--send-backup ``` [/details] [details=/srv/user_salt/backup/receive.sls] ```yaml # Overwrite current data with the most recent backup from the archive {% import 'backup/map.jinja' as backup %} include: - backup.configure backup.receive--shutdown-app-qubes: qvm.shutdown: - names: {{ backup.qubes }} - require: - cmd: backup.configure--add-volumes backup.receive--receive-backup: cmd.run: - name: echo '{{ backup.passphrase }}' | wyng receive --all --unattended - require: - qvm: backup.receive--shutdown-app-qubes backup.receive--shutdown-service-qube: qvm.shutdown: - name: sys-backup - require: - cmd: backup.receive--receive-backup ``` [/details] [details=/srv/user_salt/backup/files/wyng] This is the Wyng executable file that we have copied to the dom0 in [section 3.1](#h-31-downloading-wyng-15). [/details] [details=/srv/user_salt/backup/files/wyng.ini] ```ini {%- import 'backup/map.jinja' as backup -%} [var-global-default] local = {{ backup.source }} dest = {{ backup.destination }} ``` [/details] This gives us a general configuration file `map.jinja` where we can enter our password, as well as the following Salt states: * The initial state `init.sls` makes sure that Wyng and the python libraries that are required for encryption and compression are installed in dom0, and creates the "sys-backup" service qube. We must run this state at least once before using the other states. This state can be run with: ```sh sudo qubesctl state.sls backup saltenv=user ``` * The state `configure.sls` creates the backup archive in sys-backup if it doesn't exist, and ensures that all of the backed-up qubes defined in the configuration file `map.jinja` are in the archive configuration. This state is automatically included in states that require it, but can be run manually with: ```sh sudo qubesctl state.sls backup.configure saltenv=user ``` * The state `clear-cache.sls` shuts down all the backed-up qubes to make sure that there have no running program. It then starts them one by one and removes the cache directory `/home/user/.cache` before shutting them down once again. It is extremely important to clear the cache before making backups, and this is automatically done when using the state `send.sls` to make backups. Nevertheless, this state can be run manually with the command: ```sh sudo qubesctl state.sls backup.clear-cache saltenv=user ``` * The state `send.sls` first applies the state `configure.sls`, then clears the cache of all backed-up qubes by running the state `clear-cache.sls`, and finally creates a new backup in the archive in "sys-backup". **This is the state that we'll run the most.** We can run this state with: ```sh sudo qubesctl state.sls backup.send saltenv=user ``` * The state `receive.sls` automatically applies the state `configure.sls`, then shuts down all backed-up qubes and overwrites their data with the data contained in the latest backup found in the archive. It can be run with: ```sh sudo qubesctl state.sls backup.receive saltenv=user ``` [details=Tip: For very long operations, running Wyng manually displays a real-time output of the backup process.] Making backups manually requires performing more actions than simply applying the `send.sls` state file, but it is useful because it shows the real-time output of Wyng during the backup. It can be done by running the following command, preceded by `sudo qubesctl state.sls backup.configure` in case the archive is not yet configured: ```sh sudo qubesctl state.sls backup.clear-cache && sudo wyng send --all ``` It is also possible to restore a backup manually by running the following command after shuting down all the backed-up qubes manually: ```sh sudo wyng receive --all ``` [/details] ### 3.4 Configuring remote backups Coming soon! ### 3.5 Useful links * [Wyng repository](https://github.com/tasket/wyng-backup), with detailed explanations for each command and their arguments * [Jinja templating docs](https://jinja.palletsprojects.com/templates/), all the syntax and semantics of the Jinja templating engine * [Salt docs on Jinja](https://docs.saltproject.io/en/latest/topics/jinja/index.html), with descriptions of each built-in filter such as `regex_replace` It took me quite a while to write this last part of the guide but I'm quite happy with the result. I tried to write it in a way that is easy to adapt to another Qubes instal. Of course, feel free to ask questions if something needs clarification or doesn't work. Have a nice day.

Revision #24

Edited on
2023-08-22
Edited by user
leo

Revision #23

Edited on
2023-08-05
Edited by user
leo
### 2.2 Installing new trusted apps ### 2.2 Installing new apps

Revision #22

Edited on
2023-08-05
Edited by user
leo
[details=A malicious file could compromise your system through this command!] [details=A malicious file or qube could compromise your system through this command!]
[details=Tip: Here is what our top file would look like if we activated all the states from this guide so far.] We can now run highstate with the command: ```sh sudo qubesctl --targets=nonfree --show-output state.highstate ``` [details=Tip: Here is what our top file would look like if we would include all the states from this guide so far.]
With this top file, would run highstate with the command: With this top file, we would run highstate with:

Revision #21

Edited on
2023-08-05
Edited by user
leo

Revision #20

Edited on
2023-08-05
Edited by user
leo
We can write the top file `/srv/user_salt/top.sls` as follows: We can write the top file `/srv/user_salt/top.sls` as follows:
``` ```yaml
This state configuration file has two parts. In the first part, we wrote the instructions that Salt has to execute while running in the admin qube dom0, while the second part is about installing Telegram, which must be executed in the template debian-12. To have everything in the same file, but ensure that the right part get executed in the right qube, we decided to use a Jinja ["if statement"](https://jinja.palletsprojects.com/en/3.0.x/templates/#if) to modify the state configuration file depending on in what qube Salt is running from. This state configuration file has two parts. In the first part, we wrote the instructions that Salt has to execute while running in the admin qube dom0, while the second part is about installing Telegram, which must be executed in the template debian-12. To have everything in the same file, but ensure that the right part get executed in the right qube, we decided to use a Jinja ["if statement"](https://jinja.palletsprojects.com/en/3.0.x/templates/#if) to modify the state configuration file depending on in what qube Salt is running the instructions for.
``` ```yaml
Because Skype is not from the official repository, we consider that there is a non-zero risk that it compromises the security of the template during its installation process. Because we want to [trust our default templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates), we decide to create a new "nonfree" template to install proprietary software. We start by downloading the cryptographic key that signs the Skype repository. From a trusted qube called "disp2956" and that is connected to the internet, we run the command: As Skype is not from the official repository, we consider that there is a non-zero risk that it compromises the security of the template during its installation process. Because we want to [trust our default templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates), we decide to create a new "nonfree" template to install this proprietary software. We start by downloading the cryptographic key that signs the Skype repository. From a trusted qube called "disp2956" that is connected to the internet, we run the command:
For practical purposes, we will write our state configuration file under the same directory, at `/srv/user_salt/conferencing/init.sls`. The state configuration file file reads: For practical purposes, we will write our state configuration file under the same directory, at `/srv/user_salt/conferencing/init.sls`. The state configuration file reads:
```bash ```sh
``` With this top file, would run highstate with the command: ```sh sudo qubesctl --targets=debian-12,nonfree --show-output state.highstate
I tried to be as concise as I could. Please let me know if you have any questions! Here are some links if you'd like to go further. I tried to be as concise as I could. Please let me know if you have any further questions! Here are some related links.

Revision #19

Edited on
2023-08-05
Edited by user
leo

Revision #18

Edited on
2023-08-05
Edited by user
leo
# Part 1: Creating our first qubes # Qubes Salt Beginner's Guide ## Part 1: Creating our first qubes
## 1.1 Creating personal state configuration directories ### 1.1 Creating personal state configuration directories
> ### `qubes.user-dirs` > #### `qubes.user-dirs`
## 1.2 The top file and running highstate ### 1.2 The top file and running highstate
## 1.3 Targeting qubes ### 1.3 Targeting qubes
## 1.4. Creating a qube with Salt ### 1.4. Creating a qube with Salt
## 1.5 Creating a disconnected qube ### 1.5 Creating a disconnected qube
## Useful links ### 1.6 Useful links
# Part 2: Apps and templates ## Part 2: Apps and templates
## 2.1 Activating pre-installed apps ### 2.1 Activating pre-installed apps
## 2.2 Installing new trusted apps ### 2.2 Installing new trusted apps
There you go! As we need to run the install process in the debian-12 template, we have to [target](https://forum.qubes-os.org/t/qubes-salt-beginners-guide/20126#h-13-targeting-qubes-4) debian-12 when we make Salt execute this state: `sudo qubesctl --targets=debian-12 --show-output state.sls messaging saltenv=user`. There you go! As we need to run the install process in the debian-12 template, we have to [target](https://forum.qubes-os.org/t/qubes-salt-beginners-guide/20126#h-13-targeting-qubes-5) debian-12 when we make Salt execute this state: `sudo qubesctl --targets=debian-12 --show-output state.sls messaging saltenv=user`.
## 2.3 Creating a "non-free" template ### 2.3 Creating a "non-free" template
## Useful links ### 2.4 Useful links

Revision #17

Edited on
2023-08-05
Edited by user
leo
## 2.1 Creating a qube with new pre-installed apps ## 2.1 Activating pre-installed apps
## 2.2 Creating a qube with new apps from the official repos ## 2.2 Installing new trusted apps
## 2.3 Creating a qube with new apps from external sources ## 2.3 Creating a "non-free" template
Because this software is not from the official repository, we consider that there is a non-zero risk that the software compromises the security of its qube during its installation process. Because we want to [trust our default templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates), we choose to create a new, different template to install this non-free software. Because Skype is not from the official repository, we consider that there is a non-zero risk that it compromises the security of the template during its installation process. Because we want to [trust our default templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates), we decide to create a new "nonfree" template to install proprietary software.

Revision #16

Edited on
2023-08-05
Edited by user
leo

Revision #15

Edited on
2023-08-04
Edited by user
leo
There you go! As we need to run the install process in the debian-12 template, we need to add debian-12 as a target when we make Salt execute this state: `sudo qubesctl --targets=debian-12 --show-output state.sls messaging saltenv=user`. [details=Note on the `{% ... %}` notation] There you go! As we need to run the install process in the debian-12 template, we have to [target](https://forum.qubes-os.org/t/qubes-salt-beginners-guide/20126#h-13-targeting-qubes-4) debian-12 when we make Salt execute this state: `sudo qubesctl --targets=debian-12 --show-output state.sls messaging saltenv=user`. [details=Note on the `{% ... %}` syntax]
Similarly, we can have Salt apply this state in both dom0 and debian-12 when running highstate by adding the following to the top file `/srv/user_salt/top.sls`: Similarly, we can also have Salt apply this state targeting both dom0 and debian-12 when running highstate. We add the following to the top file `/srv/user_salt/top.sls`:
This makes the command `sudo qubesctl --targets=debian-12 --show-output state.highstate` automatically create a messaging qube with Telegram as part of its app menu This makes the command `sudo qubesctl --targets=debian-12 --show-output state.highstate` automatically create a messaging qube with Telegram as part of its app menu.
Because this software is not from the official repository, we consider that there is a non-zero risk that this software compromises the security of its qube during its installation process. Because we want to [trust our default templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates), we will create a new, different template to install this non-free software. We start by downloading the cryptographic key that signs the Skype repository. From a trusted qube called "disp2956" that is connected to the internet, we run the command: Because this software is not from the official repository, we consider that there is a non-zero risk that the software compromises the security of its qube during its installation process. Because we want to [trust our default templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates), we choose to create a new, different template to install this non-free software. We start by downloading the cryptographic key that signs the Skype repository. From a trusted qube called "disp2956" and that is connected to the internet, we run the command:
curl --output skype.asc https://repo.skype.com/data/KSYPE-GPG-KEY curl --output skype.asc https://repo.skype.com/data/SKYPE-GPG-KEY
We can then convert the file to a GPG keyring with: We can then convert the file to a GPG keyring format with:
For practical purposes, we will write our state configuration file under the same directory, at `/srv/user_salt/conferencing/init.sls` with the following: For practical purposes, we will write our state configuration file under the same directory, at `/srv/user_salt/conferencing/init.sls`. The state configuration file file reads:
Running this state makes Salt create a "conferencing" app qube based on a new template called "nonfree", in which Salt makes sure that Skype is installed, through an external repository. To run this state, we target our new "nonfree" template with the command `sudo qubesctl --targets=nonfree --show-output state.sls messaging saltenv=user`. Let's add this state to the top file, so that it is applied automatically when running highstate! We add to our top file `/srv/user_salt/top.sls`: ``` Running this state makes Salt create a "conferencing" app qube based on a new template called "nonfree", in which Salt makes sure that Skype is installed through the external repository. To run this state, we target our new "nonfree" template with the command: ```bash sudo qubesctl --targets=nonfree --show-output state.sls messaging saltenv=user ``` Let's add this state to the top file, so that it is applied automatically when we run highstate! At the end of the top file `/srv/user_salt/top.sls`, we write: ```yaml
- salty
- salty
I tried to go to the point. Please let me know if you have any questions! Here are some links if you'd like to go further. * [Qubes docs on how to install software](https://www.qubes-os.org/doc/how-to-install-software/) I tried to be as concise as I could. Please let me know if you have any questions! Here are some links if you'd like to go further. * [Qubes docs on installing software](https://www.qubes-os.org/doc/how-to-install-software/)

Revision #14

Edited on
2023-08-04
Edited by user
leo

Revision #13

Edited on
2023-08-04
Edited by user
leo
# Qubes Salt Beginner's Guide
## Part 1: Creating our first qubes # Part 1: Creating our first qubes
### 1.1 Creating personal state configuration directories ## 1.1 Creating personal state configuration directories
> #### `qubes.user-dirs` > ### `qubes.user-dirs`
### 1.2 The top file and running highstate ## 1.2 The top file and running highstate
### 1.3 Targeting qubes ## 1.3 Targeting qubes
### 1.4. Example: Creating a qube with Salt ## 1.4. Creating a qube with Salt
### 1.5 Example: Creating a disconnected qube ## 1.5 Creating a disconnected qube
### Useful links ## Useful links
## Part 2: Apps and templates # Part 2: Apps and templates
### 2.1 Example: Creating a qube with new pre-installed apps ## 2.1 Creating a qube with new pre-installed apps
### 2.2 Example: Creating a qube with new apps from the official repos ## 2.2 Creating a qube with new apps from the official repos
### 2.3 Example: Creating a qube with new apps from external sources ## 2.3 Creating a qube with new apps from external sources
### Useful links ## Useful links I tried to go to the point. Please let me know if you have any questions! Here are some links if you'd like to go further.
* [extrepo-data](https://salsa.debian.org/extrepo-team/extrepo-data), a list of external repositories for many apps that are not in the official repositories* [extrepo-data](https://salsa.debian.org/extrepo-team/extrepo-data), a list of external repositories for many apps that are not in the official repositories In the next part of this guide, we will learn how to make Salt perform automated backups of our qubes with [Wyng](https://github.com/tasket/wyng-backup)!

Revision #12

Edited on
2023-08-04
Edited by user
leo
# Part 1: Creating our first qubes # Qubes Salt Beginner's Guide <div data-theme-toc="true"></div> ## Part 1: Creating our first qubes
## 1. Creating personal state configuration directories ### 1.1 Creating personal state configuration directories
> ### `qubes.user-dirs` > #### `qubes.user-dirs`
## 2. The top file and running highstate ### 1.2 The top file and running highstate
## 3. Targeting qubes ### 1.3 Targeting qubes
## 4. Example: Creating a qube with Salt ### 1.4. Example: Creating a qube with Salt
## 5. Example: Creating a disconnected qube We have a [template](https://www.qubes-os.org/doc/glossary/#template) called debian-11. We would like Salt to create a green qube named "disconnected" based on this template, but that has no web browser and no internet access. We write the state configuration file `/srv/user_salt/disconnected.sls` as follows: ### 1.5 Example: Creating a disconnected qube We have a template called debian-11. We would like Salt to create a green qube named "disconnected" based on this template, but that has no web browser and no internet access. We write the state configuration file `/srv/user_salt/disconnected.sls` as follows:
- menu-items: 'org.gnome.Terminal.desktop org.gnome.Nautilus.desktop' - menu-items: org.gnome.Terminal.desktop org.gnome.Nautilus.desktop
- name: 'qvm-appmenus --update disconnected' - name: qvm-appmenus --update disconnected
Great! Now, the command `sudo qubesctl state.highstate` will also automatically create our disconnected qube. ## Useful links Great! Now, the command `sudo qubesctl state.highstate` will automatically create our disconnected qube. [details=Tip: How to make Salt create both "salty" and "disconnected" when we run highstate?] We can write the top file `/srv/user_salt/top.sls` as follows: ```yaml user: dom0: - salty - disconnected ``` [/details] ### Useful links
The next part of this guide will be about creating new templates and installing packages in them. See you soon!The next part of this guide will be about creating new templates and installing packages in them. See you soon! ## Part 2: Apps and templates In this part we'll learn how use Salt to make qubes with [new software](https://www.qubes-os.org/doc/how-to-install-software/) (including apps that are not in the official repositories!), and create new templates. ### 2.1 Example: Creating a qube with new pre-installed apps We have a [template](https://www.qubes-os.org/doc/glossary/#template) called debian-12. We would like Salt to create a "vault" qube based on debian-12 that is never connected to the internet, and that we will only use for the app KeepassXC. Luckily, KeepassXC comes pre-installed in the template debian-12, so we can simply tell Salt to make it available in the app menu. We write our state configuration file `/srv/user_salt/vault.sls` as follows: ```yaml {% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} vault--create-qube: qvm.vm: - name: vault - present: - template: debian-12 - label: black - prefs: - label: black - netvm: none - features: - set: - menu-items: org.keepassxc.KeePassXC.desktop org.gnome.Terminal.desktop vault--update-app-menu: cmd.run: - name: qvm-appmenus --update vault - runas: {{ gui_user }} - require: - qvm: vault--create-qube ``` As a result, running `sudo qubesctl state.sls vault saltenv=user` will make Salt create the vault qube if it's not there, and make sure that it has KeePassXC in its app menu. To make things easier, we would like Salt to automatically take care of the vault when we run highstate. We write the following in the top file `/srv/user_salt/top.sls`: ``` user: dom0: - vault ``` The command `sudo qubesctl state.highstate` will now automatically run the "vault" state. ### 2.2 Example: Creating a qube with new apps from the official repos We would like to have a "messaging" qube for communicating with our friends through an app called Telegram. However, Telegram is not part of the debian-12 template, so we'll have to install it. Luckily, Telegram is available in the official repository. We can therefore tell Salt to create the "messaging" qube and make sure that Telegram is installed in the debian-12 template by writing the state configuration file `/srv/user_salt/messaging.sls` as follows: ```yaml {% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} {% if grains['id'] == 'dom0' %} messaging--create-qube: qvm.vm: - name: messaging - present: - template: debian-12 - label: yellow - prefs: - label: yellow - features: - set: - menu-items: org.telegram.desktop.desktop org.gnome.Nautilus.desktop messaging--update-app-menu: cmd.run: - name: qvm-appmenus --update messaging - runas: {{ gui_user }} - require: - qvm: messaging--create-qube {% elif grains['id'] == 'debian-12' %} messaging--install-apps-in-template: pkg.installed: - pkgs: - telegram-desktop {% endif %} ``` There you go! As we need to run the install process in the debian-12 template, we need to add debian-12 as a target when we make Salt execute this state: `sudo qubesctl --targets=debian-12 --show-output state.sls messaging saltenv=user`. [details=Note on the `{% ... %}` notation] This state configuration file has two parts. In the first part, we wrote the instructions that Salt has to execute while running in the admin qube dom0, while the second part is about installing Telegram, which must be executed in the template debian-12. To have everything in the same file, but ensure that the right part get executed in the right qube, we decided to use a Jinja ["if statement"](https://jinja.palletsprojects.com/en/3.0.x/templates/#if) to modify the state configuration file depending on in what qube Salt is running from. [/details] Similarly, we can have Salt apply this state in both dom0 and debian-12 when running highstate by adding the following to the top file `/srv/user_salt/top.sls`: ``` user: dom0 or debian-12: - messaging ``` This makes the command `sudo qubesctl --targets=debian-12 --show-output state.highstate` automatically create a messaging qube with Telegram as part of its app menu ### 2.3 Example: Creating a qube with new apps from external sources We would like to create a "conferencing" qube with the software Skype to communicate with our family. Skype, however, is not available from the official debian-12 repository because it is distributed under a proprietary software licence: we will have to add an external repository to be able to install it. Because this software is not from the official repository, we consider that there is a non-zero risk that this software compromises the security of its qube during its installation process. Because we want to [trust our default templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates), we will create a new, different template to install this non-free software. We start by downloading the cryptographic key that signs the Skype repository. From a trusted qube called "disp2956" that is connected to the internet, we run the command: ```sh curl --output skype.asc https://repo.skype.com/data/KSYPE-GPG-KEY ``` We check the file's contents with the command `cat skype.asc` to make sure that the file is not malicious. Only if we are completely sure that it is not malicious, we can [copy the file to dom0](https://www.qubes-os.org/doc/how-to-copy-from-dom0/#copying-to-dom0) by opening a dom0 terminal and running: [details=A malicious file could compromise your system through this command!] ```sh qvm-run --pass-io disp2956 'cat skype.asc' > skype.asc ``` [/details] We can then convert the file to a GPG keyring with: ```sh gpg --dearmor --output skype.gpg skype.asc ``` The keyring is ready to be used by Salt, so we can move it under a new directory at `/srv/user_salt/conferencing/skype.gpg`. For practical purposes, we will write our state configuration file under the same directory, at `/srv/user_salt/conferencing/init.sls` with the following: ```yaml {% set gui_user = salt['cmd.shell']('groupmems -l -g qubes') %} {% if grains['id'] == 'dom0' %} conferencing--create-nonfree-template: qvm.clone: - name: nonfree - source: debian-12 conferencing--create-app-qube: qvm.vm: - name: conferencing - present: - template: nonfree - label: yellow - prefs: - label: yellow - features: - set: - menu-items: skypeforlinux.desktop org.gnome.Nautilus.desktop - require: - qvm: conferencing--create-nonfree-template conferencing--update-app-menu: cmd.run: - name: qvm-appmenus --update conferencing - runas: {{ gui_user }} - require: - qvm: conferencing--create-app-qube {% elif grains['id'] == 'nonfree' %} conferencing--add-repository: pkgrepo.managed: - name: deb [signed-by=/etc/apt/keyrings/skype.gpg] https://repo.skype.com/deb stable main - file: /etc/apt/sources.list.d/skype-stable.list - key_url: salt://conferencing/skype.gpg - aptkey: False - require_in: - pkg: conferencing--install-apps conferencing--install-apps: pkg.installed: - pkgs: - skypeforlinux {% endif %} ``` Running this state makes Salt create a "conferencing" app qube based on a new template called "nonfree", in which Salt makes sure that Skype is installed, through an external repository. To run this state, we target our new "nonfree" template with the command `sudo qubesctl --targets=nonfree --show-output state.sls messaging saltenv=user`. Let's add this state to the top file, so that it is applied automatically when running highstate! We add to our top file `/srv/user_salt/top.sls`: ``` user: dom0 or nonfree: - conferencing ``` [details=Tip: Here is what our top file would look like if we activated all the states from this guide so far.] ```yaml user: dom0: - disconnected - salty - vault dom0 or debian-12: - messaging dom0 or nonfree: - conferencing ``` [/details] ### Useful links * [Qubes docs on how to install software](https://www.qubes-os.org/doc/how-to-install-software/) * [Qubes docs on trusting your templates](https://www.qubes-os.org/doc/templates/#trusting-your-templates) * [Basic Salt syntax](https://docs.saltproject.io/salt/user-guide/en/latest/topics/requisites.html), an extremely useful primer from the official Salt documentation * [extrepo-data](https://salsa.debian.org/extrepo-team/extrepo-data), a list of external repositories for many apps that are not in the official repositories

Revision #11

Edited on
2023-08-04
Edited by user
leo

Revision #10

Edited on
2023-08-01
Edited by user
leo
We have a template called fedora-38. We would like Salt to create a purple qube named "salty" based on this template. We write the state configuration file `/srv/user_salt/salty.sls` as follows: We have a [template](https://www.qubes-os.org/doc/glossary/#template) called fedora-38. We would like Salt to create a purple qube named "salty" based on this template. We write the state configuration file `/srv/user_salt/salty.sls` as follows:
We have a template called debian-11. We would like Salt to create a green qube named "disconnected" based on this template, but that has no web browser and no internet access. We write the state configuration file `/srv/user_salt/disconnected.sls` as follows: We have a [template](https://www.qubes-os.org/doc/glossary/#template) called debian-11. We would like Salt to create a green qube named "disconnected" based on this template, but that has no web browser and no internet access. We write the state configuration file `/srv/user_salt/disconnected.sls` as follows:
[details=Note on templating] Note that by default, `cmd.run` makes Salt run commands as root. The command `qvm-appmenus` does not work as root, so we have to make Salt run this command as a regular user. To do so, in the first line of the file we use a templating language called jinja to retrieve our username, we save our username in the `gui_user` variable, and we use this variable when needed. Salt will always execute all the templating instructions before running a state configuration file. [details=Note on the `{}` characters] Note that by default, `cmd.run` makes Salt run commands as root. The command `qvm-appmenus` does not work as root, so we have to make Salt run this command as a regular user. To do so, in the first line of the file we use a templating language called [Jinja](https://jinja.palletsprojects.com/en/3.1.x/templates/) to retrieve our username, we save our username in the `gui_user` variable, and we use this variable when needed. Salt will always execute all the templating instructions between `{}` before running a state configuration file.

Revision #9

Edited on
2023-08-01
Edited by user
leo

Revision #8

Edited on
2023-08-01
Edited by user
leo
> /srv/user_salt > /srv/user_pillar > /srv/user_salt > /srv/user_pillar

Revision #7

Edited on
2023-07-31
Edited by user
leo
As a beginner, [Salt](https://www.qubes-os.org/doc/salt/) seemed daunting to me. It took me some efforts to learn but I love it now! I'm writing this guide for beginners who enjoy an hands-on introduction with examples. As a beginner, [Salt](https://www.qubes-os.org/doc/salt/) seemed daunting to me at first. It took me some efforts to learn but I love it now! I'm writing this guide for beginners who enjoy an hands-on introduction with examples.
* `sudo qubesctl --targets=fedora-38 state.sls my-custom-state` will run `my-custom-state` in dom0 and fedora-38. * `sudo qubesctl --skip-dom0 --targets=debian-12,untrusted state.highstate` will run highstate in the qubes debian-12 and untrusted but not in dom0. * `sudo qubesctl --targets=fedora-38 state.sls my-custom-state` will run `my-custom-state` targeting dom0 and fedora-38. * `sudo qubesctl --skip-dom0 --targets=debian-12,untrusted state.highstate` will run highstate targeting the qubes debian-12 and untrusted but not dom0.

Revision #6

Edited on
2023-07-31
Edited by user
leo
* [Salt docs](https://docs.saltproject.io/en/latest/contents.html), great when looking for something specific but intimidating to start with * [Salt docs](https://docs.saltproject.io/en/latest/contents.html), great when looking for something specific but intimidating to start with * [Qubes state configuration files](https://github.com/QubesOS/qubes-mgmt-salt-dom0-virtual-machines/tree/main/qvm) used to create the first qubes when installing Qubes OS

Revision #5

Edited on
2023-07-31
Edited by user
leo
I hope this was not too hard to follow. Here are some precious links if you'd like to go further: I hope this was clear. Here are some links if you'd like to go further:

Revision #4

Edited on
2023-07-31
Edited by user
leo
# Part 1: Running our first states # Part 1: Creating our first qubes
Note that we always need to add the extra argument `saltenv=user` when we run individual states from the user directory `/srv/user_salt/`. Note that we always need to add the extra argument `saltenv=user` to the command `sudo qubesctl state.sls my-custom-state` when we run individual states from the user directory `/srv/user_salt/`.

Revision #3

Edited on
2023-07-31
Edited by user
leo
Note that Salt cannot run the command `qvm-appmenus` as root, so we have to make it run this command as a regular user. To do so, we use a templating language called jinja to retrieve our username in the first line of the file, we save our username in the `gui_user` variable, and we use this variable when needed. Salt will always run all the templating instructions before reading a state configuration file. Note that by default, `cmd.run` makes Salt run commands as root. The command `qvm-appmenus` does not work as root, so we have to make Salt run this command as a regular user. To do so, in the first line of the file we use a templating language called jinja to retrieve our username, we save our username in the `gui_user` variable, and we use this variable when needed. Salt will always execute all the templating instructions before running a state configuration file.

Revision #2

Edited on
2023-07-31
Edited by user
leo
We can activate `qubes.user-dirs` to create personal state configuration directories. What is this, and how do we activate it? This is what we call a *state configuration*. It is a configuration file that tells salt what to do to reach a particular state. We can activate `qubes.user-dirs` to create personal state configuration directories. What is this, and how do we activate it? This is what we call a *state configuration*. It is a configuration file that tells Salt what to do to reach a particular state.
We have a template called debian-11. We would like Salt to create a purple qube named "salty" based on this template. We write the state configuration file `/srv/user_salt/salty.sls` as follows: We have a template called fedora-38. We would like Salt to create a purple qube named "salty" based on this template. We write the state configuration file `/srv/user_salt/salty.sls` as follows:
Note that Salt cannot run the command `qvm-appmenus` as root, so we have to make him run this command as user. To do so, we use a templating language called jinja to retrieve our username in the first line of the file, we save it in the `gui_user` variable, and we use this variable when needed. Salt will always run all the templating instructions before reading a state configuration file. Note that Salt cannot run the command `qvm-appmenus` as root, so we have to make it run this command as a regular user. To do so, we use a templating language called jinja to retrieve our username in the first line of the file, we save our username in the `gui_user` variable, and we use this variable when needed. Salt will always run all the templating instructions before reading a state configuration file.
* [unman's notes](https://github.com/unman/notes/blob/master/salt/Index), my first reference whenever I need help with Salt for qubes * [unman's notes](https://github.com/unman/notes/blob/master/salt/Index), my first reference whenever I need help with Salt in Qubes