Skip to content
This repository was archived by the owner on Feb 18, 2026. It is now read-only.

Repository files navigation

qvm-remote

Execute commands in Qubes OS dom0 from one or more VMs.

SSH for dom0qvm-remote qvm-ls is to dom0 what ssh host ls is to a remote server. Written in Python following official qvm-* tool conventions.

Warning: This tool grants VMs the ability to execute arbitrary commands in dom0 with root privileges. This breaks the Qubes security model by design. Only use it on machines you fully control.

How it works

  VM (visyble)                            dom0
 ┌────────────────────┐              ┌──────────────────────┐
 │                    │              │                      │
 │ qvm-remote         │  qvm-run     │ qvm-remote-dom0      │
 │   "qvm-ls"        │◄────────────►│   polls queue        │
 │       │            │  --pass-io   │   verifies HMAC key  │
 │       ▼            │              │   executes command   │
 │ ~/.qvm-remote/     │              │   returns results    │
 │   queue/           │              │                      │
 │   auth.key         │              │ /etc/qubes/remote.d/ │
 │   history/         │              │   visyble.key        │
 │   audit.log        │              │   dev-vm.key         │
 └────────────────────┘              └──────────────────────┘
  1. VM client writes a command + HMAC-SHA256 auth token to ~/.qvm-remote/queue/pending/
  2. Dom0 daemon polls authorized VMs via qvm-run --pass-io --no-autostart
  3. Verifies the HMAC token against the VM's registered key
  4. Fetches, validates, and executes the command with bash
  5. Writes stdout, stderr, and exit code back to the VM
  6. VM client outputs results and archives everything to history/

Every command is logged with timestamp, duration, and exit code on both sides.

Quick start

VM side

sudo make install-vm
qvm-remote key gen         # generates 256-bit auth key

Dom0 side

From a dom0 terminal, use the installer:

VM=visyble
qvm-run --pass-io --no-gui $VM \
    'cat /path/to/qvm-remote/install/install-dom0.sh' \
    > /tmp/install-dom0.sh
bash /tmp/install-dom0.sh $VM

Or install manually:

VM=visyble

# Pull daemon
qvm-run --pass-io --no-gui $VM \
    'cat /usr/bin/qvm-remote-dom0' > /usr/bin/qvm-remote-dom0
chmod +x /usr/bin/qvm-remote-dom0

# Pull service file
qvm-run --pass-io --no-gui $VM \
    'cat /path/to/dom0/qvm-remote-dom0.service' \
    > /etc/systemd/system/qvm-remote-dom0.service

# Configure
echo "QVM_REMOTE_VMS=$VM" > /etc/qubes/remote.conf
chmod 0600 /etc/qubes/remote.conf

# Authorize the VM's key
KEY=$(qvm-run --pass-io --no-gui $VM 'cat ~/.qvm-remote/auth.key')
qvm-remote-dom0 authorize $VM $KEY

# Start
systemctl daemon-reload
systemctl start qvm-remote-dom0

Verify

qvm-remote ping       # "qvm-remote-dom0 is responding."
qvm-remote hostname   # "dom0"

Usage

# Run any command in dom0 (like ssh)
qvm-remote qvm-ls
qvm-remote 'qvm-prefs work memory 4096'
qvm-remote -t 60 'qvm-shutdown --wait work'
echo 'xl info' | qvm-remote
qvm-remote < deploy.sh

# Key management
qvm-remote key gen              # generate + store key
qvm-remote key show             # print key for dom0
qvm-remote key import KEY       # import a hex key

# Diagnostics
qvm-remote ping                 # health check
qvm-remote log                  # last 20 audit entries
qvm-remote log 50               # last 50 entries
qvm-remote history              # last 10 commands

Dom0 daemon

# Key management
qvm-remote-dom0 authorize VM KEY  # register a VM
qvm-remote-dom0 revoke VM         # remove a VM
qvm-remote-dom0 keys              # list authorized VMs

# Service control
systemctl start qvm-remote-dom0          # this session only
journalctl -u qvm-remote-dom0            # view logs
qvm-remote-dom0 enable                   # autostart (risk prompt)
qvm-remote-dom0 disable                  # stop and disable
qvm-remote-dom0 --once                   # process queue once
qvm-remote-dom0 --dry-run --once         # preview without executing

Authentication

qvm-remote uses 256-bit HMAC-SHA256 key authentication — analogous to SSH keys. Each VM has its own unique key. No passwords, PINs, or retries.

How it works

  • Each VM holds a 256-bit (64-hex-char) secret key in ~/.qvm-remote/auth.key
  • Dom0 holds a copy in /etc/qubes/remote.d/<vm-name>.key
  • Every command carries HMAC-SHA256(key, command_id) as a token
  • Dom0 recomputes the HMAC and verifies before executing
  • Invalid tokens are silently rejected and logged

Why this is secure

  • 256-bit key: 2^256 possible keys makes brute force mathematically impossible
  • Per-command HMAC: each token is unique — replay is useless
  • Key never transmitted: only the HMAC token travels; key lives on disk (mode 0600)
  • No retries/lockout needed: with 256 bits, even unlimited attempts are futile
  • Per-VM isolation: compromising one VM's key does not affect others

Multi-VM support

Dom0 can poll multiple VMs simultaneously:

# /etc/qubes/remote.conf
QVM_REMOTE_VMS="visyble dev-vm staging"

Each VM must have its own key:

qvm-remote-dom0 authorize visyble <key1>
qvm-remote-dom0 authorize dev-vm <key2>
qvm-remote-dom0 authorize staging <key3>

Configuration

/etc/qubes/remote.conf in dom0:

QVM_REMOTE_VMS="visyble dev-vm"

Per-VM keys in /etc/qubes/remote.d/:

/etc/qubes/remote.d/
├── visyble.key     # 64-hex-char key (mode 0600)
└── dev-vm.key      # 64-hex-char key (mode 0600)

The VM client requires no configuration beyond the key file.

Building

Docker/Podman build (recommended for non-Fedora hosts)

make docker-rpm   # builds in Fedora 41 container

Local build

make dist    # create source tarballs
make rpm     # build RPMs (requires rpmbuild)

Qubes Builder v2

Add to your builder.yml:

components:
  - qvm-remote:
      url: https://github.com/USER/qvm-remote.git
      branch: main
      verification-mode: insecure-skip-checking

Build: ./qb -c qvm-remote package fetch prep build

Testing

make check        # syntax-check all scripts (including GUI)
make test         # run full test suite (115 tests)
make docker-test  # RPM install test (Fedora 41)
make dom0-test    # dom0 simulation E2E
make fedora-test  # Fedora client + dom0 + GUI
make arch-test    # Arch Linux client + GUI
make gui-test     # GUI build/import test
make distro-test  # all distro tests (Fedora + Arch)

Security

What this tool does

It grants authorized VMs full root-level command execution in dom0.

Protections

HMAC-SHA256 key auth. 256-bit per-VM keys. Mathematically impossible to brute-force. Python hmac module — compatible with openssl for cross-version interop.

Transient by default. Service stops on reboot. enable requires typing "yes" to an explicit risk warning.

Multi-VM isolation. Each VM has its own key. Revoking one doesn't affect others.

No VM auto-start. Uses qvm-run --no-autostart — never starts VMs as a side effect.

Full audit trail. Both sides log every command:

  • VM: ~/.qvm-remote/audit.log
  • Dom0: /var/log/qubes/qvm-remote.log
  • Full output: ~/.qvm-remote/history/YYYY-MM-DD/

Input validation. Rejects empty, oversized (>1 MiB), and binary commands.

Output limits. Stdout/stderr truncated at 10 MiB.

Recommendations

  • Use dedicated, minimal VMs with no network access.
  • Stop the service when not in use.
  • Review journalctl -u qvm-remote-dom0 periodically.
  • Rotate keys periodically (key gen + authorize).

Migrating from qubes-remote (v0.x)

v1.0.0 renames the project and rewrites everything in Python:

v0.x (bash) v1.0.0 (Python)
qubes-remote qvm-remote
qubes-remote-dom0 qvm-remote-dom0
~/.qubes-remote/ ~/.qvm-remote/
--gen-key key gen
--show-key key show
--import-key KEY key import KEY
--authorize VM KEY authorize VM KEY
--revoke VM revoke VM
--list-keys keys
QUBES_REMOTE_VMS= QVM_REMOTE_VMS=

Data directories migrate automatically on first run. RPM packages use Obsoletes: for clean upgrades. Config variables are backward compatible.

GUI (optional)

Both the VM client and dom0 service have optional GTK3 graphical interfaces. They follow the Qubes OS visual style guide and interact with the CLI tools via subprocess calls (no code coupling).

VM GUI (qvm-remote-gui)

Tabbed interface with: Execute, Files, Backup, History, Keys, Log.

sudo make install-gui-vm
qvm-remote-gui

Dom0 GUI (qvm-remote-dom0-gui)

Service manager with: Dashboard, Virtual Machines, Backup, Log.

sudo make install-gui-dom0
sudo qvm-remote-dom0-gui

Requirements: python3-gobject and gtk3 (Fedora) or python-gobject and gtk3 (Arch).

Requirements

  • Qubes OS 4.2+ (tested on 4.3)
  • Python 3.8+ in both dom0 and VMs
  • GTK3 + PyGObject (optional, for GUI only)

Project structure

qvm-remote/
├── .github/
│   └── workflows/ci.yml            GitHub Actions CI
├── dom0/
│   ├── qvm-remote-dom0             Dom0 daemon (Python)
│   └── qvm-remote-dom0.service     Systemd unit
├── gui/
│   ├── qubes_remote_ui.py          Shared GTK3 UI module
│   ├── qvm-remote-gui              VM-side GUI (GTK3)
│   ├── qvm-remote-dom0-gui         Dom0-side GUI (GTK3)
│   ├── qvm-remote-gui.desktop      VM desktop entry
│   └── qvm-remote-dom0-gui.desktop Dom0 desktop entry
├── vm/
│   └── qvm-remote                  VM client (Python)
├── etc/
│   └── qubes-remote.conf           Config template
├── install/
│   └── install-dom0.sh             Dom0 shell installer
├── pkg/
│   └── PKGBUILD                    Arch Linux package
├── rpm_spec/
│   ├── qvm-remote-dom0.spec        Dom0 RPM spec
│   ├── qvm-remote-vm.spec          VM RPM spec
│   ├── qvm-remote-gui-dom0.spec    Dom0 GUI RPM spec
│   └── qvm-remote-gui-vm.spec      VM GUI RPM spec
├── salt/
│   ├── README.md                   Salt deployment guide
│   ├── qvm-remote/init.sls         Salt state
│   ├── qvm-remote.top              Salt top file
│   └── pillar/qvm-remote.sls       Salt pillar
├── test/
│   ├── Dockerfile.arch-client      Arch Linux client + GUI tests
│   ├── Dockerfile.dom0-sim         Dom0 E2E simulation
│   ├── Dockerfile.fedora-client    Fedora client + dom0 + GUI tests
│   ├── Dockerfile.gui              GUI build/import test
│   ├── Dockerfile.test             RPM install test
│   ├── dom0-sim/                   Mock Qubes tools for E2E
│   └── test_qvm_remote.py          Python test suite (115 tests)
├── .qubesbuilder                    Qubes Builder v2 config
├── CONTRIBUTING.md                  Contribution guidelines
├── Dockerfile.build                 Fedora 41 build container
├── Makefile                         Build system
├── Makefile.builder                 Qubes Builder integration
├── version
└── README.md

Contributing

See CONTRIBUTING.md for development workflow, code style, security guidelines, test conventions, and RPM signing instructions.

About

ARCHIVED: Merged into qvm-remote — see github.com/GabrieleRisso/qvm-remote

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages