• Linux
  • Dataflex
  • Networking
  • Postgresql
  • Proxmox
  • Windows
  • Wordpress
encryptioninfrastructure

Encrypting Proxmox VMs with ZFS for Secure Virtualization

ZFS Encrypted Virtual Machines

!!! IMPORTANT !!!

  • This assumes a base ZFS setup already exists or you have done that
  • An existing ZFS dataset CANNOT be encrypted
  • We would need to create a dataset next to existing ZFS dataset then move over VMs
  • Before moving, it may say it has low space. It will dynamically re-assign as things move between the datasets, updating free space and usage as long as the pool as a whole fits it.

Overview

Protecting virtual machines at rest is becoming a mandatory requirement for businesses running sensitive workloads. Proxmox VE makes this easier by supporting native ZFS encryption, allowing you to secure VM disks without relying on full-disk encryption at the host level. When implemented correctly, ZFS encryption ensures that even if the underlying storage is compromised, the data inside your VMs remains protected.

In this guide, we break down the three most common and practical methods for unlocking ZFS-encrypted datasets on Proxmox:

  • Keyfile Unlock
  • Passphrase Unlock
  • Remote Key Unlock

Whether you’re running a home lab, managing a client’s infrastructure, or deploying Proxmox as part of a managed hosting offering, enabling ZFS encryption is one of the easiest ways to add strong, modern data protection to your virtualization stack. In the following sections, we’ll walk through each unlocking method step-by-step and outline best practices for operational security, automation, and disaster recovery.


ZFS encryption (using keyfile)

Using a keyfile is the easiest and most convenient method for enabling ZFS encryption on Proxmox. With this approach, the system automatically unlocks your encrypted datasets at boot without requiring human input—ideal for datacenters, remote environments, or MSP deployments where uptime and automation matter.

However, keyfile security is critical. The encryption key must be stored outside the encrypted dataset, otherwise the system won’t be able to load it during startup. For best security practice, always store the keyfile on a separate disk or dedicated boot device. This prevents an attacker from simply grabbing a single drive and immediately decrypting your VM storage.

Step 1: Check ZFS storage of system

  1. Open Proxmox dashboard, select SA-PVE4 then click on "Shell" button

Open the Proxmox shell

  1. Display information about all ZFS storage pools on system Show total storage stats for zfs1
root@sa-pve4:~# zpool list
NAME   SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
zfs1  1.73T   133G  1.60T        -         -    42%     7%  1.00x    ONLINE  -
  1. Show how each dataset uses space inside zfs1
  • Pool
    • zfs1
  • Datasets (volumes)
    • zfs1/vm-605-disk-0
    • zfs1/vm-699-disk-0
root@sa-pve4:~# zfs list
NAME                 USED  AVAIL     REFER  MOUNTPOINT
zfs1                 176G  1.51T       96K  /zfs1
zfs1/vm-605-disk-0   103G  1.52T     87.8G  -
zfs1/vm-699-disk-0  72.2G  1.54T     44.2G  -

Step 2: Create encrypted ZFS dataset

  1. Open shell of sa-pve4
  2. Create key
dd if=/dev/urandom of=/root/zfskey.bin bs=32 count=1
chmod 600 /root/zfskey.bin
chown root:root /root/zfskey.bin
  1. Create encrypted ZFS dataset
zfs create \\
  -o encryption=aes-256-gcm \\
  -o keyformat=raw \\
  -o keylocation=file:///root/zfskey.bin \\
  zfs1/encrypted
  1. Confirm /zfs1/encrypted encrypted ZFS dataset is created
root@sa-pve4:~# zfs list
NAME                 USED  AVAIL     REFER  MOUNTPOINT
zfs1                 176G  1.51T       96K  /zfs1
zfs1/encrypted       192K  1.51T      192K  /zfs1/encrypted
zfs1/vm-605-disk-0   103G  1.52T     87.8G  -
zfs1/vm-699-disk-0  72.2G  1.54T     44.2G  -
  1. Check encryption configuration of zfs1/encrypted encrypted ZFS dataset

*** If the keystatus is available, it means that the zfs1/encrypted encrypted ZFS dataset is UNLOCKED ***

zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted

NAME            PROPERTY     VALUE                    SOURCE
zfs1/encrypted  encryption   aes-256-gcm              -
zfs1/encrypted  keylocation  file:///root/zfskey.bin  local
zfs1/encrypted  keyformat    raw                      -
zfs1/encrypted  keystatus    available                -
  1. Mount encrypted ZFS dataset
zfs mount zfs1/encrypted

Step 3: Auto-unlock encrypted ZFS dataset

  1. Open shell of sa-pve4
  2. Create zfs-load-key@zfs1-encrypted.service file
touch /etc/systemd/system/zfs-load-key@zfs1-encrypted.service
  1. In zfs-load-key@zfs1-encrypted.service file, add the following
[Unit]
Description=Unlock ZFS dataset zfs1/encrypted
Before=zfs-mount.service
After=zfs-import.target

[Service]
Type=oneshot
ExecStart=/usr/sbin/zfs load-key zfs1/encrypted

[Install]
WantedBy=zfs-mount.service
  1. Enable the "auto-unlock" service at boot
systemctl enable zfs-load-key@zfs1-encrypted.service

Created symlink /etc/systemd/system/zfs-mount.service.wants/zfs-load-key@zfs1-encrypted.service /etc/systemd/system/zfs-load-key@zfs1-encrypted.service.
  1. Check "auto-unlock" service is enabled
systemctl is-enabled zfs-load-key@zfs1-encrypted.service

Step 4: Integrate encrypted ZFS dataset in Proxmox

  1. In Proxmox dashboard, click on "Datacenter" -> "Storage" -> "Add" -> "ZFS" Add ZFS pool to Promxox
  2. Input
    • "ID" with zfs1-encrypted-pve4
    • "ZFS Pool" with zfs1/encrypted
    • "Nodes" with sa-pve4
    • "Thin provision" with checked

*** Note that if there is no zfs1-encrypted-pve4 for "ZFS Pool", please login to PVE dashboard directly to this node ***

Add ZFS Pool in Datacenter storage

  1. We can see that there is zfs1-encrypted-pve4 available in sa-pve4 node

View Encrypted Storage Mount in PVE


Step 5: Move VM's disk to encrypted ZFS dataset

  1. In shell of sa-pve4, we can see zfs1/vm-700-disk-0
root@sa-pve4:~# zfs list
NAME                  USED  AVAIL     REFER  MOUNTPOINT
zfs1                  294G  1.39T       96K  /zfs1
zfs1/encrypted        192K  1.39T      192K  /zfs1/encrypted
zfs1/vm-4003-disk-0  33.0G  1.43T       56K  -
zfs1/vm-4003-disk-1  33.0G  1.43T       56K  -
zfs1/vm-605-disk-0    103G  1.41T     87.8G  -
zfs1/vm-699-disk-0   72.2G  1.42T     44.2G  -
zfs1/vm-700-disk-0   51.6G  1.41T     32.0G  -
  1. In PVE dashboard, select the VM that we would like to move disk to encrypted ZFS pool Move PVE Disk Storage to encrypted volume
  2. For "Target Storage", select zfs1-encrypted-pve4

Move PVE Disk Storage to encrypted volume confirmation

  1. In shell of sa-pve4, we can see that the VM 700 disk changes from zfs1/vm-700-disk-0 to zfs1/encrypted/vm-700-disk-0
root@sa-pve4:~# zfs list
NAME                           USED  AVAIL     REFER  MOUNTPOINT
zfs1                           274G  1.41T       96K  /zfs1
zfs1/encrypted                32.2G  1.41T      192K  /zfs1/encrypted
zfs1/encrypted/vm-700-disk-0  32.2G  1.41T     32.2G  -
zfs1/vm-4003-disk-0           33.0G  1.45T       56K  -
zfs1/vm-4003-disk-1           33.0G  1.45T       56K  -
zfs1/vm-605-disk-0             103G  1.43T     87.8G  -
zfs1/vm-699-disk-0            72.2G  1.44T     44.2G  -

Step 6: Reboot node for testing (with auto-unlock enabled)

  1. Reboot sa-pve4 node Reboot the Proxmox node
  2. Once rebooted successfully, click on "Shell" button Open the Proxmox shell
  3. Ensure that the zfs1/encrypted encrypted ZFS dataset is unlocked and mounted automatically

Mounted successfully

root@sa-pve4:~# df -h
Filesystem              Size  Used Avail Use% Mounted on
zfs1                    1.6T  128K  1.6T   1% /zfs1
zfs1/encrypted          1.6T  256K  1.6T   1% /zfs1/encrypted

Unlocked successfully

root@sa-pve4:~# zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted
NAME            PROPERTY     VALUE                    SOURCE
zfs1/encrypted  encryption   aes-256-gcm              -
zfs1/encrypted  keylocation  file:///root/zfskey.bin  local
zfs1/encrypted  keyformat    raw                      -
zfs1/encrypted  keystatus    available                -

Step 7: Reboot node for testing (without auto-unlock enabled)

  1. In shell of sa-pve4, disable the "auto-unlock" service at boot
systemctl disable zfs-load-key@zfs1-encrypted.service
  1. Check "auto-unlock" service is disabled
systemctl is-enabled zfs-load-key@zfs1-encrypted.service
  1. Reboot sa-pve4 node Reboot the Proxmox node
  2. Once rebooted successfully, click on "Shell" button Open the Proxmox shell
  3. The zfs1/encrypted encrypted ZFS dataset SHOULD NOT BE unlocked or mounted

Mounted unsuccessfully

root@sa-pve4:~# df -h
Filesystem            Size  Used Avail Use% Mounted on
zfs1                  1.6T  128K  1.6T   1% /zfs1

Unlocked unsuccessfully

root@sa-pve4:~# zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted
NAME            PROPERTY     VALUE                    SOURCE
zfs1/encrypted  encryption   aes-256-gcm              -
zfs1/encrypted  keylocation  file:///root/zfskey.bin  local
zfs1/encrypted  keyformat    raw                      -
zfs1/encrypted  keystatus    unavailable              -
  1. The VM configured "Target Storage" with zfs1-encrypted-pve4 would not be started Error timeout: no zvol device link for vm
  2. Manually unlock
zfs load-key zfs1/encrypted

Result

root@sa-pve4:~# zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted
NAME            PROPERTY     VALUE                    SOURCE
zfs1/encrypted  encryption   aes-256-gcm              -
zfs1/encrypted  keylocation  file:///root/zfskey.bin  local
zfs1/encrypted  keyformat    raw                      -
zfs1/encrypted  keystatus    available                -

ZFS encryption (using remote key)

For environments where security and centralized control are top priorities, unlocking ZFS encryption with a remote key provides the strongest and most flexible solution. Instead of storing the key locally, the Proxmox host retrieves it securely from an external system—such as an API endpoint, HashiCorp Vault, a password manager with API access, or a dedicated key management server.

This method ensures the encrypted datasets stay locked by default until the host successfully authenticates against your key server. Even if someone steals the drives and the boot disk, they still cannot decrypt the VM storage without access to the remote key infrastructure.

A typical workflow looks like this:

  1. During boot, a small script (e.g. /etc/zfs/keyfetch.sh) runs before the ZFS import.
  2. The script authenticates to your remote service (via token, certificate, VPN tunnel, or hardware-bound credential).
  3. If the request is authorized, the server sends back the encryption key.
  4. The key is piped directly into zfs load-key without ever touching persistent storage.

This approach is ideal for MSPs, enterprise clients, and secure hosting environments where keys must remain off-host and centrally managed. It also allows you to revoke or rotate keys without touching each Proxmox node—great for long-term operational security.

Step 1: Create encrypted ZFS dataset

  1. Open shell of sa-pve4
  2. Create key
dd if=/dev/urandom of=/root/zfskey.bin bs=32 count=1
chmod 600 /root/zfskey.bin
chown root:root /root/zfskey.bin
  1. Encode binary key to base64
base64 /root/zfskey.bin > /root/zfskey.b64
  1. Create encrypted ZFS dataset with /root/zfskey.bin
zfs create \\
  -o encryption=aes-256-gcm \\
  -o keyformat=raw \\
  -o keylocation=file:///root/zfskey.bin \\
  zfs1/encrypted-with-remote-key
  1. Confirm /zfs1/encrypted-with-remote-key encrypted ZFS dataset is created
root@sa-pve4:~# zfs list
NAME                             USED  AVAIL     REFER  MOUNTPOINT
zfs1                            99.0G  1.58T       96K  /zfs1
zfs1/encrypted-with-remote-key   192K  1.58T      192K  /zfs1/encrypted-with-remote-key
  1. Check encryption configuration of zfs1/encrypted-with-remote-key encrypted ZFS dataset *** If the keystatus is available, it means that the zfs1/encrypted-with-remote-key encrypted ZFS dataset is UNLOCKED ***
root@sa-pve4:~# zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted-with-remote-key
NAME                            PROPERTY     VALUE                    SOURCE
zfs1/encrypted-with-remote-key  encryption   aes-256-gcm              -
zfs1/encrypted-with-remote-key  keylocation  file:///root/zfskey.bin  local
zfs1/encrypted-with-remote-key  keyformat    raw                      -
zfs1/encrypted-with-remote-key  keystatus    available                -

Step 2: Setup remote key

In our example, we will use a private gist. However, there are many better ways to do this, but this is the easiest for a tutorial.

Remember, if you are encrypting using a remote key, your Proxmox node will require an internet connection before it can decrypt volumes!

  1. Open shell of sa-pve4
  2. Get the content of /root/zfskey.b64
  3. Visit https://gist.github.com/
  4. Create a gist Create a Github GIST
  5. Click on "Raw" button Create a RAW Github GIST
  6. Get the URL Get GIST URL
  7. Open shell of sa-pve4
  8. In shell of sa-pve4, ensure that we could get the base64 encoded value with the URL
curl -X GET <GITHUB_GIST_URL>

Step 3: Create script to fetch remote key

  1. Create unlock_with_remote_key.sh
touch /root/unlock_with_remote_key.sh
  1. In unlock_with_remote_key.sh, add the following
#!/bin/bash

URL="<GITHUB_GIST_URL>"
curl -s "$URL" | tr -d '\\n' | base64 --decode > /root/zfskey.bin
zfs load-key zfs1/encrypted-with-remote-key
rm /root/zfskey.bin
  1. Ensure root has permission to execute the unlock_with_remote_key.sh script
chmod u+x unlock_with_remote_key.sh

Step 4: Auto-unlock encrypted ZFS dataset

  1. Create zfs-load-key@zfs1-encrypted-with-remote-key.service file
touch /etc/systemd/system/zfs-load-key@zfs1-encrypted-with-remote-key.service
  1. In zfs-load-key@zfs1-encrypted-with-remote-key.service file, add the following
[Unit]
Description=Unlock ZFS dataset zfs1/encrypted-with-remote-key
After=zfs-import.target network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/root/unlock_with_remote_key.sh

[Install]
WantedBy=zfs-mount.service
  1. Enable the "auto-unlock" service at boot
systemctl enable zfs-load-key@zfs1-encrypted-with-remote-key.service

Created symlink /etc/systemd/system/zfs-mount.service.wants/zfs-load-key@zfs1-encrypted-with-remote-key.service /etc/systemd/system/zfs-load-key@zfs1-encrypted-with-remote-key.service.
  1. Check "auto-unlock" service is enabled
systemctl is-enabled zfs-load-key@zfs1-encrypted-with-remote-key.service

Step 5: Reboot node for testing

  1. Reboot sa-pve4 node Reboot the Proxmox node
  2. Once rebooted successfully, click on "Shell" button Open the Proxmox shell
  3. Ensure that the zfs1/encrypted-with-remote-key encrypted ZFS dataset is unlocked and mounted automatically
  • Mounted successfully
root@sa-pve4:~# df -h
Filesystem                      Size  Used Avail Use% Mounted on
zfs1                            1.6T  128K  1.6T   1% /zfs1
zfs1/encrypted-with-remote-key  1.6T  256K  1.6T   1% /zfs1/encrypted-with-remote-key
  • Unlocked successfully
root@sa-pve4:~# zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted-with-remote-key
NAME                            PROPERTY     VALUE                    SOURCE
zfs1/encrypted-with-remote-key  encryption   aes-256-gcm              -
zfs1/encrypted-with-remote-key  keylocation  file:///root/zfskey.bin  local
zfs1/encrypted-with-remote-key  keyformat    raw                      -
zfs1/encrypted-with-remote-key  keystatus    available                -

ZFS encryption (using manual passphrase)

Unlocking ZFS encryption with a manual passphrase is the simplest and most secure method from a cryptographic standpoint. Instead of storing keys locally or retrieving them from a remote system, the dataset is unlocked only when an administrator physically (or through console access) enters the passphrase during boot.

With this method, your encrypted VM storage remains fully protected until a human enters the correct passphrase. This makes it ideal for:

  • Standalone hosts
  • High-security on-premises deployments
  • Environments where physical or out-of-band console access is available
  • Situations where you want to guarantee no automatic decryption

Because no keyfiles or remote systems are involved, the security boundary is extremely tight: even if someone steals all storage devices and the boot drive, the data remains inaccessible without the passphrase.

Typical workflow:

  1. System boots and reaches the point where encrypted ZFS datasets need to be imported.
  2. The system waits for user input and prompts for the passphrase.
  3. Once entered, ZFS unlocks the dataset and the VM storage becomes available.
  4. This method provides maximum data confidentiality, but it does require human action during every reboot—so it’s best suited for hosts where reboots are rare or where operational workflows already include console access at boot time.

Step 1: Create encrypted ZFS dataset

  1. Open shell of sa-pve4
  2. Create encrypted ZFS dataset
zfs create \
  -o encryption=aes-256-gcm \
  -o keyformat=passphrase \
  -o keylocation=prompt \
  zfs1/encrypted-with-passphrase
  1. Confirm /zfs1/encrypted-with-passphrase encrypted ZFS dataset is created
root@sa-pve4:~# zfs list
NAME                             USED  AVAIL     REFER  MOUNTPOINT
zfs1                            99.0G  1.58T       96K  /zfs1
zfs1/encrypted-with-passphrase   192K  1.58T      192K  /zfs1/encrypted-with-passphrase
  1. Check encryption configuration of zfs1/encrypted-with-passphrase encrypted ZFS dataset

*** If the keystatus is available, it means that the zfs1/encrypted-with-passphrase encrypted ZFS dataset is UNLOCKED ***

zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted-with-passphrase

root@sa-pve4:~# zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted-with-passphrase
NAME                            PROPERTY     VALUE        SOURCE
zfs1/encrypted-with-passphrase  encryption   aes-256-gcm  -
zfs1/encrypted-with-passphrase  keylocation  prompt       local
zfs1/encrypted-with-passphrase  keyformat    passphrase   -
zfs1/encrypted-with-passphrase  keystatus    available    -
  1. Mount encrypted ZFS dataset
zfs mount zfs1/encrypted-with-passphrase

Step 2: Reboot node for testing

  1. Reboot the Proxmox node Reboot the Proxmox node
  2. Once rebooted successfully, click on "Shell" button Open the Proxmox shell
  3. Ensure that the zfs1/encrypted-with-passphrase encrypted ZFS dataset is locked and not mounted by default

Not mounted by default

root@sa-pve4:~# df -h
Filesystem            Size  Used Avail Use% Mounted on
zfs1                  1.6T  128K  1.6T   1% /zfs1

Locked by default

root@sa-pve4:~# zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted-with-passphrase
NAME                            PROPERTY     VALUE        SOURCE
zfs1/encrypted-with-passphrase  encryption   aes-256-gcm  -
zfs1/encrypted-with-passphrase  keylocation  prompt       local
zfs1/encrypted-with-passphrase  keyformat    passphrase   -
zfs1/encrypted-with-passphrase  keystatus    unavailable  -

Manually unlock

root@sa-pve4:~# zfs load-key zfs1/encrypted-with-passphrase
Enter passphrase for 'zfs1/encrypted-with-passphrase':

Result

root@sa-pve4:~# zfs get encryption,keylocation,keyformat,keystatus zfs1/encrypted-with-passphrase
NAME                            PROPERTY     VALUE        SOURCE
zfs1/encrypted-with-passphrase  encryption   aes-256-gcm  -
zfs1/encrypted-with-passphrase  keylocation  prompt       local
zfs1/encrypted-with-passphrase  keyformat    passphrase   -
zfs1/encrypted-with-passphrase  keystatus    available    -

Need Help With Proxmox or Secure Virtualization?

If you want Proxmox ZFS encryption set up correctly—or you need help designing a secure, high-availability virtualisation environment—we can do it for you.

Whether it’s configuring encrypted VM storage, hardening your hypervisor, setting up automated backups, or managing your entire Proxmox infrastructure, our team can assist with:

  • Proxmox installation, upgrades, and migrations
  • ZFS encrypted storage design (keyfile, passphrase, or remote key)
  • Firewalling, VPNs, and secure remote access
  • Backup and disaster recovery planning
  • Performance tuning and ongoing maintenance

If you’d like this implemented in your environment—or you need reliable Proxmox support—get in touch and we’ll be happy to help.

Get In Touch

Why partner with Digitize?

At Digitize, we are a focused team that invest constantly in improving so that we can provide the best capabilities to our clients. Our processes and teams are built around being flexible so we can deliver tailored solutions instead of trying to make existing solutions fit.

Each client has a dedicated account manager that will ensure you are always getting the best service possible.