Nextcloud AIO — NFS Data Directory & Emergency Local Access
A guide to moving Nextcloud AIO's data directory to an NFS share, maintaining file ownership integrity, and setting up an emergency local access VM for use during internet outages.
Overview
This setup moves Nextcloud's primary data directory to an NFS share hosted on a local server (e.g. a NAS), with Nextcloud AIO running on a remote server (e.g. a Proxmox VM). This gives you:
- Full Nextcloud functionality over the internet under normal conditions
- Direct local access to your data during internet outages
- A clean, single source of truth for all files
Architecture
┌─────────────────────────────────────────────────┐
│ Local Network (LAN) │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Nextcloud AIO │ │ NAS / Local │ │
│ │ (Proxmox VM) │◄───►│ Server (NFS) │ │
│ │ │ NFS │ │ │
│ └──────────────────┘ └──────────────────┘ │
│ │ ▲ │
│ │ Internet │ NFS (LAN) │
│ ▼ │ │
│ Remote Clients ┌──────────────┐ │
│ (WebDAV / Desktop) │ Emergency VM │ │
│ │ (Proxmox VM) │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────┘
Part 1 — Moving the Nextcloud Data Directory to NFS
Why This Is Better Than External Storage
Mounting the NFS share as Nextcloud's native datadirectory is cleaner than using Nextcloud's External Storage feature:
| Native Data Dir on NFS | External Storage | |
|---|---|---|
| Nextcloud awareness | Transparent | Explicit backend |
| File ownership | Handled natively | Can have edge cases |
| Versioning & Trash | Fully supported | Can be quirky |
| Encryption | Works natively | Can have complications |
| Config complexity | One config.php change |
Requires app setup |
NFS Mount Configuration
Add to /etc/fstab on the Nextcloud server:
nas-server:/share /mnt/nextcloud nfs _netdev,auto 0 0
The _netdev flag tells the OS to wait for the network before mounting — critical for a remote NFS share.
Key Considerations
File locking — Use Redis for Nextcloud file locking rather than the database, as NFS can interfere with lock files:
// config.php
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => [
'host' => 'localhost',
'port' => 6379,
],
UID/GID ownership — Nextcloud's web server runs as www-data (typically UID 33 on Debian/Ubuntu). The NFS share must be accessible to this user. Check the UID with:
id www-data
Configure your NFS server to export with matching UID permissions, and be cautious of NFS UID squashing settings (no_root_squash / UID mapping may be needed).
Part 2 — Emergency Local Access VM
Purpose
A lightweight Linux VM running permanently on Proxmox, pre-configured to access the NFS share directly over the LAN. Used when internet access is unavailable but local file access is needed.
Why a Dedicated VM
- Runs Linux, making UID/GID matching straightforward
- Accessible via SSH from any OS (Windows, Mac, Linux)
- No dependency on internet connectivity
- Keeps file ownership intact when writing to the NFS share
Recommended OS — Alpine Linux
Alpine Linux is the ideal choice for a permanently-running, lightweight emergency VM. It's the same base image used by many Docker containers, and its footprint is minimal:
- Base install is around 130MB of disk space
- RAM usage at idle is typically 50-100MB
- Uses musl libc and busybox instead of heavier GNU equivalents
- Uses OpenRC instead of systemd
- Package manager (
apk) is fast and simple
LXC Container vs Full VM
Since everything is on Proxmox, Alpine works particularly well as an LXC container rather than a full VM, reducing overhead even further:
| LXC Container | Full VM | |
|---|---|---|
| RAM at idle | ~20-30MB | ~100MB+ |
| Disk footprint | Minimal | Larger |
| Boot time | Seconds | 10-30 seconds |
| NFS support | Yes, with minor config | Yes, standard |
| SSH access | Identical | Identical |
| Proxmox snapshots | Very fast | Slightly slower |
Note: Use a privileged LXC container for NFS mounts — unprivileged containers can have issues mounting NFS shares.
Proxmox has Alpine available as a built-in LXC template (Datacenter → Node → local storage → CT Templates).
Proxmox LXC Suggested Specs
- RAM: 512MB (it will rarely use more than 50MB, but this gives headroom)
- Disk: 512MB (the full Alpine install with all required packages sits well under 300MB, leaving ~200MB for logs, updates, and system overhead)
- Privileged container: Yes (required for NFS)
Note: The LXC disk is the system disk only — Nextcloud data lives on the NFS mount and does not consume space here. rsync and mc stream data directly between the NFS mount and remote machines without staging anything on the local disk. If you ever need local staging space, mount a separate volume rather than enlarging the system disk.
Alpine Package Installation
apk update && apk upgrade
apk add nfs-utils # NFS client support
apk add rsync # File transfers
apk add openssh # SSH server
apk add tmux # Terminal multiplexer
apk add mc # Midnight Commander
apk add shadow # Needed for usermod on Alpine
Total footprint including all packages will remain well under 300MB.
Alpine-Specific Configuration
Enable and start NFS services:
rc-update add rpcbind
rc-update add nfsmount
rc-service rpcbind start
rc-service nfsmount start
Enable SSH:
ssh-keygen -A
rc-update add sshd
rc-service sshd start
Note: Alpine uses ash (via busybox) as its default shell rather than bash. The startup scripts in this guide use #!/bin/ash accordingly. If you prefer bash, install it with:
apk add bash
VM Setup Checklist
- Create Alpine LXC container in Proxmox using the built-in template
- Install required packages (see above)
- Set the local user's UID to match
www-dataon the Nextcloud server (UID 33):usermod -u 33 your-username - Configure NFS services (see above)
- Add the NFS mount to
/etc/fstab:nas-server:/share /mnt/nextcloud nfs _netdev,auto 0 0 - Enable and start SSH (see above)
- Take a Proxmox snapshot once configured, so you can roll back if something goes wrong during an emergency file operation.
Part 3 — File Management Tools
Midnight Commander (mc)
A terminal-based two-panel file manager, ideal for navigating and copying files over SSH without a GUI.
sudo apt install mc
mc
Key Bindings
| Key | Action |
|---|---|
Tab |
Switch between panels |
F3 |
View file |
F4 |
Edit file |
F5 |
Copy |
F6 |
Move |
F7 |
New directory |
F8 |
Delete |
F9 |
Menu bar |
Insert |
Select/deselect files |
Ctrl+T |
Select by pattern (e.g. *.jpg) |
Alt+. |
Toggle hidden files |
mc also has a built-in SFTP client (F9 → Left/Right → SFTP link), allowing you to browse a remote machine in one panel and the NFS mount in the other — all within a single SSH session.
tmux — Terminal Multiplexer
tmux provides persistent terminal sessions and split-pane layouts. Rather than using tmux alone to display directory listings (which are static and don't update automatically), the recommended approach is to run mc inside tmux — giving you live-updating two-panel file browsing alongside a persistent shell pane for rsync and other commands.
Key Benefit
If your SSH connection drops during a large file transfer, the tmux session keeps running. Reconnect and reattach with:
ssh user@emergency-vm
tmux attach -t emergency
Key Bindings
| Key | Action |
|---|---|
Ctrl+b % |
Split vertically |
Ctrl+b " |
Split horizontally |
Ctrl+b ←→↑↓ |
Move between panes |
Ctrl+b z |
Zoom current pane (toggle) |
Ctrl+b [ |
Scroll mode |
Ctrl+b d |
Detach (session keeps running) |
Why Not tmux Panes Alone?
A tmux layout using ls or watch ls in each pane was considered but has drawbacks:
lsis a one-shot command — it doesn't update as files changewatch lsupdates automatically but locks the pane, requiringCtrl+Cbefore you can interact with it
mc running in a tmux pane gives live directory updates and full interactivity, making it the better solution.
Combined tmux + mc Layout
┌──────────────────────────────────────┐
│ mc (two-panel, full width) │
│ ~/staging │ /mnt/nextcloud │
│ (live) │ (live) │
│ │ │
├──────────────────────────────────────┤
│ Shell pane — rsync / occ commands │
└──────────────────────────────────────┘
mc accepts two path arguments (left panel and right panel), so it opens directly with your staging area and NFS mount side by side, both updating live.
Emergency Session Startup Script
Save as ~/emergency-session.sh on the VM:
#!/bin/ash
tmux new-session -d -s emergency -x 220 -y 50
# Top pane - mc with staging area on left, NFS mount on right
tmux send-keys -t emergency 'mc /home/user/staging /mnt/nextcloud' Enter
# Bottom pane - shell for rsync and other commands
tmux split-window -v -t emergency
tmux resize-pane -t emergency -y 8
tmux send-keys -t emergency 'echo "Command pane ready"' Enter
tmux attach -t emergency
chmod +x ~/emergency-session.sh
Part 4 — Transferring Files with rsync
Recommended Flags
rsync -avh --progress --stats
| Flag | Purpose |
|---|---|
-a |
Archive mode — preserves permissions, timestamps, symlinks |
-v |
Verbose output |
-h |
Human readable sizes |
--progress |
Per-file progress |
--stats |
Transfer summary |
--partial |
Keeps partial files if connection drops |
--append-verify |
Safely resumes interrupted transfers |
NFS Mount → Mac
Mac has rsync and SSH built in. Enable Remote Login under System Settings → General → Sharing → Remote Login, then:
# Push to Mac
rsync -avh --progress /mnt/nextcloud/username/files/ user@mac-ip:/Users/username/destination/
# Pull from Mac
rsync -avh --progress user@mac-ip:/Users/username/source/ /mnt/nextcloud/username/files/
NFS Mount → Windows
Windows requires one of the following:
Option 1 — WSL2 (Recommended)
WSL2 includes rsync and SSH. Windows drives are accessible at /mnt/c/, /mnt/d/ etc. Start the SSH server in WSL2 first:
# In WSL2
sudo service ssh start
# From Emergency VM
rsync -avh --progress /mnt/nextcloud/username/files/ windowsuser@windows-ip:/mnt/c/Users/username/destination/
Option 2 — OpenSSH + scp OpenSSH Server is built into Windows 10/11 (Settings → Apps → Optional Features → OpenSSH Server):
scp -r /mnt/nextcloud/username/files/ windowsuser@windows-ip:"C:/Users/username/destination/"
Option 3 — DeltaCopy A Windows application that wraps rsync as a Windows service — good for a set-and-forget solution without WSL2.
Part 5 — Resynchronising Nextcloud After an Outage
Any files written directly to the NFS share (bypassing Nextcloud's API) will not be reflected in Nextcloud's database until a file scan is run.
Run a File Scan (Nextcloud AIO)
# Scan all users
sudo docker exec -it --user www-data nextcloud-aio-nextcloud php occ files:scan --all
# Scan a specific user
sudo docker exec -it --user www-data nextcloud-aio-nextcloud php occ files:scan username
# Scan a specific path
sudo docker exec -it --user www-data nextcloud-aio-nextcloud php occ files:scan --path="/username/files"
Verify your container name first:
sudo docker ps --format "table {{.Names}}\t{{.Status}}"
Automate the Scan on Internet Restoration
Save as /usr/local/bin/wait-and-scan.sh on the Nextcloud server:
#!/bin/bash
until ping -c1 8.8.8.8 &>/dev/null; do
sleep 30
done
sudo docker exec --user www-data nextcloud-aio-nextcloud php occ files:scan --all
chmod +x /usr/local/bin/wait-and-scan.sh
Run via cron or a systemd service to trigger automatically when connectivity is restored.
Normal Operation vs Internet Outage — Summary
| Condition | Access Method | Notes |
|---|---|---|
| Internet up | Nextcloud WebDAV / Desktop Client / Mobile App | Full sync, versioning, activity logs |
| Internet up | NFS direct (read-only recommended) | For bulk access; run occ files:scan after writes |
| Internet down | Emergency VM → NFS mount | Full read/write at LAN speed |
| Internet down | NFS mount on Mac (direct) | Works natively; run occ files:scan after |
| Internet down | NFS mount on Windows | Limited; WSL2 or OpenSSH recommended |
| Internet restored | Run occ files:scan |
Reconciles any direct NFS writes with Nextcloud |
Important Reminders
- Always run
occ files:scanafter writing files directly to the NFS share - Keep a Proxmox snapshot of the Emergency VM
- Use Redis for Nextcloud file locking when data is on NFS
- Ensure
www-dataUID matches between the Nextcloud server and any direct NFS clients - The
_netdevfstab option is essential on the Nextcloud server to prevent boot failures if the NFS share is temporarily unavailable