Good evening everyone, after 5–6 hours of research and discussions with Claude, I finally managed to piece everything together.
Below is the finalized manual edited by Claude.
The goal was to have my sdb1 attached to the VM with the memory configured as a parameter, because I use DispVMs to transfer files via SSH. But depending on the file size, I couldn’t transfer them from one VM to another due to lack of space. So I “found” a solution that works for me while keeping the partition encrypted — therefore inaccessible and invisible at first glance.
Thank you.
What We’re Building
You’re gonna create an offline VM with 900 GB of private storage on your /dev/sdb1 partition (encrypted). The disk will be unlocked manually when you need it, then locked back up after you’re done.
Why this rocks:
Encrypted disk (password protected)
Dedicated VM with 900 GB accessible
Manual activation/deactivation
Automatic snapshots for backups
PREREQUISITES
Check your partition in dom0
bash
lsblk -f | grep sdb
You should see sdb1 with ~900G
Check if you have the tools
bash
sudo dnf list installed lvm2 cryptsetup
If missing:
bash
sudo dnf install lvm2 cryptsetup
STEP 1: Encrypt the Disk
WARNING: This step ERASES all data on /dev/sdb1
1.1 Clean up the partition
bash
# Unmount if mounted
sudo umount /dev/sdb1 2>/dev/null
# Wipe existing signatures
sudo wipefs -a /dev/sdb1
1.2 Encrypt with LUKS
bash
sudo cryptsetup luksFormat /dev/sdb1
What’s gonna happen:
- Type
YESin capitals - Enter your passphrase (≥12 chars, make it strong!)
- Confirm the passphrase
IMPORTANT: Save this passphrase somewhere safe!
1.3 Verify encryption
bash
lsblk -f | grep sdb1
You should see crypto_LUKS as the filesystem type.
STEP 2: Unlock the Disk
bash
sudo cryptsetup luksOpen /dev/sdb1 myencrypted
Breaking it down:
sudo cryptsetup luksOpen= FIXED COMMAND/dev/sdb1= YOUR PARTITION (fixed)myencrypted= NAME you choose (keep this one)
What it asks: Your LUKS passphrase
Verify it worked:
bash
lsblk
You should see /dev/mapper/myencrypted
STEP 3: Create the LVM Structure
3.1 Create the Physical Volume
bash
sudo pvcreate /dev/mapper/myencrypted
Breaking it down:
sudo pvcreate= FIXED COMMAND/dev/mapper/myencrypted= Uses the name from step 2
Verify:
bash
sudo pvdisplay
You should see your PV with ~900G
3.2 Create the Volume Group
bash
sudo vgcreate myvg /dev/mapper/myencrypted
Breaking it down:
sudo vgcreate= FIXED COMMANDmyvg= NAME you choose (keep this one)/dev/mapper/myencrypted= Reuses the name from step 2
Check available size:
bash
sudo vgdisplay myvg
NOTE the “VG Size” (example: 899.50 GiB)
3.3 Create the Thin Pool
Use 100% of available space:
bash
sudo lvcreate -l 100%FREE -T myvg/mypool
Breaking it down:
sudo lvcreate= FIXED COMMAND-l 100%FREE= Uses all free space-T= Creates a thin pool (for snapshots)myvg/mypool= VG/pool name
Verify:
bash
sudo lvs -a myvg
You should see mypool with type twi-a-tz--
STEP 4: Connect to Qubes
4.1 Add the pool to Qubes
CORRECT SYNTAX (spaces between each -o - this is important!):
bash
qvm-pool add mypool lvm_thin -o volume_group=myvg -o thin_pool=mypool -o revisions_to_keep=3
Breaking it down:
qvm-pool add mypool= Pool name in Qubeslvm_thin= Pool type-o volume_group=myvg= Your VG (step 3.2)-o thin_pool=mypool= Your pool (step 3.3)-o revisions_to_keep=3= Keeps 3 snapshots
Verify:
bash
qvm-pool list
You should see mypool with driver lvm_thin
STEP 5: Create the Offline VM
5.1 List your available templates
bash
qvm-ls --template
Note a template (examples: debian-12, fedora-40, debian-11)
5.2 Create the VM
Replace debian-12 with YOUR template!
bash
qvm-create --pool private=mypool --label red --template debian-12 --standalone --property netvm=none my-offline-vm
Breaking it down:
qvm-create= FIXED COMMAND--pool private=mypool= Uses your pool--label red= Color (changeable: blue, green, orange…)--template debian-12= YOUR TEMPLATE (change it!)--standalone= Independent VM--property netvm=none= No network (offline)my-offline-vm= VM name (changeable)
5.3 Extend the private volume
bash
qvm-volume extend my-offline-vm:private 850G
Why 850G? Leaves 50G margin for snapshots.
Verify:
bash
qvm-volume info my-offline-vm:private
You should see size: 850 GiB
STEP 6: Test the VM
6.1 Start the VM
bash
qvm-start my-offline-vm
Wait 20-30 seconds (first-time initialization).
6.2 Open a terminal in the VM
Method 1 - Via Qube Manager:
- Open Qube Manager (menu)
- Find
my-offline-vm(red) - Right-click → Run Terminal
Method 2 - From dom0:
bash
qvm-run my-offline-vm xterm
6.3 Check available space (INSIDE the VM)
bash
df -h /home
You should see ~850G available!
6.4 Test writing
bash
echo "Secure storage test" > ~/test.txt
cat ~/test.txt
If it works: CONGRATS, everything is operational!
DAILY USE: How to Use It
START AND USE THE VM
1. Unlock the disk (in dom0):
bash
sudo cryptsetup luksOpen /dev/sdb1 myencrypted
sudo vgchange -ay myvg
2. Start the VM:
bash
qvm-start my-offline-vm
3. Use normally via Qube Manager or terminal
STOP AND LOCK THE DISK
1. Stop the VM:
bash
qvm-shutdown my-offline-vm
Wait until it’s completely stopped (qvm-ls no longer shows it in green)
2. Deactivate the VG:
bash
sudo vgchange -an myvg
3. Lock the disk:
bash
sudo cryptsetup luksClose myencrypted
Secured: The disk is now completely inaccessible
Automation Scripts (Optional)
Startup script: ~/start-offline-vm.sh
bash
#!/bin/bash
echo "🔓 Unlocking disk..."
sudo cryptsetup luksOpen /dev/sdb1 myencrypted || exit 1
sudo vgchange -ay myvg || exit 1
echo "🚀 Starting VM..."
qvm-start my-offline-vm
echo "✅ VM ready!"
Shutdown script: ~/stop-offline-vm.sh
bash
#!/bin/bash
echo "🛑 Stopping VM..."
qvm-shutdown --wait my-offline-vm
echo "🔒 Locking disk..."
sudo vgchange -an myvg
sudo cryptsetup luksClose myencrypted
echo "✅ Disk secured!"
Make them executable:
bash
chmod +x ~/start-offline-vm.sh ~/stop-offline-vm.sh
Use them:
bash
~/start-offline-vm.sh
# ... your work ...
~/stop-offline-vm.sh
File Transfer
From a networked VM to my-offline-vm:
bash
# In the source VM
qvm-copy /path/to/file
Select my-offline-vm in the window
In my-offline-vm, files arrive in:
~/QubesIncoming/source-vm-name/
Verification Commands
bash
# Check if disk is unlocked
lsblk | grep myencrypted
# Check if VG is active
sudo vgs
# Check pool space usage
qvm-pool info mypool
# Check VM space
qvm-volume info my-offline-vm:private
# VM status
qvm-ls | grep my-offline-vm
Troubleshooting
“Got empty response from qubesd”
Solution:
bash
# Check VG is active
sudo vgs
# If "inactive":
sudo vgchange -ay myvg
# Restart qubesd
sudo systemctl restart qubesd
# Retry with SPACES between each -o:
qvm-pool add mypool lvm_thin -o volume_group=myvg -o thin_pool=mypool -o revisions_to_keep=3
“Device or resource busy” during luksClose
bash
sudo vgchange -an myvg --force
sudo cryptsetup luksClose myencrypted
VM won’t start (“volume missing”)
Cause: Disk not unlocked
bash
sudo cryptsetup luksOpen /dev/sdb1 myencrypted
sudo vgchange -ay myvg
qvm-start my-offline-vm
Forgot LUKS passphrase
Unfortunately: LUKS without passphrase = data lost forever
Prevention: Save the passphrase in a secure password manager
Complete Removal
bash
# 1. Stop the VM
qvm-shutdown my-offline-vm
# 2. Remove the VM
qvm-remove my-offline-vm
# 3. Remove the pool
qvm-pool remove mypool
# 4. Destroy LVM structure
sudo lvremove myvg/mypool
sudo vgremove myvg
sudo pvremove /dev/mapper/myencrypted
# 5. Close LUKS
sudo cryptsetup luksClose myencrypted
# 6. (Optional) Completely erase sdb1
sudo cryptsetup luksErase /dev/sdb1 # WARNING: Permanent loss!
sudo wipefs -a /dev/sdb1
Change LUKS Passphrase
bash
sudo cryptsetup luksChangeKey /dev/sdb1
Enter old passphrase, then new one (twice).