This is probably a very dumb question but how do you go about actually installing split-gpg2?
I’ve read the docs from here: GitHub - QubesOS/qubes-app-linux-split-gpg2: split-gpg v2
But perhaps I’ve misunderstood but that seems to suggest rebuilding qubes to include it. Whereas a bunch of threads seem to suggest it can just be installed.
I’ve tried various combinations of sudo dnf install split-gpg, split-gpg2, qubes-split-gpg etc and always getting a not found error.
Can someone offer some advice?
1 Like
In your split-gpg2 vault template:
Install package split-gpg2
Maybe remove qubes-gpg-split if it’s installed (might not be necessary)
shutdown
In your split-gpg2 client template:
Install package split-gpg2
shutdown
Then create (or repurpose) vault and client app qubes that are backed by the templates above.
Then in dom0:
Install package split-gpg2-dom0 (edit: not actually necessary )
In a new file /etc/qubes/policy.d/30-user-gpg2.policy, add line qubes.Gpg2 + SPLIT_GPG2_CLIENT_QUBE @default allow target=SPLIT_GPG2_VAULT_QUBE but using your app qube names instead of the all-caps names
Run: qvm-service --enable SPLIT_GPG2_CLIENT_QUBE split-gpg2-client (but using your client app qube name)
In your split-gpg2 vault app qube (not template):
Setup / import your secret key (as in the doc you linked)
In your split-gpg2 client app qube (not template):
Import your public key (as in the doc you linked)
I think that covers it all. It’s not trivial to set it all up. You can have multiple client app qubes, in which case you repeat some of the steps above for each.
2 Likes
Thanks.
This is the bit I seem to get stuck at:
sudo dnf install split-gpg2-dom0
Qubes OS Repository for Dom0 2.9 MB/s | 3.0 kB 00:00
No match for argument: split-gpg2-dom0
Error: Unable to find a match: split-gpg2-dom0
In dom0 you don’t usually use dnf directly to install packages. Instead you go through qubes-dom0-update:
sudo qubes-dom0-update split-gpg2-dom0
2 Likes
solene
December 14, 2025, 6:10pm
5
3 Likes
ah. Thanks.
Its been a while since I’ve been using qubes. Have forgotten a lot!
2 Likes
tanky0u
December 14, 2025, 6:51pm
7
What’s the diff between qubes-gpg-split-dom0 and split-gpg2? I am using
the former one.
parulin
December 14, 2025, 7:46pm
8
Euwiiwueir:
Then in dom0:
Install package split-gpg2-dom0
I dont think that this step is useful:
First, you need to search for *gpg2* in order to find the package.
Then, it will only install some python tests and this policy file: /etc/qubes/policy.d/30-user-gpg2.policy which content is:
# Policy for qubes.Gpg2 service.
#
# Add line like this:
#
# qubes.Gpg2 + gpg-client-vm @default allow target=gpg-server-vm
#
# to allow the VM named 'gpg-client-vm' use (but not export) the private keys
# in 'gpg-server-vm'.
Yes, it is a file full of comments!
1 Like
Making some progress, I think.
Running into this error in the client VM.
qubes-gpg-client-wrapper
ERROR: Destination domain not defined! Set it with QUBES_GPG_DOMAIN env variable.
Yet in Dom0 I’m seeing:
qvm-service secure-email
key-server-VM on
split-gpg2 on
The key is showing up when I run gpg -k in the key-server-VM
parulin
December 14, 2025, 10:15pm
10
qubes-gpg-client-wrapper is related to Split GPG 1
Try to follow only the instructions of one version to start somewhere.
My suggestion is that you follow these instructions about Split GPG 2 as I tested them a few days ago.
1 Like
Thanks.
I did follow those instructions, but there are no details relating to how to configure Thunderbird to use this split gpg.
I thought the details for Thunderbird were common to both. My mistake.
1 Like
So, can anyone help with advice how to get split-gpg2 working in Thunderbird?
parulin
December 15, 2025, 2:47pm
13
Are you able to use some basic gpg commands?
Yep, key has been imported into the key server vm.
Am comfortable using gpg, just not sure what to ask it to do!
parulin
December 15, 2025, 5:48pm
15
The last newsletter from alimirjamali mentions some test about Thunderbird. And indeed, there is a test: qubes-app-linux-split-gpg2/tests/test_thunderbird.py at main · QubesOS/qubes-app-linux-split-gpg2 · GitHub
That could help you. You could try to follow the Split GPG-1 docs about Thunderbird without:
using /usr/bin/qubes-gpg-client-wrapper (use gpg instead)
or setting mail.openpgp.alternative_gpg_path
I don’t use Thunderbird + GPG so I’m just guessing.
solene
December 16, 2025, 11:13am
16
It’s now live on the documentation
parulin
December 16, 2025, 2:15pm
17
Out of curiosity I tried to configure Thunderbird with Split GPG-2 and it works . No need to follow Split GPG-1 docs: any how-to about Thunderbird using an external GnuPG will work. Split GPG-2 doesn’t need any extra step!
Refs:
Side note: maybe the whole Thunderbird section could be replaced in the Split GPG-1 page by something like that:
The built-in functionality is more limited currently, including that public keys must live in your work-email qube with Thunderbird rather than your offline work-gpg qube .
Follow any tutorial about smartcards or external GnuPG. The only extra step is to make sure to set mail.openpgp.alternative_gpg_path value to /usr/bin/qubes-gpg-client-wrapper.
1 Like
I’m thinking in this “basic” secure setup for devs and sysadmins:
Diagram of the separation of GPG and SSH private keys and subkeys inside AppVM Server and AppVM Client using Qubes Split GPG-2
├── Policy in dom0 (/etc/qubes/policy.d/30-split-gpg.policy)
│ qubes.Gpg2 * @anyvm vault allow
│
├── Policy in dom0 (/etc/qubes/policy.d/50-ssh.policy)
│ qubes.SshAgent * dev vault ask default_target=vault
│
└── AppVM vault Server (network-isolated)
│
├── GPG Keyring (managed by gpg itself)
│ ├── [sec#] GPG Email Master Key (certify-only, no passphrase)
│ │ └── [sec#] GPG Email Subkey (RSA sign only for email)
│ │ └── Used by email qube via qubes.Gpg2 qrexec
│ │
│ └── [sec#] GPG Dev Master Key (certify-only, no passphrase)
│ └── [sec#] GPG Dev Subkey (RSA sign only for Git commits)
│ └── Used by dev qube via qubes.Gpg2 qrexec
│
└── SSH Agent (via ssh-agent systemd service)
│
├── SSH Key for GitHub/GitLab (id_ed25519_github)
├── SSH Key for servers (id_ed25519_server)
│ └── Used by dev qube via qubes.SshAgent qrexec
│
└── KeePassXC (optional, for SSH key management)
├── Unlocks SSH agent automatically when database opens
├── Stores SSH private keys as attachments
└── Does NOT manage GPG keys—GPG uses its own keyring
└── AppVM dev Client (networked)
│ Git → uses qubes-gpg-client-wrapper → qrexec → vault (GPG signing)
│ SSH client → SSH_AUTH_SOCK forwarded → qrexec → vault (SSH auth)
│
└── ~/.gitconfig
├── user.signingkey = DEV_SUBKEY_ID
├── commit.gpgsign = true
└── gpg.program = qubes-gpg-client-wrapper
└── AppVM email Client (networked)
│ Thunderbird/Evolution → uses qubes-gpg-client-wrapper → qrexec → vault (GPG signing/decrypt)
│
└── Enigmail/Thunderbird config
├── GnuPG binary: /usr/bin/qubes-gpg-client-wrapper
└── Uses same GPG Email Subkey from vault for signing/encryption
Simplified:
appvm-vault (network-isolated)
│
├── GPG Email Master Key (certify-only)
│ └── GPG Email Subkey (sign/encrypt)
│
├── GPG Dev Master Key (certify-only)
│ └── GPG Git Subkey (sign commits)
│
└── SSH Keys (for dev)
├── SSH GitHub Key
└── SSH Server Key
appvm-dev (networked)
├── Git commits (signed with GPG Git Subkey from vault)
└── SSH connections (authenticated with SSH keys from vault)
appvm-email (networked)
└── Thunderbird/Evolution (uses GPG Email Subkey from vault)
What about a key and subkey generator like this?
split-gpg2-key-generator.sh
#!/usr/bin/env bash
# Qubes OS Split GPG-2 key and subkeys generator without passphrase
NAME="Your Name"
EMAIL="your.email@example.com"
COMMENT="Split GPG-2 Key" # Optional
KEY_EXPIRE="2y" # Master key expiration
SUBKEY_EXPIRE="1y" # Subkeys expiration
# Clean start
mv ~/.gnupg ~/.gnupg.backup.$(date +%Y%m%d_%H%M%S)
rm -rf ~/.gnupg
mkdir -m 0700 ~/.gnupg
# Generate master key with expiration
gpg --batch --pinentry-mode loopback --passphrase '' --quick-gen-key "$NAME ($COMMENT) <$EMAIL>" ed25519 sign "$KEY_EXPIRE"
# Get key ID and fingerprint
KEYID=$(gpg --list-secret-keys --keyid-format LONG "$EMAIL" | grep sec | head -1 | awk '{print $2}' | cut -d'/' -f2)
FPR=$(gpg --list-secret-keys --with-colons "$EMAIL" | grep fpr | head -1 | cut -d: -f10)
echo " Master key created: $KEYID"
echo " Fingerprint: $FPR"
# Add signing subkey with expiration
gpg --batch --pinentry-mode loopback --passphrase '' --quick-add-key "$FPR" ed25519 sign "$SUBKEY_EXPIRE"
# Add encryption subkey with expiration
gpg --batch --pinentry-mode loopback --passphrase '' --quick-add-key "$FPR" cv25519 encr "$SUBKEY_EXPIRE"
# Export keys
cd ~/.gnupg
gpg --armor --export "$EMAIL" > "public-key-$KEYID.asc"
gpg --armor --export-secret-keys "$EMAIL" > "master-secret-key-$KEYID.asc"
gpg --armor --export-secret-subkeys "$EMAIL" > "subkeys-only-$KEYID.asc"
# Create revocation certificate
echo "Generating revocation certificate..."
gpg --batch --pinentry-mode loopback --passphrase '' --gen-revoke --armor "$EMAIL" > "revocation-cert-$KEYID.asc" 2>/dev/null <<EOF
y
0
Key has been compromised
y
EOF
# Export ownertrust
gpg --export-ownertrust > "ownertrust-export.txt"
# Test
echo "Testing encryption..."
echo "test" | gpg --batch --yes --always-trust -e -a -r "$EMAIL" | gpg --batch --yes -d 2>/dev/null && echo "Encryption test passed!"
Does it have a good source of entropy?