Connect Your Ubuntu Desktops to Private Storage on ZCP
Mount the file share from Deploy Private Shared Storage on the desktop from Deploy Ubuntu Employee Desktops, as part of provisioning that desktop, before the employee ever receives their RDP login. The employee ends up with a persistent, shared place for company files that survives VM rebuilds and isn’t tied to any one desktop, without doing anything themselves.
About 10 minutes per desktop.
Before you start
Section titled “Before you start”- Deploy Private Shared Storage on ZCP complete: an NFS share up and reachable over the tier, and the storage VM’s tier IP saved from that script’s own summary output. There’s no reliable way to look up an existing VM’s tier IP after the fact, only what the script printed once.
- Deploy Ubuntu Employee Desktops on ZCP complete: a desktop VM with its named employee login created via cloud-init.
- SSH access to the desktop still working: the same key from the desktop tutorial, loaded in your
SSH agent or default location. The script connects as
ubuntuusing that existing access, locked down to your own IP in the desktop tutorial, and doesn’t take an SSH key or password flag of its own. - The
zcpCLI installed and authenticated (zcp auth validate), from the setup in Build a Private Network.jqinstalled too: the script uses thezcpCLI to resolve the desktop’s public IP from--desktop-name, the same way earlier scripts in this series resolve resources by name. - The employee doesn’t have their RDP login yet. Run this script while access to the desktop is still SSH-only, through you.
Run the script
Section titled “Run the script”Mounting the storage share on a desktop, confirming the employee account, installing the NFS client,
and adding the persistent /etc/fstab entry is one script: zcp/connect-desktop-to-storage.sh from
the zsoftly/tools repository. It connects over SSH and runs
through the phases explained in the next section, in order.
bash <(curl -fsSL https://raw.githubusercontent.com/zsoftly/tools/main/zcp/connect-desktop-to-storage.sh) \ --desktop-name jane-doe-desktop --storage-tier-ip <storage-vm-tier-ip> --username janedoe \ --region yul-1 --project default-9This tutorial continues jane-doe-desktop and janedoe from the desktop tutorial’s own example,
and <storage-vm-tier-ip> from the storage tutorial’s script summary. Your own values will differ
based on the --name and --username you used there and the tier IP printed for your own storage
VM.
The script picks up ZCP_REGION and ZCP_PROJECT from your shell if you exported them. Pass
--region/--project instead if you didn’t.
| Flag | Purpose | Default / requirement |
|---|---|---|
--desktop-name | The desktop VM’s name, from the desktop tutorial | Required |
--storage-tier-ip | The storage VM’s tier IP, from the storage tutorial’s script summary | Required |
--username | The employee’s Linux login on the desktop | Required |
--share-name | NFS share directory name | company-share |
--region | zcp region slug | Required (flag or env var) |
--project | zcp project slug | Required (flag or env var) |
--storage-tier-ip isn’t auto-discovered. Unlike the desktop, which the script resolves by name
through the zcp CLI, an existing storage VM’s tier IP has no equivalent lookup after deployment.
The storage tutorial’s own script summary is the only place it’s printed.
--share-name must match the storage VM’s own --share-name from the storage tutorial. It defaults
to company-share on both scripts, so most runs leave it out entirely.
What the script does
Section titled “What the script does”Confirms the employee account exists
Section titled “Confirms the employee account exists”The script SSHes to the desktop as ubuntu, the same admin access already locked down to your own
IP in the desktop tutorial, and confirms the --username account exists before doing anything else.
Installs the NFS client
Section titled “Installs the NFS client”nfs-common isn’t present by default on the ubuntukde template. This mirrors the mesh-client
check from
Deploy Private Shared Storage:
the same install-mount-verify sequence, already proven reachable over the mesh from a generic
client. Over the same SSH connection, this looks like:
sudo apt-get update && sudo apt-get install -y nfs-commonMounts the share
Section titled “Mounts the share”sudo mkdir -p /mnt/company-sharesudo mount -t nfs <storage-vm-tier-ip>:/srv/nfs/company-share /mnt/company-sharesudo mount always runs as root, regardless of which user’s SSH session invoked it, so the mount
itself never decides file ownership. NFS enforces permissions by raw UID number, not by username.
Ownership comes from who writes a file afterward, not who ran the mount. That’s why the verification
step below writes specifically as the employee, separately from mounting.
You can see the raw-UID behavior for yourself from your own local machine, not the desktop:
ssh ubuntu@<storage-vm-public-ip>
ls -la /srv/nfs/company-share/A file written under an employee’s UID shows correctly by name when viewed from the desktop, but shows as a bare number when viewed from the storage server specifically, since it has no local user at that UID. That part is harmless, cosmetic only. A different desktop is not the same case: if it has its own local user at that same UID (likely, since every desktop gets the same UID by default unless you assigned unique ones), the file shows under that user’s name there too, even though it’s a different employee. The UID match or mismatch between desktops is what matters, not whether any one machine can resolve a name for it.
Verifies the mount works, as the employee
Section titled “Verifies the mount works, as the employee”A mount command returning success doesn’t prove the share is usable, and it doesn’t prove the
employee can write to it under their own UID either. The script switches to the employee with
sudo -u <username>, writes a uniquely named test file to the mount, reads it back, then deletes
it. sudo -u is ubuntu’s own privilege to run a command as another local user; the employee
doesn’t authenticate for this, and nothing is left on the share afterward for you to inspect.
To see the same idea yourself, run an equivalent check manually over SSH:
df -h /mnt/company-sharesudo -u janedoe sh -c 'echo "hello from desktop" > /mnt/company-share/from-desktop.txt'cat /mnt/company-share/from-desktop.txtls -la /mnt/company-share/This is optional. It repeats the same check the script already ran; run it again only if you want to see it for yourself.
Adds the persistent fstab entry
Section titled “Adds the persistent fstab entry”For a mount that survives reboots, the script appends an entry to /etc/fstab on the desktop:
<storage-vm-tier-ip>:/srv/nfs/company-share /mnt/company-share nfs defaults,noatime,nofail,_netdev 0 0nofail keeps a boot from hanging if the storage VM is briefly unreachable when the desktop starts.
_netdev tells systemd to wait for the network before attempting the mount at all. Both matter here
in a way they wouldn’t for a local disk. This platform has no console access, so a desktop that
stalls at boot over an NFS mount has no recovery path, unlike a local-disk boot failure.
Re-running the script against the same desktop is safe. It skips the mount and fstab steps if
they’re already in place rather than duplicating them or failing. If you’re pointing it at a
different storage VM, a changed tier IP, unmount first: sudo umount /mnt/company-share over SSH.
The script errors on a mismatched source instead of silently switching it for you.
Confirm it in Dolphin before handoff
Section titled “Confirm it in Dolphin before handoff”One thing the script can’t check for you: Dolphin, the KDE file manager, surfaces the mounted share automatically under Places → Remote rather than Devices, but confirming that needs an actual RDP session. Log in once yourself, using the password from the desktop tutorial’s own script summary, and check Places → Remote before handing the login over to the employee.
Repeat for each desktop
Section titled “Repeat for each desktop”Run the script again for the next desktop, with that desktop’s own --desktop-name and
--username. This becomes a step in the standard onboarding flow, before handing off RDP
credentials each time. If your organization needs separate ownership per employee, that decision
still happens in
Give this desktop a unique identity on shared storage,
before the employee’s first login.
Clean up
Section titled “Clean up”sudo umount /mnt/company-shareRun this the same way as everything else in this tutorial: over SSH, not inside an RDP session.
Remove the fstab entry only if you’re tearing down a test desktop:
sudo sed -i '\#/mnt/company-share#d' /etc/fstabIn normal operation this mount is meant to be permanent.
connect-desktop-to-storage.sh --desktop-name <name> --storage-tier-ip <ip> \ --username <login> --region yul-1 --project default-9- Run the script against a desktop before handing off its RDP credentials, with the storage VM’s tier IP from the storage tutorial’s script summary.
- The script confirms the employee account, installs
nfs-common, mounts the share through your existingubuntuSSH access, then verifies it by writing and reading a test file as the employee (sudo -u <username>), confirming ownership under their own UID, and adds a persistentfstabentry. Safe to re-run against the same desktop. - Log in once yourself with the employee’s password, from the desktop tutorial’s own summary, to confirm the share appears in Dolphin under Places → Remote, then hand the credentials to the employee.
- Run the script again for each additional desktop.
Troubleshooting: adding storage to a desktop the employee already used
Section titled “Troubleshooting: adding storage to a desktop the employee already used”This section applies if you or the employee have logged in via RDP before applying the identity fix
in
Give this desktop a unique identity on shared storage.
That includes the Dolphin check above: logging in yourself to confirm the share starts a real KDE
session under the employee’s own account, the same as the employee’s first login would. If no one
has logged in yet, usermod and groupmod apply cleanly, with no extra steps.
If a login already happened, the fix still works, with two extra hurdles.
usermod refuses while the employee has an active session. A logged-in desktop session is a lot
of processes (KDE, xrdp, the shell, all of it):
usermod: user janedoe is currently used by process 2357Closing the RDP client window does not end the session. This is a real gotcha, not a guess:
closing the window and reconnecting later showed every process still running, identical PIDs. The
session and everything in it stays alive on the server. Only the display connection drops. From your
own local machine, SSH in as ubuntu (not the employee’s RDP session, which is what’s being ended):
ssh ubuntu@<desktop-vm-public-ip>
sudo loginctl terminate-user janedoepgrep -u janedoe || echo "no processes left"Only once that shows no processes left does the fix succeed. Re-run the usermod/groupmod/chown
commands from
Give this desktop a unique identity on shared storage,
then the employee can log back in immediately with the same username and password, home directory
and sudo access both intact.
chown from the desktop doesn’t fix files already written under the old UID. The export uses
root_squash, which strips root’s power over the share specifically to stop a compromised client
from claiming root privileges on shared storage. That’s exactly what blocks a client-side
retroactive fix too, for any file that predates the identity change, for example a file named
notes.txt already on the share (not something the script itself leaves behind; its own
verification file deletes itself):
$ sudo chown 2001:2001 /mnt/company-share/notes.txtchown: changing ownership of '/mnt/company-share/notes.txt': Operation not permittedRun the same chown from the storage VM’s own local filesystem instead, where root_squash
doesn’t apply since it’s not a remote client request. From your own local machine:
ssh ubuntu@<storage-vm-public-ip>
sudo chown 2001:2001 /srv/nfs/company-share/notes.txtAnything written after the fix gets the correct owner automatically. Only files that predate it need this manual step.
Next steps
Section titled “Next steps”- Deploy Private Shared Storage: the share this tutorial mounts
- Deploy Ubuntu Employee Desktops: the desktop this tutorial connects, before RDP credentials are handed off
- CLI reference: every command and flag
- Tutorials overview: the full list of available tutorials