In this guide you’ll set up a local mirror of your Microsoft OneDrive — for one or more accounts — on a Proxmox host using a dedicated Debian 13 LXC container and a ZFS Mirror Pool for redundant storage. The result is a resilient, automatically synced local copy of your cloud files — no GUI, no fuss. 🎯
The key idea behind this OneDrive Proxmox LXC ZFS Mirror setup: the ZFS pool lives on the host, the container only handles syncing. Your data survives container rebuilds and benefits from ZFS redundancy at the same time.
🏗️ Architecture Overview
The OneDrive Proxmox LXC ZFS Mirror stack has three layers. Each OneDrive account gets its own subdirectory in the dataset and its own systemd service inside the container:
⚠️ Do NOT run apt install onedrive without first adding the OBS repository — the version in default Debian repos is outdated and unsupported. Details in Step 4.
🪨 Step 1: Create a ZFS Mirror Pool on the Proxmox Host
All host-level commands run in the Proxmox shell (web UI → node → Shell, or SSH into PVE). This is the foundation of the entire OneDrive Proxmox LXC ZFS Mirror setup — get the pool right first, everything else builds on top of it.
Identify your disks 🔍
Always use stable /dev/disk/by-id/ paths. Raw kernel names like /dev/sda are assigned at boot and can change after a reboot or when adding/removing disks — never rely on them for pool creation.
ls -la /dev/disk/by-id/ | grep -v part
You’ll see output like:
ata-WDC_WD40EFRX_XXXXXXXXXXXX -> ../../sdb ata-WDC_WD40EFRX_YYYYYYYYYYYY -> ../../sdc
The long ata-... identifier is stable across reboots. That’s what you use — not sdb/sdc on the right side.
Create the mirror pool
zpool create -f -o ashift=12 \ -O compression=lz4 \ -O atime=off \ -O xattr=sa \ -O dnodesize=auto \ cloud mirror \ /dev/disk/by-id/ata-WDC_WD40EFRX_XXXXXXXXXXXX \ /dev/disk/by-id/ata-WDC_WD40EFRX_YYYYYYYYYYYY
Key options: ashift=12 is correct for 4K-sector drives. compression=lz4 saves space at near-zero CPU cost. atime=off eliminates write amplification from access-time tracking.
Verify the pool
zpool status cloud zpool list cloud
Expected output shows state: ONLINE and mirror topology. ✅
Create a dedicated dataset for OneDrive
zfs create cloud/onedrive zfs list cloud/onedrive
This automatically creates the mountpoint /cloud/onedrive on the host. A dedicated dataset gives you per-dataset snapshots, quotas, and ZFS properties for your OneDrive data independently of the rest of the pool. 📦
💡 Optional quota: To cap how much space OneDrive data can consume: zfs set quota=500G cloud/onedrive
📦 Step 2: Create the Debian 13 LXC Container
Debian 13 “Trixie” was released on August 9, 2025 and is the current stable release (latest point release: 13.4, March 2026). In this OneDrive Proxmox LXC ZFS Mirror setup we use a privileged container — the simplest path for bind-mounting a host ZFS dataset without complex UID remapping. 🐧
# Download the Debian 13 template (skip if already present) pveam update pveam download local debian-13-standard_13.1-2_amd64.tar.zst # Create the container pct create 200 local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst \ --hostname onedrive-sync \ --memory 512 \ --cores 1 \ --rootfs local-lvm:8 \ --net0 name=eth0,bridge=vmbr0,ip=dhcp \ --unprivileged 0 \ --start 1 \ --password YourRootPasswordHere
⚠️ Privileged container note: Privileged LXC containers share the host UID namespace. Fine for a trusted homelab, but be aware of the security tradeoff. For an unprivileged setup, UID/GID remapping is required — see the Proxmox unprivileged LXC docs.
Update the container
# Run inside the LXC (pct enter 200, or Shell in web UI) apt-get update && apt-get upgrade -y apt-get install -y curl wget gnupg2
🔗 Step 3: Bind-Mount the ZFS Dataset into the LXC
The bind mount is configured on the Proxmox host, not inside the container. This is the standard Proxmox way to share host directories with LXC containers — and the core link of the OneDrive Proxmox LXC ZFS Mirror architecture. Without this bind mount the OneDrive Proxmox LXC ZFS Mirror cannot write synced files to the ZFS pool. 🔗
# Run on the Proxmox host pct stop 200 pct set 200 -mp0 /cloud/onedrive,mp=/mnt/onedrive pct start 200
Verify inside the container that the directory is visible and writable:
# Run inside the LXC ls /mnt/onedrive touch /mnt/onedrive/.test && echo "Write OK" && rm /mnt/onedrive/.test
✅ If “Write OK” appears, the bind mount is working. Files written to /mnt/onedrive inside the container land directly on the ZFS Mirror Pool on the host.
⬇️ Step 4: Install the OneDrive Client (abraunegg) in the LXC
All commands below run inside the LXC container. We use the abraunegg/onedrive client — fully featured, actively maintained, with WebSocket support for near real-time sync. This is the only OneDrive client worth using in an OneDrive Proxmox LXC ZFS Mirror context. 🚀 For other self-hosted sync options, see our self-hosted cloud comparison.
⚠️ apt install onedrive without the OBS repo installs a severely outdated version. Debian 12 and earlier are also explicitly marked as EOL by the project — use Debian 13 and the OBS repo below.
Add the OBS repository and install (Debian 13 / Trixie)
# Step 1 – Add the signing key wget -qO - https://download.opensuse.org/repositories/home:/npreining:/debian-ubuntu-onedrive/Debian_13/Release.key \ | gpg --dearmor \ | tee /usr/share/keyrings/obs-onedrive.gpg > /dev/null # Step 2 – Add the repository echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/obs-onedrive.gpg] \ https://download.opensuse.org/repositories/home:/npreining:/debian-ubuntu-onedrive/Debian_13/ ./" \ | tee /etc/apt/sources.list.d/onedrive.list # Step 3 – Install apt-get update apt-get install --no-install-recommends --no-install-suggests -y onedrive
Verify the version — you should see v2.5.x or newer:
onedrive --version
👥 Step 5: Multi-Account Setup
The OneDrive Proxmox LXC ZFS Mirror supports multiple accounts in a single container. Each account gets its own config directory, its own sync destination, and its own systemd service. This makes the OneDrive Proxmox LXC ZFS Mirror ideal for households or small teams where multiple Microsoft accounts need local redundant storage. 🔀
The pattern is: for each account, replace ACCOUNT with a short name of your choice (e.g. work, personal, alice, bob).
Create directories for each account
# Run inside the LXC # Replace "work" and "personal" with your actual account names mkdir -p /root/.config/onedrive-work mkdir -p /root/.config/onedrive-personal mkdir -p /mnt/onedrive/work mkdir -p /mnt/onedrive/personal mkdir -p /var/log/onedrive
Authenticate each account 🔐
The client uses OAuth2 with a file-based flow — suitable for headless servers with no browser. The flag --auth-files authUrl:responseUrl means: write the login URL to a file called authUrl, then wait until a file called responseUrl appears. You need two terminal sessions simultaneously: one running the client, one to read/write the files.
Terminal 1 — start the auth process:
onedrive --confdir /root/.config/onedrive-work --auth-files authUrl:responseUrl
The client prints Waiting for --auth-files elements to be available and blocks. Leave it running.
Terminal 2 — open a second SSH session to the same LXC, then:
# Read the login URL the client generated cat authUrl
Copy the full URL → open it in any browser on any machine → log in to your Microsoft account → after login, the browser redirects to a blank or localhost page → copy the full URL from the address bar (it starts with https://login.microsoftonline.com/... and contains a long code= parameter).
Then write that URL to the response file — use single quotes, not double quotes, because the URL contains ! and * characters that bash would otherwise try to interpret:
echo 'https://login.microsoftonline.com/...' > responseUrl
⚠️ Always use single quotes around the URL. Double quotes ("...") cause bash to interpret ! as history expansion and * as a glob — you’ll get a event not found error. Single quotes pass the string exactly as-is.
Terminal 1 will immediately detect the file, complete the authentication, save the token, and exit. ✅
💡 The authUrl and responseUrl files are created in the current working directory where you ran the command — typically /root/. Make sure both terminals are in the same directory, or use full paths: --auth-files /root/authUrl:/root/responseUrl
Repeat for each account:
# Account 2: personal (run in Terminal 1, repeat the two-terminal flow above) onedrive --confdir /root/.config/onedrive-personal --auth-files authUrl:responseUrl
Create config for each account
# Config for the "work" account
cat > /root/.config/onedrive-work/config << 'EOF'
sync_dir = "/mnt/onedrive/work"
download_only = "true"
cleanup_local_files = "true"
log_dir = "/var/log/onedrive/"
skip_file = "~*|.~*|*.tmp"
monitor_interval = "300"
EOF
# Config for the "personal" account
cat > /root/.config/onedrive-personal/config << 'EOF'
sync_dir = "/mnt/onedrive/personal"
download_only = "true"
cleanup_local_files = "true"
log_dir = "/var/log/onedrive/"
skip_file = "~*|.~*|*.tmp"
monitor_interval = "300"
EOF
💡 download_only = "true" means files are only pulled from OneDrive — nothing is uploaded or deleted from the cloud. Remove this line if you want bidirectional sync for a given account.
Initial sync — run in background with tmux 🖥️
The first sync can take hours (or days) if you have hundreds of gigabytes in OneDrive. Never run it in a plain terminal — closing the SSH session will kill the process mid-sync. Use tmux so the sync continues independently of your connection.
# Install tmux if not present apt-get install -y tmux
Then start a named tmux session and run the sync inside it:
# Start session for account 1 tmux new -s onedrive-work onedrive --confdir /root/.config/onedrive-work --sync # Detach without stopping the sync: # Press Ctrl+B, then D
If you have multiple accounts, create a separate session for each:
# After detaching from the first session, start a second one tmux new -s onedrive-personal onedrive --confdir /root/.config/onedrive-personal --sync # Detach: Ctrl+B, then D
To check progress at any time, reattach:
# List active sessions tmux ls # Reattach to a session tmux attach -t onedrive-work
💡 Once the initial sync completes, you don’t need tmux anymore — Step 6 sets up a systemd service that handles everything automatically on every boot.
⚠️ Note: --synchronize is deprecated in newer versions of the client. Use --sync or -s instead to avoid deprecation warnings.
🔄 Step 6: Systemd Services — One per Account
Create a separate systemd service for each account so the OneDrive Proxmox LXC ZFS Mirror sync runs automatically on container start. Running the OneDrive Proxmox LXC ZFS Mirror in monitor mode means changes are picked up in near real-time without manual intervention. The naming pattern onedrive-ACCOUNT.service makes it easy to manage, enable, and troubleshoot individual accounts independently. 🔄
# Service for the "work" account
cat > /etc/systemd/system/onedrive-work.service << 'EOF'
[Unit]
Description=OneDrive Client - work account
Documentation=https://github.com/abraunegg/onedrive
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/bin/onedrive --monitor --confdir /root/.config/onedrive-work
User=root
Restart=on-failure
RestartSec=10
RestartPreventExitStatus=126
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
# Service for the "personal" account
cat > /etc/systemd/system/onedrive-personal.service << 'EOF'
[Unit]
Description=OneDrive Client - personal account
Documentation=https://github.com/abraunegg/onedrive
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/bin/onedrive --monitor --confdir /root/.config/onedrive-personal
User=root
Restart=on-failure
RestartSec=10
RestartPreventExitStatus=126
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
# Enable and start both
systemctl daemon-reload
systemctl enable onedrive-work.service onedrive-personal.service
systemctl start onedrive-work.service onedrive-personal.service
Adding more accounts later
To add a third account (e.g. shared), just repeat the pattern: create a config dir, authenticate, write a config file, and create a service file named onedrive-shared.service. No changes to existing services needed.
Check status per account
systemctl status onedrive-work.service systemctl status onedrive-personal.service # Follow live logs for a specific account journalctl -u onedrive-work.service -f
📸 Step 7: Optional — ZFS Snapshots for Recovery
Because all synced data lives on the ZFS Mirror Pool, you can snapshot the dataset on the Proxmox host at any time — completely independent of the LXC container. This is one of the biggest advantages of the OneDrive Proxmox LXC ZFS Mirror approach over simply mounting a cloud drive directly. If files are accidentally deleted in OneDrive, you can restore from a local snapshot. 🛡️
# Manual snapshot (run on the Proxmox host) zfs snapshot cloud/onedrive@2026-04-06 # List snapshots zfs list -t snapshot cloud/onedrive # Automated daily snapshots via cron (on the PVE host) echo "0 3 * * * root zfs snapshot cloud/onedrive@\$(date +%F)" \ > /etc/cron.d/zfs-onedrive-snap
To roll back:
zfs rollback cloud/onedrive@2026-04-06
📋 Quick Reference
| Component | Location | Detail |
|---|---|---|
| ZFS Mirror Pool | Proxmox Host | cloud — /dev/disk/by-id/... paths |
| ZFS Dataset | Proxmox Host | /cloud/onedrive |
| LXC Container | Proxmox | Debian 13 (Trixie), privileged, CT ID 200 |
| Bind Mount | LXC Config | /cloud/onedrive → /mnt/onedrive |
| OneDrive Client | Inside LXC | abraunegg/onedrive via OBS Debian_13 repo |
| Per-account config | Inside LXC | /root/.config/onedrive-ACCOUNT/config |
| Per-account sync dir | Inside LXC | /mnt/onedrive/ACCOUNT/ |
| Per-account service | Inside LXC | onedrive-ACCOUNT.service |
| Snapshots | Proxmox Host | zfs snapshot cloud/onedrive@DATE |
🔧 Troubleshooting
Authentication fails or token expires
Delete the token for that account and re-authenticate: rm -rf /root/.config/onedrive-work/*.json && onedrive --confdir /root/.config/onedrive-work --auth-files authUrl:responseUrl
Bind mount is empty inside LXC
Check the dataset is mounted on the host: zfs list cloud/onedrive and df -h /cloud/onedrive. If not mounted: zfs mount cloud/onedrive on the host, then restart the container.
Wrong disk identifiers used during pool creation
If you accidentally created the pool using /dev/sdX names, destroy and recreate using /dev/disk/by-id/ paths. The pool will still import fine after reboot, but letter-based paths are not guaranteed to be stable. Verify with: zpool status -v cloud — if it shows /dev/disk/by-id/ paths in the VDEV list, you’re good.
Service for one account fails — another is unaffected
Each service is independent. Check the failing one specifically: journalctl -u onedrive-ACCOUNT.service --since "1 hour ago". Common cause: expired OAuth token — re-authenticate for that account only.
Old onedrive version already installed
Remove it first: apt remove onedrive && apt autoremove, then follow Step 4.
📚 Official Documentation
- abraunegg/onedrive — GitHub
- abraunegg/onedrive — Debian/Ubuntu Package Install Guide
- abraunegg/onedrive — Usage Documentation
- Proxmox VE — Linux Container Wiki
- Proxmox VE — ZFS on Linux Wiki
- OpenZFS — zpool-create man page
- Proxmox VE — Unprivileged LXC Containers
- Debian 13 “Trixie” — Release Information
