A web-based management dashboard for Ubuntu Linux that provides a unified interface for managing:
- ZFS Storage Pools — Create and manage ZFS pools, datasets, and snapshots
- iSCSI Targets — Configure LIO iSCSI targets, backstores, LUNs, and ACLs
- NFS Exports — Manage NFS exports and client access
- SMB/CIFS Shares — Create and manage Samba shares and users
- LVM — Manage physical volumes, volume groups, and logical volumes
- MD RAID — Create and manage Linux software RAID arrays
Built with Python/Flask backend and a dark-theme single-page web UI with SVG icons and service cards.
┌─────────────────────────────────────────────────────┐
│ Web Browser │
│ https://<host>:4043 │
└──────────────────────┬──────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────┐
│ Flask Web Server (port 4043, HTTPS) │
│ /opt/storage-dashboard/app.py │
│ Runs as: dashboard user │
└───────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┘
│ │ │ │ │ │
┌────▼────┐ ┌──▼───┐ ┌───▼────┐ ┌──▼────┐ ┌──▼───┐ ┌───▼────┐
│ ZFS │ │iSCSI │ │ NFS │ │ SMB │ │ LVM │ │MD RAID │
│zfsutils │ │LIO │ │nfs-ker-│ │samba │ │lvm2 │ │mdadm │
│ │ │target│ │nel-svr │ │ │ │ │ │ │
└────────┘ └──────┘ └────────┘ └───────┘ └──────┘ └────────┘
All managed via sudo with passwordless sudoers rules
- Ubuntu 22.04 or 24.04 LTS
- Root or sudo access
- At least one unused disk for ZFS pools (optional)
curl -sk https://github.com/brainchillz/StorageDashboard/raw/main/bootstrap.sh | sudo bashThis clones the repo from GitLab and runs the full installer. The -sk flag skips SSL verification (the GitLab instance uses a self-signed certificate).
git clone https://github.com/brainchillz/StorageDashboard.git /opt/storage-dashboard
cd /opt/storage-dashboard
sudo bash install.sh# 1. Install system dependencies
sudo apt-get update
sudo apt-get install -y python3 python3-pip python3-venv \
zfsutils-linux targetcli-fb nfs-kernel-server samba \
smbclient cifs-utils nfs-common lsscsi curl acl lvm2 mdadm
# 2. Create the directory and files
sudo mkdir -p /opt/storage-dashboard/static/css /opt/storage-dashboard/templates
# Copy all project files into /opt/storage-dashboard/
# 3. Create the dashboard user
sudo useradd -r -s /usr/sbin/nologin -M -d /opt/storage-dashboard dashboard
# 4. Set up Python virtual environment
sudo python3 -m venv /opt/storage-dashboard/venv
sudo /opt/storage-dashboard/venv/bin/pip install flask flask-cors
# 5. Set up sudoers (file: /etc/sudoers.d/storage-dashboard)
sudo tee /etc/sudoers.d/storage-dashboard << 'EOF'
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/zpool
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/zfs
dashboard ALL=(ALL) NOPASSWD: /usr/bin/targetcli
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/exportfs
dashboard ALL=(ALL) NOPASSWD: /usr/bin/systemctl
dashboard ALL=(ALL) NOPASSWD: /bin/systemctl
dashboard ALL=(ALL) NOPASSWD: /usr/bin/tee
dashboard ALL=(ALL) NOPASSWD: /usr/bin/mkdir
dashboard ALL=(ALL) NOPASSWD: /bin/mkdir
dashboard ALL=(ALL) NOPASSWD: /usr/bin/chown
dashboard ALL=(ALL) NOPASSWD: /bin/chown
dashboard ALL=(ALL) NOPASSWD: /usr/bin/chmod
dashboard ALL=(ALL) NOPASSWD: /bin/chmod
dashboard ALL=(ALL) NOPASSWD: /bin/lsblk
dashboard ALL=(ALL) NOPASSWD: /usr/bin/lsblk
dashboard ALL=(ALL) NOPASSWD: /sbin/lsblk
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/lsscsi
dashboard ALL=(ALL) NOPASSWD: /bin/journalctl
dashboard ALL=(ALL) NOPASSWD: /usr/bin/journalctl
dashboard ALL=(ALL) NOPASSWD: /sbin/zpool
dashboard ALL=(ALL) NOPASSWD: /sbin/zfs
dashboard ALL=(ALL) NOPASSWD: /bin/zpool
dashboard ALL=(ALL) NOPASSWD: /bin/zfs
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/smbd
dashboard ALL=(ALL) NOPASSWD: /usr/bin/testparm
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/ufw
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/parted
dashboard ALL=(ALL) NOPASSWD: /sbin/parted
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/sgdisk
dashboard ALL=(ALL) NOPASSWD: /sbin/sgdisk
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/sfdisk
dashboard ALL=(ALL) NOPASSWD: /sbin/sfdisk
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/wipefs
dashboard ALL=(ALL) NOPASSWD: /sbin/wipefs
dashboard ALL=(ALL) NOPASSWD: /sbin/blkid
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/blkid
dashboard ALL=(ALL) NOPASSWD: /bin/blkid
# LVM
dashboard ALL=(ALL) NOPASSWD: /sbin/pvcreate
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/pvcreate
dashboard ALL=(ALL) NOPASSWD: /sbin/pvremove
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/pvremove
dashboard ALL=(ALL) NOPASSWD: /sbin/pvs
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/pvs
dashboard ALL=(ALL) NOPASSWD: /sbin/vgcreate
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/vgcreate
dashboard ALL=(ALL) NOPASSWD: /sbin/vgremove
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/vgremove
dashboard ALL=(ALL) NOPASSWD: /sbin/vgs
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/vgs
dashboard ALL=(ALL) NOPASSWD: /sbin/lvcreate
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/lvcreate
dashboard ALL=(ALL) NOPASSWD: /sbin/lvremove
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/lvremove
dashboard ALL=(ALL) NOPASSWD: /sbin/lvs
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/lvs
# MDADM
dashboard ALL=(ALL) NOPASSWD: /sbin/mdadm
dashboard ALL=(ALL) NOPASSWD: /usr/sbin/mdadm
EOF
sudo chmod 440 /etc/sudoers.d/storage-dashboard
# 6. Set ownership
sudo chown -R dashboard:dashboard /opt/storage-dashboard
sudo mkdir -p /var/log/storage-dashboard
sudo chown dashboard:dashboard /var/log/storage-dashboard
# 7. Create systemd service
sudo tee /etc/systemd/system/storage-dashboard.service << 'SERVICE'
[Unit]
Description=Ubuntu Storage Management Dashboard
After=network.target zfs.target nfs-server.service smbd.service
Wants=zfs.target nfs-server.service smbd.service
[Service]
Type=simple
User=dashboard
Group=dashboard
WorkingDirectory=/opt/storage-dashboard
ExecStart=/opt/storage-dashboard/venv/bin/python /opt/storage-dashboard/app.py
Restart=on-failure
RestartSec=10
StandardOutput=append:/var/log/storage-dashboard/app.log
StandardError=append:/var/log/storage-dashboard/app.log
[Install]
WantedBy=multi-user.target
SERVICE
# 8. Enable and start services
sudo systemctl daemon-reload
sudo systemctl enable zfs.target
sudo systemctl enable target
sudo systemctl enable nfs-server
sudo systemctl enable smbd
sudo systemctl enable storage-dashboard
sudo systemctl start target nfs-server smbd storage-dashboard
# 9. (Optional) Open firewall ports
sudo ufw allow 4043/tcp comment 'Storage Dashboard'
sudo ufw allow 3260/tcp comment 'iSCSI Target'
sudo ufw allow 2049/tcp comment 'NFS'
sudo ufw allow 445/tcp comment 'SMB'
sudo ufw allow 139/tcp comment 'SMB NetBIOS'Once installed, open a web browser to:
https://<server-ip>:4043
Note: The dashboard uses a self-signed SSL certificate generated during installation. Your browser will show a security warning — accept it to proceed. The cert is stored at
/opt/storage-dashboard/ssl/. To use custom certificates, set theSSL_CERTandSSL_KEYenvironment variables in the systemd service file.
The dashboard homepage shows six large service cards (ZFS, iSCSI, NFS, SMB, LVM, MD RAID) with live status indicators. Use the sidebar to navigate between sections:
| Section | Description |
|---|---|
| Dashboard | Overview with service cards, host stats, and service status table |
| Disks | View available disks on the system |
| ZFS Pools | Create/manage pools, datasets, snapshots |
| iSCSI Targets | Manage iSCSI targets, backstores, LUNs, ACLs |
| NFS Exports | Create and manage NFS shared directories |
| SMB Shares | Create and manage Samba shares and users |
| LVM | Manage physical volumes, volume groups, logical volumes |
| MD RAID | Create and manage Linux software RAID arrays |
| Services | Start/stop/restart/enable/disable/install services |
GET /api/status— Service status overviewGET /api/disks— List available disksGET /api/logs/<service>— Service logs
GET /api/zfs/pools— List poolsPOST /api/zfs/pools— Create pool{name, vdev_type, disks[]}DELETE /api/zfs/pools/<name>— Destroy poolGET /api/zfs/pools/<name>/datasets— List datasetsPOST /api/zfs/datasets— Create dataset{name, properties{}}DELETE /api/zfs/datasets/<name>— Destroy datasetGET /api/zfs/snapshots— List snapshotsPOST /api/zfs/snapshots— Create snapshot{dataset, snap_name}POST /api/zfs/snapshots/rollback— Rollback{snapshot}
POST /api/iscsi/targets— Create target{iqn}DELETE /api/iscsi/targets/<iqn>— Delete targetPOST /api/iscsi/backstores— Create backstore{type, name, path, size}POST /api/iscsi/luns— Create LUN{iqn, backstore_type, backstore_name, lun_id}POST /api/iscsi/acls— Create ACL{iqn, initiator_iqn}POST /api/iscsi/saveconfig— Save config to disk
GET /api/nfs/exports— List exportsPOST /api/nfs/exports— Create export{path, clients[{host, options}]}DELETE /api/nfs/exports/<path>— Remove export
GET /api/smb/shares— List sharesPOST /api/smb/shares— Create share{name, path, ...}DELETE /api/smb/shares/<name>— Remove sharePOST /api/smb/users— Create SMB user{username, password}
GET /api/lvm/physicalvolumes— List PVsPOST /api/lvm/physicalvolumes— Create PV{device}DELETE /api/lvm/physicalvolumes/<device>— Remove PVGET /api/lvm/volumegroups— List VGsPOST /api/lvm/volumegroups— Create VG{name, devices[]}DELETE /api/lvm/volumegroups/<name>— Remove VGGET /api/lvm/logicalvolumes— List LVsPOST /api/lvm/logicalvolumes— Create LV{name, vg, size}DELETE /api/lvm/logicalvolumes/<vg>/<name>— Remove LV
GET /api/mdadm/arrays— List arrays (with detail parsing)POST /api/mdadm/arrays— Create array{name, level, devices[]}DELETE /api/mdadm/arrays/<name>— Stop and remove arrayGET /api/mdadm/arrays/<name>/detail— Get parsed detailPOST /api/mdadm/arrays/<name>/stop— Stop arrayPOST /api/mdadm/arrays/<name>/start— Assemble/start arrayPOST /api/mdadm/arrays/<name>/manage— Manage device{action, device}
/opt/storage-dashboard/
├── app.py # Flask backend (~930 lines)
├── install.sh # Automated installation script
├── bootstrap.sh # Bootstrap installer (curl | sudo bash)
├── requirements.txt # Python dependencies
├── opencode.md # Project baseline for AI tools
├── .gitignore
├── README.md
├── static/
│ └── css/
│ └── style.css # Dark theme UI styles
└── templates/
└── index.html # Single-page web application (~800 lines)
# View status
sudo systemctl status storage-dashboard
# View logs
sudo journalctl -u storage-dashboard -f
# Restart
sudo systemctl restart storage-dashboard
# Stop
sudo systemctl stop storage-dashboardCheck if the service is running:
sudo systemctl status storage-dashboardCheck logs for errors:
sudo journalctl -u storage-dashboard --no-pager -n 50Test API directly (authenticate first):
# Login and capture session cookie
curl -sk -c /tmp/dash.cookie -X POST https://localhost:4043/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"your-password"}'
# Use the cookie for authenticated requests
curl -sk -b /tmp/dash.cookie https://localhost:4043/api/statusReset password:
sudo systemctl stop storage-dashboard
sudo rm /opt/storage-dashboard/users.json
sudo systemctl start storage-dashboard
# Then visit the dashboard UI for first-time setupCheck sudoers permissions (run as dashboard user):
sudo -u dashboard sudo -n /usr/sbin/zpool listIf ZFS module is not loaded:
sudo modprobe zfsIf targetcli fails with lockfile error:
sudo rm -f /var/run/targetcli.lockHard refresh if styles don't load after update:
Cmd+Shift+R (Mac) or Ctrl+F5 (Windows/Linux)
MIT