Skip to main content

Ricing My Home Backup Strategy: Proxmox, WD Red, 2.5GbE, and Windows

·5 mins

Background & Hardware #

My home lab runs on a Lenovo M920q with an NVMe drive for performance, but the weakest point was storage for backups. Until now I was using old 2,5" HDD from laptop in a cheap usb enclosure as a storage for backups, but it was slow and was lacking available space.I wanted to “rice it out” using the hardware I already had on hand. Instead of buying a flashy new NAS, I decided to use a spare, almost-new 4TB WD Red, 2,5gbps network and my windows desktop with RAID1 to create a high-performance 3-2-1 backup system.

Hardware Verification #

I opted for a SATA to USB 3.0 enclosure supporting UASP (USB Attached SCSI Protocol) to ensure I wasn’t bottlenecked by the USB interface. UASP is the “secret sauce” here - it allows for much higher speeds and lower CPU overhead compared to the old Bulk-Only Transport (BOT) protocol.

After plugging it in, I verified the UASP driver was active:

$ lsusb -t | grep Mass
    |__ Port 003: Dev 002, If 0, Class=Mass Storage, Driver=uas, 5000M

I also confirmed the disk was recognized correctly:

$ lsblk -o MODEL,NAME /dev/sda
MODEL                NAME
WDC WD40EFRX-68N32N0 sda
                     └─sda1

Setting Up the Disk: Maximizing Performance #

Mechanical NAS drives like the WD Red (EFRX) have aggressive power-saving features. In a Proxmox environment, constant head parking can cause lag and premature hardware failure.

  1. Disabling Head Parking I used idle3ctl to disable the 8-second head parking timer. This prevents the actuator arm from constantly retracting. Note: This requires a full power cycle (unplug/replug) to apply the firmware change.
$ idle3ctl -d /dev/sda
Idle3 timer disabled
Please power cycle your drive off and on for the new setting to be taken into account. A reboot will not be enough!
  1. Managing Spindown with hdparm To ensure the drive doesn’t “sleep” during my backup windows, I used hdparm.

File: /etc/hdparm.conf"

/dev/sda {
    spindown_time = 0
}
  1. Optimizing the I/O Scheduler For mechanical HDDs, the BFQ (Budget Fair Queuing) scheduler is superior for handling heavy backup streams. I created a udev rule to apply this automatically.

File: /etc/udev/rules.d/60-hdd-scheduler.rules

ACTION=="add|change", KERNEL=="sda", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"

Pulling backups from Proxmox to Windows #

To achieve a true 3-2-1 strategy, I needed a copy off the Proxmox node. I decided to replicate the /mnt/external/dump directory to my Desktop PC’s RAID array.

The Replication Script #

I use rclone on Windows due to ability to connect over ssh and login using my ssh key. It’s also free and open source - check it out on https://rclone.org/. Instead of a static config file, I use environment variables to define the SFTP connection on the fly. This makes the script portable and easy to manage.

sync_proxmox.bat

 1@echo off
 2SETLOCAL EnableDelayedExpansion
 3
 4:: --- Configuration ---
 5SET "REMOTE_HOST=192.168.1.10"
 6SET "REMOTE_USER=root"
 7SET "REMOTE_PATH=/mnt/external/dump"
 8SET "LOCAL_PATH=D:\Backup\proxmox-backup"
 9
10:: Dynamic Rclone SFTP Setup via Env Vars
11SET "RCLONE_CONFIG_PROX_TYPE=sftp"
12SET "RCLONE_CONFIG_PROX_HOST=%REMOTE_HOST%"
13SET "RCLONE_CONFIG_PROX_USER=%REMOTE_USER%"
14SET "RCLONE_CONFIG_PROX_USE_AGENT=true"
15SET "LOG_FILE=%~dp0proxmox-backup.log"
16
17:: Check for SSH Keys in Windows OpenSSH Agent
18ssh-add -L >nul 2>&1
19if %ERRORLEVEL% NEQ 0 (
20    echo [!] Error: SSH Agent has no keys. Run ssh-add first.
21    pause
22    exit /b
23)
24
25echo [!] Syncing: %REMOTE_HOST%:%REMOTE_PATH% -> %LOCAL_PATH%
26
27rclone sync PROX:"%REMOTE_PATH%" "%LOCAL_PATH%" ^
28    --progress ^
29    --transfers 1 ^
30    --buffer-size 1024M ^
31    --multi-thread-streams 1 ^
32    --multi-thread-cutoff 999G ^
33    --sftp-concurrency 16 ^
34    --sftp-chunk-size 128k ^
35    --use-mmap ^
36    --links ^
37    --sftp-disable-hashcheck ^
38    --contimeout 2m ^
39    --timeout 10m ^
40    --stats 9999h ^
41    --log-file="%LOG_FILE%" ^
42    --log-level=INFO
43
44if %ERRORLEVEL% EQU 0 (
45    echo.
46    echo [OK] Backup finished successfully!
47    echo Start: %START_TIME%
48    echo End: %TIME%
49) else (
50    echo.
51    echo [ERROR] Error during rclone (Error: %ERRORLEVEL%)
52)
53
54ENDLOCAL
55pause

Im running this script as a scheduled task running at 2am every day, one hour after my Proxmox backup job. Job has ability to wake up my desktop PC from sleep mode and run the script. If desktop PC is not running, script will be ran as soon as PC is booted.

To automate this, I created a new task in Task scheduler with these specific settings to ensure reliability:

  1. Triggers: Set to Daily at 2:00 AM (one hour after the Proxmox internal backup finishes).
  2. Conditions: Check “Wake the computer to run this task”. This makes sure the script runs even if the desktop is in sleep mode.
  3. Settings: Check “Run task as soon as possible after a scheduled start is missed”. This makes sure that if the PC was powered off during the night, the sync starts immediately when I turn it on in the morning.

Performance #

[!] Syncing: 192.168.1.10:/mnt/external/dump -> D:\Backup\proxmox-backup
Transferred:      142.518 GiB / 142.518 GiB, 100%, 160.461 MiB/s, ETA 0s
Checks:               147 / 147, 100%, Listed 294
Deleted:               42 (files), 0 (dirs), 142.146 GiB (freed)
Transferred:           42 / 42, 100%
Elapsed time:     16m15.1s

[OK] Backup finished successfully!
Start: 14:11:27,89
End: 14:27:44,51
Press any key to continue . . .

The results? Sustained speeds of ~160 MiB/s over network.

As shown in my Grafana metrics, we are effectively saturating the physical sequential limits of the WD Red.

Grafana Metrics