iSCSI lets you present a remote disk to a Linux server as if it were
plugged in locally, using the standard IP network. Unlike NFS, which shares
files, iSCSI shares raw blocks: the client sees a real disk (/dev/sda),
formats it and mounts it like a local disk. This guide covers the full
configuration of a target (server) with targetcli and of an initiator
(client) with open-iscsi on Ubuntu 24.04; every command was tested in a KVM
lab.
What you will learn
- How iSCSI works: protocol, vocabulary, architecture
- Target (server):
targetcli, block and fileio backstores, IQN, TPG - LUNs and ACLs: expose disks and control access
- Initiator (client):
open-iscsi, discovery, login, mount - CHAP security: one-way and mutual authentication
- Persistent mount:
/etc/fstabwith_netdev - Troubleshooting: frequent errors and tested fixes
What is iSCSI?
iSCSI (Internet Small Computer Systems Interface) is a protocol that carries SCSI commands (the standard language of hard disks) across a classic TCP/IP network. It turns any server into a network storage array (SAN) without specialised hardware.
iSCSI vs NFS: two complementary approaches
| Criterion | iSCSI | NFS |
|---|---|---|
| Type of sharing | Block (raw disk) | Files (directory) |
| What the client sees | /dev/sdX, a disk | /mnt/nfs, a folder |
| File system | Chosen by the client (ext4, xfs...) | Managed by the server |
| Multi-client | A single client per LUN (except clustered FS) | Several clients at once |
| Performance | Excellent (close to a local disk) | Good |
| Use cases | Databases, VMs, block storage | File shares, configs, homes |
| Port | 3260/tcp | 2049/tcp |
The iSCSI vocabulary
Before starting, here are the terms you will come across:
| Term | Definition |
|---|---|
| Target | The server that exposes the disks |
| Initiator | The client that connects and uses the disks |
| IQN | Unique identifier (iSCSI Qualified Name), format: iqn.YYYY-MM.domain:identifier |
| TPG | Target Portal Group, network access point (IP:port) |
| LUN | Logical Unit Number, a disk exposed in a TPG |
| Backstore | The physical storage behind a LUN (partition, file, LVM volume) |
| ACL | Access Control List, controls which initiator reaches which LUN |
| CHAP | Challenge-Handshake Authentication Protocol, password authentication |
| Portal | IP:port pair the target listens on (default: 0.0.0.0:3260) |
Prerequisites
- 2 Ubuntu 24.04 machines (physical or virtual)
- Network connectivity between the two
- root or
sudoaccess on both machines - Port 3260/tcp open between the target and the initiator
- On the target: an additional disk or partition to expose
To reproduce this lab, two KVM VMs are enough: a target (192.168.122.50,
with a 10 GB /dev/vdb disk) and an initiator (192.168.122.225).
Lab architecture
The lab links two machines through the single port 3260. The target exposes two LUNs of different kinds, a partition in block mode and an image file in fileio mode, to compare both backstores on the same initiator:
┌──────────────────────────┐ TCP/3260 ┌──────────────────────────┐│ storage-srv │◄────────────────────────►│ storage-cli ││ (iSCSI target) │ │ (iSCSI initiator) ││ │ │ ││ targetcli-fb │ │ open-iscsi ││ /dev/vdb1 (5 GB block) │ ──── LUN 0 ────► │ /dev/sda → /mnt/iscsi ││ 1 GB file (fileio) │ ──── LUN 1 ────► │ /dev/sdb → /mnt/file ││ │ │ ││ IP: 192.168.122.50 │ │ IP: 192.168.122.225 │└──────────────────────────┘ └──────────────────────────┘Configure the target (server)
The target is the server that exposes its disks via iSCSI. On Linux, you
use LIO (Linux-IO Target), the iSCSI target framework built into the
kernel, driven by the targetcli command.
Install targetcli
sudo apt updatesudo apt install targetcli-fbThe targetcli-fb package ("free branch") is the actively maintained
version of the project. It provides the targetcli command to configure
backstores, targets and ACLs through an interactive shell.
Enable the service so that the configuration persists after a reboot:
sudo systemctl enable rtslib-fb-targetctlPrepare the storage
iSCSI can expose several types of storage as a backend (called backstores). The two most common:
| Type | Description | Performance | Use case |
|---|---|---|---|
| block | Partition, disk or LVM volume | Excellent | Databases, production |
| fileio | Image file on the file system | Good | Tests, prototyping |
For the lab, create both types:
block backstore: partition the additional disk.
sudo parted /dev/vdb mklabel gptsudo parted /dev/vdb mkpart iscsi-lun1 ext4 0% 50%sudo parted /dev/vdb mkpart iscsi-lun2 ext4 50% 100%fileio backstore: create an image file.
sudo mkdir -p /srv/iscsisudo dd if=/dev/zero of=/srv/iscsi/lun-file.img bs=1M count=1024Configure with targetcli
Start the interactive targetcli shell and create the whole structure:
sudo targetcli-
Create the backstores: declare the physical storage media.
/> cd /backstores/block/backstores/block> create lun-data /dev/vdb1/backstores/block> cd /backstores/fileio/backstores/fileio> create lun-file /srv/iscsi/lun-file.imgEach backstore gets a logical name (
lun-data,lun-file) that identifies it in the configuration. -
Create the iSCSI target: define the identity of the storage server.
/> cd /iscsi/iscsi> create iqn.2026-03.lab.storage:target01The IQN (iSCSI Qualified Name) follows the format
iqn.YYYY-MM.reversed.domain:identifier. It identifies the target uniquely on the network. A TPG (Target Portal Group) is created automatically. -
Create an ACL for the initiator: allow the client to connect.
/> cd /iscsi/iqn.2026-03.lab.storage:target01/tpg1/acls/iscsi/.../acls> create iqn.2026-03.lab.storage:client01The ACL controls which initiator can reach the target. The IQN must match exactly the name configured on the client.
-
Map the LUNs: attach the backstores to the target.
/> cd /iscsi/iqn.2026-03.lab.storage:target01/tpg1/luns/iscsi/.../luns> create /backstores/block/lun-data/iscsi/.../luns> create /backstores/fileio/lun-fileEach LUN gets an automatic number (LUN 0, LUN 1...). LUNs are automatically mapped to the existing ACLs.
-
Check and save:
/> ls //> saveconfig/> exit
Expected result of ls /:
o- / .............................................................. [...] o- backstores ................................................... [...] | o- block ........................................... [Storage Objects: 1] | | o- lun-data ................ [/dev/vdb1 (5.0GiB) write-thru activated] | o- fileio .......................................... [Storage Objects: 1] | o- lun-file . [/srv/iscsi/lun-file.img (1.0GiB) write-back activated] o- iscsi ................................................. [Targets: 1] o- iqn.2026-03.lab.storage:target01 ........................ [TPGs: 1] o- tpg1 ........................................ [gen-acls, no-auth] o- acls ............................................... [ACLs: 1] | o- iqn.2026-03.lab.storage:client01 ......... [Mapped LUNs: 2] o- luns ............................................... [LUNs: 2] | o- lun0 .................. [block/lun-data (/dev/vdb1) (default)] | o- lun1 .. [fileio/lun-file (/srv/iscsi/lun-file.img) (default)] o- portals ........................................ [Portals: 1] o- 0.0.0.0:3260 .......................................... [OK]Check: port 3260 is indeed listening.
sudo ss -tlnp | grep 3260LISTEN 0 256 0.0.0.0:3260 0.0.0.0:*The line carries no process, even with -p: the LIO target listens
from the kernel, not from targetcli, which is only a configuration tool
and exits once the session is closed.
Configure the initiator (client)
The initiator is the client that connects to the target to use the remote
disks. On Linux, the open-iscsi package provides the necessary tools.
Install open-iscsi
sudo apt updatesudo apt install open-iscsi lsscsiThe lsscsi package is optional but very useful to list the detected SCSI
devices.
Configure the initiator name
Each initiator has a unique IQN stored in /etc/iscsi/initiatorname.iscsi.
This name must match exactly the ACL configured on the target:
echo "InitiatorName=iqn.2026-03.lab.storage:client01" | sudo tee /etc/iscsi/initiatorname.iscsisudo systemctl restart iscsidDiscover the target
Discovery queries the target to list the available resources:
sudo iscsiadm -m discovery -t sendtargets -p 192.168.122.50192.168.122.50:3260,1 iqn.2026-03.lab.storage:target01The target answers with its IQN and its portal (IP:port). This information is stored locally for future connections.
Connect (login)
sudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 --loginLogging in to [iface: default, target: iqn.2026-03.lab.storage:target01, portal: 192.168.122.50,3260]Login to [...] successful.Check: list the active sessions.
sudo iscsiadm -m session -o showtcp: [1] 192.168.122.50:3260,1 iqn.2026-03.lab.storage:target01 (non-flash)Check the disks
After the login, the LUNs appear as classic SCSI disks:
lsscsi[0:0:0:0] cd/dvd QEMU QEMU DVD-ROM 2.5+ /dev/sr0[6:0:0:0] disk LIO-ORG lun-data 4.0 /dev/sda[6:0:0:1] disk LIO-ORG lun-file 4.0 /dev/sdbThe two LUNs are visible: lun-data (5 GB, block) on /dev/sda and
lun-file (1 GB, fileio) on /dev/sdb. The LIO-ORG vendor confirms
that they come from the LIO target.
lsblk /dev/sda /dev/sdbNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTSsda 8:0 0 5G 0 disksdb 8:16 0 1G 0 diskFormat and mount the LUNs
iSCSI LUNs are raw disks. Format them and mount them like any local disk:
# Format as ext4sudo mkfs.ext4 /dev/sdasudo mkfs.ext4 /dev/sdb
# Create the mount pointssudo mkdir -p /mnt/iscsi-data /mnt/iscsi-file
# Mountsudo mount /dev/sda /mnt/iscsi-datasudo mount /dev/sdb /mnt/iscsi-fileCheck: write data and verify.
echo "Données critiques sur iSCSI block" | sudo tee /mnt/iscsi-data/test.txtcat /mnt/iscsi-data/test.txtDonnées critiques sur iSCSI blockPerformance benchmark
# Write (100 MB, direct I/O)dd if=/dev/zero of=/mnt/iscsi-data/bench bs=1M count=100 oflag=direct
# Readdd if=/mnt/iscsi-data/bench of=/dev/null bs=1M iflag=directOn our lab (virtio network, same KVM host):
| Direction | Measured throughput |
|---|---|
| Write | ~866 MB/s |
| Read | ~1.7 GB/s |
On this lab, iSCSI in block mode writes much faster than NFS, because the client handles the file system directly, without the overhead of a file protocol. Both measurements share the same limit: client and server on the same host, so a throughput that mostly reflects memory.
Persistent mount via /etc/fstab
For the LUNs to mount automatically at boot:
/dev/sda /mnt/iscsi-data ext4 defaults,_netdev 0 0/dev/sdb /mnt/iscsi-file ext4 defaults,_netdev 0 0The _netdev option is essential: it tells the system to wait for the
network (and therefore the iSCSI session) to be up before mounting.
Automatic connection at boot
For the initiator to reconnect automatically to the target at boot:
sudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 \ -o update -n node.startup -v automaticCheck that the parameter is saved:
sudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 | grep node.startupnode.startup = automaticSecure with CHAP
By default, any initiator knowing the IQN and the IP of the target can connect. The CHAP protocol (Challenge-Handshake Authentication Protocol) adds authentication by user name and password.
One-way CHAP (the most common)
The target checks the identity of the initiator. It is enough in most cases.
Target side (in targetcli):
sudo targetcli/> cd /iscsi/iqn.2026-03.lab.storage:target01/tpg1/iscsi/.../tpg1> set attribute authentication=1/iscsi/.../tpg1> cd acls/iqn.2026-03.lab.storage:client01/iscsi/.../client01> set auth userid=labuser/iscsi/.../client01> set auth password=S3cur3P4ssw0rd/> saveconfig/> exitInitiator side: log out, configure CHAP, then log in again.
# Log outsudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 --logout
# Configure CHAPsudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 \ -o update -n node.session.auth.authmethod -v CHAP
sudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 \ -o update -n node.session.auth.username -v labuser
sudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 \ -o update -n node.session.auth.password -v S3cur3P4ssw0rd
# Log in again with CHAPsudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 --loginLogin to [...] successful.Check: the session is active with authentication.
sudo iscsiadm -m session -o showtcp: [2] 192.168.122.50:3260,1 iqn.2026-03.lab.storage:target01 (non-flash)The disks are available again. Mount them again:
sudo mount /dev/sda /mnt/iscsi-datasudo mount /dev/sdb /mnt/iscsi-filecat /mnt/iscsi-data/test.txtDonnées critiques sur iSCSI blockThe data is intact after the logout/login.
Mutual (two-way) CHAP
For environments where the target must also prove its identity to the initiator (preventing spoofing), configure mutual CHAP:
Target side: add the reverse credentials.
/iscsi/.../client01> set auth mutual_userid=target-srv/iscsi/.../client01> set auth mutual_password=T4rg3tS3cur3dInitiator side:
sudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 \ -o update -n node.session.auth.username_in -v target-srv
sudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 \ -o update -n node.session.auth.password_in -v T4rg3tS3cur3dManage iSCSI sessions
List the active sessions
A session matches an open connection to a target. Listing them is the first gesture before any logout or any diagnosis:
sudo iscsiadm -m session -o showLog out cleanly
Before logging out, unmount the file systems:
sudo umount /mnt/iscsi-data /mnt/iscsi-filesudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 --logoutDelete a recorded target
To forget a target completely (discovery + node):
sudo iscsiadm -m node \ -T iqn.2026-03.lab.storage:target01 \ -p 192.168.122.50 -o deleteSee the configuration on the target side
On the server, look at the active configuration:
sudo targetcli ls /The full configuration is saved in /etc/rtslib-fb-target/saveconfig.json.
Back up this file for recovery after an incident.
Good practices in production
Dedicated network
In production, isolate iSCSI traffic on a dedicated network or VLAN:
- Avoids congestion with application traffic
- Reduces the attack surface (CHAP is not encryption)
- Lets you configure jumbo MTU (9000) for performance
Multipath (high availability)
For critical servers, configure multipath-tools to use several network paths to the same target:
sudo apt install multipath-toolsMultipath provides:
- Redundancy: if a path goes down, traffic fails over automatically
- Performance: bandwidth aggregation over the active paths
Sizing
These values are starting points for production, to compare with your own measurements: an undersized storage network shows up first in database latency.
| Parameter | Recommendation |
|---|---|
| Network | 10 Gbps minimum for databases |
| MTU | 9000 (jumbo frames) if the network supports it |
| Backstores | Block (partition/LVM) for production, fileio for tests |
| CHAP | Always enabled, even on an isolated network |
| Config backup | Copy /etc/rtslib-fb-target/saveconfig.json regularly |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Discovery returns nothing | Port 3260 filtered | sudo ufw allow 3260/tcp then ss -tlnp | grep 3260 on the target |
| Login refused without a clear message | Initiator IQN matches no ACL | Check that the IQN in /etc/iscsi/initiatorname.iscsi is identical to the ACL in targetcli |
| Login fails with CHAP | Wrong password, or outside the 12 to 16 character range some initiators require | Check userid/password on the target AND on the initiator |
| Disks not visible after login | LUNs not mapped in the TPG | In targetcli: check ls /iscsi/.../tpg1/luns |
/dev/sdX changes after reboot | Dynamic device names | Use UUID=... in /etc/fstab instead of /dev/sdX |
| Mount at boot fails | iSCSI session not yet established | Add _netdev in fstab + node.startup = automatic |
Read-only file system after reconnection | File system flagged in error | sudo fsck /dev/sda then mount again |
| Slow performance | MTU 1500 on a dedicated network | Switch to MTU 9000 (jumbo frames) on all interfaces |
| Target does not start at boot | rtslib-fb-targetctl service disabled | sudo systemctl enable rtslib-fb-targetctl |
Key points
- iSCSI carries disk commands (SCSI) over the TCP/IP network: the client
sees a real block disk (
/dev/sdX) - The target (server) exposes the disks via
targetcli, the initiator (client) connects to it viaopen-iscsi - Backstores define the physical storage: block (partition, LVM) for production, fileio (file) for tests
- Each target and initiator is identified by a unique IQN, the match between the ACLs and the initiatorname is mandatory
- Enable CHAP systematically: it is the only authentication built into the protocol
- The
_netdevoption in/etc/fstabis essential for iSCSI mounts at boot - In production, dedicate a network or VLAN to iSCSI traffic and use multipath for high availability
Knowledge check
Check that the essentials of this guide are acquired. The questions only cover what has just been explained here.
Knowledge check
Check what you have learned with this interactive quiz
How it works
- The timer starts when you click Start
- Multiple choice, true/false and short answer questions
- You can move between questions
- Detailed results are shown at the end
Starts the quiz and the timer
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: Analyse disk performance on Linux
A new full quiz with random questions
Work again only on the questions you missed