My bash deploy script started failing with a read-only filesystem error on an NFS mount that looked completely healthy. This is the full path from symptom to fix.
Executive Summary#
The root cause was two separate issues compounding each other. The NFS mount was pointing to the wrong path on the Unraid server, and rsync’s default behavior of syncing directory metadata is not compatible with NFS mounts where the target directory is owned by root. Fixing both got the deploy running clean.
Prerequisites#
- A working Unraid server with an NFS share configured
- A Linux workstation with the NFS share mounted
- A deploy script using rsync to push files to the share
- SSH access to the Unraid server
Implementation#
Step 1: Check the Mount#
When you get a read-only error, the first thing to check is whether the filesystem is actually mounted read-only:
mount | grep unraidIf the output shows rw for your NFS mounts, the mount itself is not the problem. Move on to checking the server.
Step 2: Check the Array on Unraid#
A read-only NFS export can happen when Unraid’s array stops or a disk errors, as the server protects itself by making shares read-only. SSH into your Unraid server and check:
mdcmd status | grep -E "mdState|rdevStatus"If the array shows STARTED and all active disks show DISK_OK, the server side is healthy.
Step 3: Remount to Clear Stale NFS State#
If the server is fine but the client is still getting read-only errors, the likely cause is a stale NFS state. The client cached a read-only condition from a previous hiccup and never recovered. Remount to clear it:
sudo umount /mnt/unraid/websites
sudo mount /mnt/unraid/websitesIf the mount fails with can't find in /etc/fstab, the share was mounted manually at some point and never persisted. Mount it explicitly instead:
sudo mount -t nfs YOUR_SERVER_IP:/mnt/user/websites /mnt/unraid/websitesStep 4: Verify the Correct Export Path#
If writing still fails after remounting, the mount may be pointing to the wrong path. Check the actual NFS exports on the Unraid server:
exportfs -v | grep websitesUnraid exports shares from /mnt/cache/sharename when the share is configured to use cache-only storage, not /mnt/user/sharename. If the export path does not match what you are mounting, unmount and remount with the correct path:
sudo umount /mnt/unraid/websites
sudo mount -t nfs YOUR_SERVER_IP:/mnt/cache/websites /mnt/unraid/websites
touch /mnt/unraid/websites/test.txt && echo "Writable!"Step 5: Fix the NFS Security Rule on Unraid#
If the mount is denied entirely, check the NFS security settings for the share in the Unraid web UI under Shares > your-share > NFS Security Settings. If Security is set to Private with no rule defined, no client is allowed to connect.
Add a rule:
*(rw,sec=sys,insecure,anongid=100,anonuid=99,no_root_squash,lock)Key flags:
rwallows read-write accessno_root_squashallows rsync’s chgrp operations to pass throughinsecureallows connections from ports above 1024, required for most Linux NFS clients
Step 6: Fix rsync Metadata Flags#
If files transfer but rsync still exits with errors like this:
rsync: [generator] chgrp "/mnt/unraid/websites/hofiverse/." failed: Operation not permitted
rsync: [generator] failed to set times on "/mnt/unraid/websites/hofiverse/.": Operation not permittedThe problem is rsync trying to sync ownership, timestamps, and permissions on the root target directory, which NFS rejects because the directory is owned by root on the server. Add these flags to your rsync command:
rsync -av --delete --no-group --omit-dir-times --no-perms "$SITE_DIR/public/" "$PROD_DIR/"--no-groupskips syncing group ownership--omit-dir-timesskips setting timestamps on directories--no-permsskips syncing permissions
Step 7: Persist the Mount#
Add the correct mount to /etc/fstab so it survives reboots:
echo 'YOUR_SERVER_IP:/mnt/cache/websites /mnt/unraid/websites nfs rw,relatime,vers=3,hard,proto=tcp,timeo=600,retrans=2,_netdev 0 0' | sudo tee -a /etc/fstab
sudo mount -aLab Notes & Troubleshooting#
The unmount fails with “target is busy”. A terminal or file manager has the mount open. Close anything accessing the path and try again, or use sudo umount -l /mnt/unraid/websites to lazy unmount.
The mount keeps dropping after a server restart. Make sure _netdev is in your fstab options. Without it, the system tries to mount the NFS share before the network is ready and silently fails.
rsync errors persist after adding the flags. Double check the flags are on the rsync line in your deploy script and not somewhere else. Run the rsync command manually first to confirm it works before testing through the script.
Summary#
Two things were wrong. The NFS mount was pointing to /mnt/user/websites when the actual export path was /mnt/cache/websites because the share was configured to use cache-only storage on Unraid. Once that was fixed, rsync’s default metadata syncing caused permission errors on the target directory. Adding --no-group --omit-dir-times --no-perms to the rsync command resolved those. Both fixes together got the deploy running clean.