OneDrive Proxmox LXC ZFS Mirror: Complete 7-Step Setup Guide

onedrive-proxmox-lxc-zfs-mirror-sync-setup.md
title OneDrive Proxmox LXC ZFS Mirror: Complete 7-Step Setup Guide
date
author VahaC
read 13 min read
category Self-Hosting
tags #Homelab #Linux #Onedrive #Proxmox
OneDrive Proxmox LXC ZFS Mirror: Complete 7-Step Setup Guide

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:

Proxmox host (PVE) ZFS Mirror Pool — “cloud” disk/by-id/ata-DISK_A stable identifier · never /dev/sdX mirror disk/by-id/ata-DISK_B stable identifier · never /dev/sdX cloud/onedrive /onedrive/work/ /onedrive/personal/ bind-mount LXC Container — Debian 13 (Trixie) · CT ID 200 /mnt/onedrive onedrive-work.service monitor mode → /mnt/onedrive/work/ onedrive-personal.service monitor mode → /mnt/onedrive/personal/ ~/.config/onedrive-work ~/.config/onedrive-personal OneDrive (work) OneDrive (personal) HTTPS HTTPS

⚠️ 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. workpersonalalicebob).

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

ComponentLocationDetail
ZFS Mirror PoolProxmox Hostcloud — /dev/disk/by-id/... paths
ZFS DatasetProxmox Host/cloud/onedrive
LXC ContainerProxmoxDebian 13 (Trixie), privileged, CT ID 200
Bind MountLXC Config/cloud/onedrive → /mnt/onedrive
OneDrive ClientInside LXCabraunegg/onedrive via OBS Debian_13 repo
Per-account configInside LXC/root/.config/onedrive-ACCOUNT/config
Per-account sync dirInside LXC/mnt/onedrive/ACCOUNT/
Per-account serviceInside LXConedrive-ACCOUNT.service
SnapshotsProxmox Hostzfs 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

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.