How to Set Up Diskless Linux Boot with ZFS and iSCSI on Proxmox

How to Set Up Diskless Linux Boot with ZFS and iSCSI on Proxmox

Diskless boot is a powerful DevOps technique that lets you boot a Linux system entirely from a network-attached storage volume instead of local drives. This approach is especially useful when you want to preserve your local storage for other purposes, maintain a clean system configuration, or test multiple Linux environments without physical repartitioning.

This guide walks you through configuring diskless Linux boot on Proxmox using ZFS, iSCSI targets, TFTP, and PXE—everything you need to boot Debian directly from your NAS or networked storage.

Prerequisites and Architecture

Before starting, ensure you have:

  • A Proxmox server or standalone Debian host (we'll use this as the boot server)
  • A client machine with network boot capability (PXE support in BIOS/UEFI)
  • ZFS storage available on your Proxmox host
  • Network connectivity between boot server and client
  • DNS/DHCP control (we'll use Asus router with Merlin firmware as an example)

The architecture consists of:

  1. Netboot.xyz — bootloader and OS selection interface
  2. TFTP server — serves the bootloader files
  3. iSCSI target — exposes the ZFS ZVol as a block device
  4. DNSMasq — handles DHCP options for PXE
  5. ZFS ZVol — the actual Debian installation stored on networked storage

Step 1: Install Required Packages on Proxmox

Logon to your Proxmox host and install the necessary services:

apt update
apt install apache2 git ansible tftpd-hpa targetcli-fb

These packages provide:

  • apache2 — web server for serving ISO and boot files
  • tftpd-hpa — lightweight TFTP daemon for PXE boot files
  • targetcli-fb — iSCSI target configuration tool
  • ansible — optional, used in the source setup for automation

Step 2: Install and Configure Netboot.xyz

Netboot.xyz is a PXE bootloader that lets you select which OS to install remotely. Clone and set it up on your Proxmox host:

cd /opt
git clone https://github.com/netbootxyz/netboot.xyz.git
cd netboot.xyz

Configure Apache to serve Netboot.xyz files. Create a virtual host:

cat > /etc/apache2/sites-available/netboot.conf << 'EOF'
<VirtualHost *:80>
    ServerName netboot.local
    DocumentRoot /opt/netboot.xyz/site
    <Directory /opt/netboot.xyz/site>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
ErrorLog ${APACHE_LOG_DIR}/netboot-error.log
    CustomLog ${APACHE_LOG_DIR}/netboot-access.log combined
</VirtualHost>
EOF

Enable the site and reload Apache:

a2ensite netboot.conf
systemctl reload apache2

Step 3: Configure TFTP for PXE

TFTP serves the initial bootloader files. Edit /etc/default/tftpd-hpa:

cat > /etc/default/tftpd-hpa << 'EOF'
TFTPD_USERNAME="tftp"
TFTPD_DIRECTORY="/srv/tftp"
TFTPD_ADDRESS="[::]:69"
TFTPD_OPTIONS="--secure --create"
EOF

Create the TFTP directory and populate it with Netboot.xyz boot files:

mkdir -p /srv/tftp
cd /opt/netboot.xyz
cp -r bin/* /srv/tftp/
chown -R tftp:tftp /srv/tftp
systemctl restart tftpd-hpa

Step 4: Configure DNSMasq on Your Router

You need DHCP to point clients to your TFTP server. On your Asus router with Merlin firmware, SSH in and edit the dnsmasq configuration:

ssh admin@192.168.1.1  # Default Asus IP

# Edit dnsmasq config
cat >> /jffs/configs/dnsmasq.conf.add << 'EOF'
# PXE Boot Configuration
dhcp-boot=pxelinux.0,netboot-server,192.168.1.100
dhcp-option=vendor:PXEClient,6,192.168.1.100
EOF

# Restart dnsmasq
service restart_dnsmasq

Replace 192.168.1.100 with your Proxmox host's IP. The netboot-server hostname should resolve to that IP via DNS.

Step 5: Create ZFS ZVol for Debian Installation

On your Proxmox host, create a ZFS ZVol (block device) to store the Debian installation:

# List existing ZFS pools
zfs list

# Create a 100GB ZVol named debian-boot
zfs create -V 100G tank/debian-boot

# Verify creation
zfs list -t volume

The ZVol will appear as /dev/zvol/tank/debian-boot.

Step 6: Configure iSCSI Target

iSCSI exposes the ZFS ZVol as a network block device. Use targetcli:

targetcli

Inside the targetcli shell, create the target and LUN:

# Create iSCSI target
/iscsi create iqn.2025-05.proxmox:debian-boot

# Create a block storage object pointing to the ZVol
/backstores/block create debian-boot-store /dev/zvol/tank/debian-boot

# Create LUN under the target
/iscsi/iqn.2025-05.proxmox:debian-boot/tpg1/luns create /backstores/block/debian-boot-store

# Set portal (iSCSI listener)
/iscsi/iqn.2025-05.proxmox:debian-boot/tpg1/portals create 192.168.1.100

# Enable the target
/iscsi/iqn.2025-05.proxmox:debian-boot/tpg1 set attribute authentication=0

# Exit and save
exit

Save the configuration:

targetcli saveconfig
systemctl restart iscsid

Step 7: Install Debian on the iSCSI Target

On your client machine, enable network boot in BIOS/UEFI and power on. You should see:

  1. PXE boot prompt
  2. DHCP assigns IP and TFTP server address
  3. Netboot.xyz menu loads
  4. Select "Debian" → latest version
  5. Debian installer detects the iSCSI LUN as /dev/sda

During the Debian installer, configure iSCSI discovery:

Configuring iSCSI
Discovery method: Manual
Target IP: 192.168.1.100
Target Name: iqn.2025-05.proxmox:debian-boot

The installer will partition and install to the ZVol. Once complete, the system will boot directly from the network on every startup.

Performance Considerations

Diskless boot over iSCSI will be slower than local NVMe, especially during OS startup. However:

  • System boots remain acceptable (20-30 seconds) with gigabit networking
  • RAM caching in the client mitigates repeated disk access
  • Suitable for workloads where local SSD is reserved for application data
  • Perfect for testing, development, and LLM model inference (model files on local NVMe, OS on iSCSI)

Troubleshooting

Client stuck at PXE boot menu:

  • Verify DHCP-BOOT option is set on router
  • Check TFTP server is listening: netstat -tulpn | grep 69
  • Inspect /var/log/syslog on Proxmox for TFTP errors

iSCSI target not discovered:

  • Confirm portal is listening: ss -tulpn | grep 3260
  • Test connectivity: iscsiadm -m discovery -t st -p 192.168.1.100

Debian installer doesn't see iSCSI LUN:

  • Ensure targetcli saved configuration: cat /etc/target/saveconfig.json
  • Verify ZVol exists and is writable: ls -la /dev/zvol/tank/

Next Steps

Once diskless boot is working:

  • Create multiple ZVols for different client VMs
  • Automate client provisioning with Ansible
  • Set up ZFS snapshots for rapid rollback
  • Configure read-only iSCSI targets for shared read-only OSes

This setup keeps your local storage clean while leveraging your existing NAS infrastructure for network boot.

Recommended Tools

  • DigitalOceanCloud hosting built for developers — $200 free credit for new users
  • DockerDevelop faster. Run anywhere.