Configuring Fedora Server as an iSCSI Target with targetcli: Sharing Block Storage Over a Local Network

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

Context: When Do You Actually Need iSCSI?

Running a home virtualization lab or working in a small team environment, I constantly run into the same problem: Machine A has 500GB of free disk space, and Machine B needs more storage to run VMs. NFS handles file-level sharing just fine, but when you need a real block device — for instance, to format ext4 directly, mount it like a physical disk, or use it as a datastore for VMware/Proxmox — iSCSI is the right choice.

I’ve been using Fedora as my primary development machine for two years and I’m quite happy with its fast package update cycle. When setting up lab storage for the team, choosing Fedora Server as the iSCSI target was a natural decision — targetcli is available in the official repo, well-documented, and its interactive shell is very intuitive.

How does iSCSI work? Simply put: you expose a block device (a file, LVM volume, or physical disk) from the target machine over TCP/IP. The initiator (client) connects to it and sees it as a standard SCSI disk — fully partitionable, formattable, and mountable.

The advantages over NFS: lower latency for block workloads, support for exclusive locking in cluster environments, and the initiator doesn’t need to know what filesystem the target is using.

Installing targetcli and Preparing the Environment

On Fedora Server, the main package is targetcli-fb (a community fork of the original Red Hat targetcli):

sudo dnf install -y targetcli-fb

Start and enable the service:

sudo systemctl enable --now target

Open the firewall for the iSCSI port (3260/TCP):

sudo firewall-cmd --permanent --add-service=iscsi-target
sudo firewall-cmd --reload

Check the service status:

sudo systemctl status target

Seeing Active: active (exited) is perfectly normal. The service loads configuration at boot and then exits. With no configuration yet, it has nothing to do.

Configuring the iSCSI Target Step by Step

All configuration is done through targetcli — an interactive shell with filesystem-style navigation:

sudo targetcli

You’ll see the /> prompt. Use ls to view the structure, cd to navigate, and help to see available commands.

Step 1: Create a Backstore

A backstore is where data is actually stored. There are three common types:

File-based — the simplest option, use this when LVM isn’t available:

# Create the directory first
sudo mkdir -p /var/lib/iscsi-storage

# In targetcli:
/backstores/fileio> create storage01 /var/lib/iscsi-storage/disk01.img 20G

Block-based — LVM volume, best choice for production:

# Create an LVM volume
sudo lvcreate -L 50G -n iscsi-vol vg0

# In targetcli:
/backstores/block> create storage02 /dev/vg0/iscsi-vol

RAM disk — for benchmarking only, data is lost on reboot:

/backstores/ramdisk> create ramdisk01 1G

For a home lab, I usually go with fileio since there’s no need to set up LVM. In production, block-based on LVM delivers noticeably better performance.

Step 2: Create the iSCSI Target

An iSCSI target is identified by its IQN (iSCSI Qualified Name) in the format: iqn.YYYY-MM.tld.domain:identifier

/iscsi> create iqn.2026-06.com.itfromzero:storage01

If you don’t specify an IQN, targetcli auto-generates one from the hostname. However, it’s best to set an explicit name for easier management down the line.

Step 3: Create a LUN

Navigate into the TPG (Target Portal Group) of the target you just created:

/iscsi/iqn.2026-06.com.itfromzero:storage01/tpg1/luns> create /backstores/fileio/storage01

LUN 0 will be created automatically and mapped to the specified backstore.

Step 4: Configure the Portal

The portal is the IP address and port the target listens on:

/iscsi/iqn.2026-06.com.itfromzero:storage01/tpg1/portals> create 192.168.1.100 3260

Replace 192.168.1.100 with the actual IP address of your Fedora Server. To listen on all interfaces, use 0.0.0.0.

Step 5: Configure ACLs

This is the most important step for security. By default, TPG runs with generate_node_acls=1 (allowing all initiators). In a production environment, disable this and whitelist each initiator:

/iscsi/iqn.2026-06.com.itfromzero:storage01/tpg1> set attribute generate_node_acls=0

# Add ACL for a specific initiator
/iscsi/iqn.2026-06.com.itfromzero:storage01/tpg1/acls> create iqn.2026-06.com.itfromzero:client01

To add CHAP authentication (username/password):

/iscsi/iqn.2026-06.com.itfromzero:storage01/tpg1/acls/iqn.2026-06.com.itfromzero:client01> set auth userid=iscsiuser password=SecretPass123

Save the Configuration

/> saveconfig
/> exit

The configuration is saved to /etc/target/saveconfig.json. The target service loads this file at boot.

Connecting from the Initiator (Linux Client)

On the client machine — Fedora, Ubuntu, or any Linux distribution:

# Fedora/RHEL
sudo dnf install iscsi-initiator-utils

# Ubuntu/Debian
sudo apt install open-iscsi

Check the client’s IQN (you’ll need to provide this to the target when creating the ACL):

cat /etc/iscsi/initiatorname.iscsi

Discover the target:

sudo iscsiadm -m discovery -t sendtargets -p 192.168.1.100

Expected output:

192.168.1.100:3260,1 iqn.2026-06.com.itfromzero:storage01

Log in to the target:

sudo iscsiadm -m node -T iqn.2026-06.com.itfromzero:storage01 -p 192.168.1.100 --login

Check that the new disk has appeared:

lsblk
# or check dmesg
dmesg | tail -20

You’ll see the device /dev/sdb (or /dev/sdc) appear. From here, format and mount it like any regular disk:

sudo mkfs.ext4 /dev/sdb
sudo mount /dev/sdb /mnt/iscsi-storage

Checking Status and Monitoring

View the Target Structure

sudo targetcli ls

This command displays the entire structure: backstores, targets, LUNs, portals, and ACLs — extremely useful for debugging.

View Active Sessions

sudo targetcli /iscsi/iqn.2026-06.com.itfromzero:storage01/tpg1 sessions

Monitor I/O with iostat

# Install sysstat if not already installed
sudo dnf install sysstat

# Monitor in real-time every 1 second
iostat -x 1

With a fileio backstore, you’ll see I/O on the disk containing the .img file. With a block backstore, you’ll see it directly on the LVM device.

Quick Benchmark from the Initiator

sudo fio --filename=/dev/sdb --rw=read --bs=128k --iodepth=32 \
  --runtime=30 --numjobs=4 --time_based \
  --group_reporting --name=seq-read-test

In my lab (Gigabit LAN, fileio backstore on SSD), sequential read hits around 900–950 MB/s — nearly saturating the 1Gbps link. For higher throughput, consider upgrading to 10GbE or enabling jumbo frames.

A Few Practical Notes

  • SELinux context: If you’re running SELinux in enforcing mode (the default on Fedora), you need to set the correct context for the backstore directory:
    sudo semanage fcontext -a -t tgtd_var_lib_t "/var/lib/iscsi-storage(/.*)?" 
    sudo restorecon -Rv /var/lib/iscsi-storage

    Skipping this step can prevent the target service from reading the backstore file — a silent failure that’s hard to debug.

  • Persistent mount on the initiator: Add to /etc/fstab with the _netdev option to ensure it mounts after the network comes up:
    /dev/sdb  /mnt/iscsi-storage  ext4  _netdev,auto  0  0
  • iSCSI vs NVMe-oF: If you’re running 10GbE+ and need minimum latency, NVMe-oF is a natural upgrade path. But for a 1GbE lab, iSCSI via targetcli is more than sufficient and far simpler to set up.
  • Log out when done: On the initiator, cleanly log out before rebooting the target to avoid hung mounts:
    sudo iscsiadm -m node -T iqn.2026-06.com.itfromzero:storage01 -p 192.168.1.100 --logout

targetcli’s interactive shell is quite user-friendly — just use ls to view the current structure, cd to navigate, and help when you forget a command. Compared to manually editing iSCSI config files directly, targetcli saves significant time and minimizes syntax errors.

Share: