My QNAP TS-469L is now around 13 years old. From a hardware perspective, that sounds ancient, especially when compared with modern NAS systems. Nevertheless, the device is still perfectly usable for what I need: network storage, RAID, SMB shares and backups.
Instead of replacing perfectly functional hardware, I decided to give the TS-469L a second life by replacing QNAP’s operating system with OpenMediaVault (OMV).
The result was surprisingly straightforward — and the performance is better than I expected from hardware of this age.
This article describes how I installed OMV, rebuilt the storage, restored roughly 3.5 TB of data and finally added an automated weekly OneDrive backup using rclone.
The Hardware
My system is a:
QNAP TS-469L
The important difference compared with a standard OMV installation is that I did not want to install the operating system onto one of the internal storage disks.
Instead, I bought a small SSD and connected it externally to one of the QNAP’s USB 2.0 ports.
The basic setup therefore looks like this:
QNAP TS-469L
│
├── External USB SSD
│ └── OpenMediaVault / Debian
│
├── Internal USB Memory
│ └── QTS OS
│
└── Internal HDDs
└── RAID1 mirror
└── 1TB HDD
└── 3 TB HDD
Using USB 2.0 for the operating system obviously isn’t particularly fast by today’s standards, but OMV itself does not generate huge amounts of disk I/O during normal NAS operation.
For my use case, this works perfectly well.
Preparation: Back Up Everything First
Before touching the NAS, I copied approximately 3.5 TB of existing data to external storage.
This was probably the most important preparation step.
I did not want to preserve the existing QNAP disk configuration. My intention was to completely reinitialize the disks after installing OMV and create a clean storage configuration.
That meant I needed to assume that everything on the internal disks would be lost.
My approach was therefore:
QNAP data
│
▼
External backup (~3.5 TB)
│
▼
Install OpenMediaVault
│
▼
Reinitialize internal disks
│
▼
Create new storage / RAID
│
▼
Restore data
I would strongly recommend doing the same.
Even if you intend to reuse an existing filesystem, a full independent backup before replacing the NAS operating system is a very good idea.
Creating the OpenMediaVault Installation USB Stick
For the installation itself, I used the ready-made OpenMediaVault appliance image and wrote it to a USB flash drive.
The QNAP was then booted from this USB stick.
I had another USB device connected at the same time: the SSD that would become the permanent OMV system disk.
So during installation there were essentially three categories of storage:
Installation USB stick
│
├── OMV installer
│
▼
QNAP TS-469L
│
├── USB SSD → target for OMV
│
└── Internal HDDs → later used for data
One thing is worth mentioning here.
Before doing the installation, I had expected that identifying or selecting the correct installation disk might be problematic.
That turned out not to be the case.
The OpenMediaVault/Debian installer allowed me to select the correct target disk during installation.
I simply selected the external SSD and installed OMV onto it.
So, at least with my TS-469L and this installation method, there was no need to physically remove all of the internal hard drives just to force the installer onto the correct disk.
Obviously, you should still check the disk size and device carefully before confirming the installation. Selecting the wrong disk at this stage can destroy the data on it.
First Boot
After installation, I removed the installation USB stick and booted the QNAP from the USB SSD.
OpenMediaVault started normally.
From that point onwards, the TS-469L essentially behaved like a normal x86 Linux server.
The external SSD contains the operating system while the internal drive bays are completely available for storage.
Reinitializing the Hard Drives
Because I had already backed up my approximately 3.5 TB of data, I did not need to worry about preserving the previous QNAP storage configuration.
I therefore reinitialized the disks in OpenMediaVault and created the storage layout from scratch.
Part of my storage is configured as a mirrored array.
For this I installed:
openmediavault-md 8.1.5-1
This adds the Linux MD software RAID functionality to OMV and allowed me to create my RAID1 mirror.
Conceptually:
HDD 1 ─────┐
├── RAID1 ──► Mirror
HDD 2 ─────┘
With RAID1, the same data is stored on both disks. If one disk fails, the data remains available on the other.
It is important to remember, however:
RAID is not a backup.
RAID protects against a disk failure. It does not protect against accidental deletion, malware, corrupted files or a file being overwritten.
This is one of the reasons why I additionally use rclone backups, which I describe later.
Restoring the Data
Once the filesystems, RAID and shared folders were configured, I copied the approximately 3.5 TB of data back to the NAS.
There was nothing particularly exciting about this step — it simply took some time.
After the restore had completed and I had verified the data, the migration itself was basically finished.
The process was therefore surprisingly simple:
1. Back up all data externally
2. Create OMV installation USB stick
3. Connect SSD to the QNAP
4. Boot from installation USB
5. Install OMV onto the SSD
6. Boot OMV
7. Reinitialize internal disks
8. Configure RAID / filesystems / shares
9. Restore the data
10. Done
Useful OpenMediaVault Plugins
There are two OMV plugins that I currently find particularly useful.
openmediavault-md 8.1.5-1
As mentioned above, I use this for my mirrored disks.
It provides the integration for Linux MD software RAID and allows the RAID configuration to be managed through OpenMediaVault.
For my setup, this is one of the essential plugins.
openmediavault-filebrowser 8.0.6-1
I also installed:
openmediavault-filebrowser 8.0.6-1
The idea is useful because it provides a graphical file browser directly through the web interface.
However, I personally find the functionality rather limited.
It is useful for quickly checking directories or doing some simple file operations, but I would not consider it a replacement for a proper file manager.
Still, having a browser-based file interface available on a headless NAS can occasionally be convenient.
Performance: Surprisingly Good for 13-Year-Old Hardware
The TS-469L is around 13 years old, so I did not expect miracles.
Nevertheless, I am quite satisfied with its performance.
Of course, this machine cannot compete with a modern NAS in terms of CPU performance, memory bandwidth or modern interfaces.
But that isn’t what I need it to do.
For:
- file storage
- SMB shares
- RAID1
- backups
- rclone
- general home NAS duties
it is still perfectly adequate.
And that was ultimately the point of this project.
Instead of throwing away functioning hardware simply because the original software platform is getting old, OpenMediaVault allows the machine to continue operating as a modern Linux-based NAS.
Adding Weekly OneDrive Backups with rclone
After the basic NAS migration was finished, I wanted another layer of protection.
Several OneDrive accounts contain data that I want to keep locally on the NAS.
For this I use rclone.
The basic idea is:
OneDrive
│
│ rclone sync
▼
Local NAS copy
However, I wanted something slightly more sophisticated than simply running:
rclone sync remote: /some/local/folder
A normal sync has an important characteristic:
If a file disappears from OneDrive, rclone will eventually remove it from the destination as well.
That is exactly what a synchronization tool is supposed to do, but it isn’t necessarily what I want from a backup.
So I created a script around rclone that combines synchronization with a temporary archive.
I used ChatGPT extensively to help develop, review and refine this script. What started as a relatively simple rclone command eventually became a much more comprehensive backup script with safety checks, locking, logging, statistics, archive retention and separate handling for certain directories.
The following is a simplified and anonymized version of my setup.
Directory Structure
My real paths contain disk UUIDs and personal directory names, so I have replaced them here with generic examples.
Assume the NAS contains:
/storage/raid1/
Backup-OneDrive/
/storage/data/
OneDrive/
Archive/
/var/log/rclone-backup/
/etc/rclone/rclone.conf
In my setup, photographs are stored on the mirrored storage while other OneDrive data can be stored on another data disk.
For example:
RAID1
└── Backup-OneDrive
└── Pictures
├── User-A
├── User-B
└── Photos
Data Disk
├── OneDrive
│ ├── User-A
│ ├── User-B
│ ├── User-C
│ └── User-D
│
└── Archive
rclone Configuration
My rclone configuration is stored centrally at:
/etc/rclone/rclone.conf
The real file contains the authentication information for the OneDrive remotes.
For example, after configuring rclone, you might have remotes such as:
OneDrive-UserA:
OneDrive-UserB:
OneDrive-UserC:
OneDrive-Photos:
These names are arbitrary. They are simply the names assigned while running:
rclone config
The configuration file should obviously be protected appropriately because it contains credentials/tokens that allow rclone to access the cloud accounts.
The Backup Script
At the beginning of the script I define the important locations:
#!/bin/bash
set -u
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
umask 0002
CONFIG="/etc/rclone/rclone.conf"
RAID="/storage/raid1"
DATA="/storage/data"
ARCHIVE="$DATA/Archive"
LOGDIR="/var/log/rclone-backup"
LOCKFILE="/root/.onedrive-backup.lock"
DATE="$(date +%F_%H-%M-%S)"
START_TIME="$(date '+%d.%m.%Y %H:%M:%S')"
Let’s look at what these settings do.
set -u
set -u
This makes Bash stop when the script attempts to use an undefined variable.
That helps detect typos or programming mistakes instead of silently continuing with an empty value.
PATH
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Scheduled jobs do not necessarily receive the same environment as an interactive SSH session.
Defining PATH explicitly makes sure commands such as rclone, find, mkdir and flock can be located when the script runs automatically.
umask
umask 0002
This makes newly created files/directories group-writable, which fits my OMV permission model.
Preventing Two Backups from Running Simultaneously
One of the safety features I added is a lock.
exec 9>"$LOCKFILE"
if ! flock -n 9; then
echo "ERROR: Another OneDrive backup is already running."
exit 1
fi
This is important.
Imagine that the weekly backup is still running for some reason and another execution starts.
You could then have two instances of rclone modifying the same destination and archive directories simultaneously.
flock prevents that.
The first script obtains the lock.
If another instance starts, it detects the existing lock and immediately exits.
Preparing Directories
The script contains a small helper function:
prepare_dir() {
DIR="$1"
mkdir -p "$DIR"
chgrp users "$DIR" 2>/dev/null || true
chmod g+rws "$DIR" 2>/dev/null || true
}
This does three things.
First:
mkdir -p
creates the directory if it does not already exist.
Second:
chgrp users
assigns the directory to the users group.
Finally:
chmod g+rws
makes the directory group-writable and sets the SGID bit.
The SGID bit is useful for shared storage because new files and directories inherit the parent directory’s group.
A Safety Whitelist for Backup Targets
This is one of the parts of the script that I particularly like.
Before rclone is allowed to synchronize anything, the destination is checked against a list of explicitly permitted paths.
A simplified version looks like this:
check_safe_target() {
TARGET="$1"
case "$TARGET" in
"$RAID/Backup-OneDrive/Pictures/User-A"|\
"$RAID/Backup-OneDrive/Pictures/User-B"|\
"$DATA/OneDrive/User-A"|\
"$DATA/OneDrive/User-B"|\
"$DATA/OneDrive/User-C")
return 0
;;
*)
echo "SAFETY ABORT: Unsafe destination:"
echo "$TARGET"
exit 1
;;
esac
}
Why bother doing this?
Because rclone sync is destructive by design.
The destination is changed to match the source.
A typo such as accidentally specifying:
/storage
instead of:
/storage/data/OneDrive/User-A
could therefore have very unpleasant consequences.
The whitelist means the script only accepts destinations that I have explicitly defined.
Anything else causes an immediate abort.
The Actual rclone Command
The central part of the script eventually executes something equivalent to:
rclone sync \
"$SOURCE" \
"$TARGET" \
--config "$CONFIG" \
--backup-dir "$BACKUP" \
--create-empty-src-dirs \
--delete-after \
--max-delete 1000 \
--transfers 2 \
--checkers 4 \
--log-level INFO
This deserves a closer look.
rclone sync
Unlike copy, sync tries to make the destination match the source.
If OneDrive contains:
A
B
C
and the NAS contains:
A
B
C
D
then a normal sync would remove D from the NAS.
That is why the next option is so important.
--backup-dir
Every run gets its own timestamp:
DATE="$(date +%F_%H-%M-%S)"
For example:
2026-09-06_03-00-00
The archive can therefore look like:
Archive
└── OneDrive
└── User-A
├── 2026-09-06_03-00-00
├── 2026-09-13_03-00-00
└── 2026-09-20_03-00-00
The rclone option:
--backup-dir "$BACKUP"
means that files which would otherwise be overwritten or deleted at the destination are moved into the backup directory.
This changes the character of the synchronization significantly.
Instead of:
Cloud deletion
│
▼
Local file deleted
I effectively get:
Cloud deletion
│
▼
Removed from current mirror
│
▼
Moved into timestamped archive
This gives me an additional recovery window.
--delete-after
--delete-after
tells rclone to process deletions after transfers have completed.
I prefer this behaviour because the new/changed files are transferred before obsolete destination files are dealt with.
--max-delete 1000
Another safety mechanism is:
--max-delete 1000
This limits the number of deletions rclone is allowed to perform during one run.
The reason is simple.
Suppose something goes seriously wrong with a OneDrive remote or I accidentally point the script at an empty source.
Without protection, a synchronization could interpret this as:
The cloud is empty, therefore the local mirror must also become empty.
A deletion limit provides an additional barrier against a catastrophic mass deletion.
It isn’t a replacement for backups, but it is a useful safety mechanism.
--transfers 2 and --checkers 4
I deliberately keep the concurrency relatively conservative:
--transfers 2
--checkers 4
Only two file transfers are performed simultaneously, while four checker operations can run concurrently.
Remember: this is a 13-year-old NAS.
There is little point in aggressively increasing concurrency if the CPU, disks or network connection cannot benefit from it.
For my hardware, this conservative configuration works well.
Separating Pictures from the Main OneDrive Backup
For some accounts, I do not want the picture directories stored on the same disk as the rest of the OneDrive data.
Therefore, the main sync excludes them:
--exclude "/Pictures/**" \
--exclude "/Pictures/"
The picture directory is then synchronized separately to the RAID1 storage:
OneDrive User
│
├── Documents ─────────────► Data Disk
├── Other files ───────────► Data Disk
│
└── Pictures ──────────────► RAID1
This lets me decide which type of data should live on which physical storage.
Checking Whether Optional Cloud Folders Exist
Some accounts may contain particular picture directories while others may not.
Instead of treating a missing directory as an error, the script first checks whether it exists:
rclone lsf "$REMOTE" \
--config "$CONFIG" \
--dirs-only \
--max-depth 1
If the folder exists, the synchronization is performed.
If it doesn’t, the script simply records something similar to:
Cloud folder not present - skipped
This makes the same script usable even if the directory structure differs slightly between accounts.
Logging
Every backup job has a persistent log file:
/var/log/rclone-backup/
For example:
user-a-onedrive.log
user-a-pictures.log
user-b-onedrive.log
photos.log
In addition, each execution creates temporary working files.
The script counts operations such as:
Copied
Deleted
Moved/Renamed
Errors
and generates a summary.
A typical result might look conceptually like:
User A OneDrive: 23 copied | 2 deleted | 1 moved | 0 errors | OK
User A Pictures: 142 copied | 0 deleted | 0 moved | 0 errors | OK
User B OneDrive: 4 copied | 1 deleted | 0 moved | 0 errors | OK
Photos: 18 copied | 0 deleted | 0 moved | 0 errors | OK
This makes it much easier to see what actually happened during a backup without manually reading thousands of rclone log lines.
Automatic Cleanup After 90 Days
Keeping every historical version forever would eventually fill the disk.
Therefore, my script retains the timestamped archive directories for approximately 90 days.
The principle is:
find "$ARCHIVE/..." \
-type d \
-mtime +90 \
-exec rm -rf -- {} +
Afterwards, empty archive directories are removed as well.
Conceptually:
Current local mirror
│
├── current files
│
└── deleted/changed files
│
▼
Archive
│
kept 90 days
│
▼
automatically
removed
This is a compromise between having version history and not allowing the archive to grow indefinitely.
Temporary Working Directory
For each execution, the script creates a temporary directory:
WORKDIR="$(mktemp -d /tmp/onedrive-backup.XXXXXX)"
The temporary summary and detailed report are generated there.
A trap makes sure it is removed when the script exits:
trap 'rm -rf "$WORKDIR"' EXIT
So temporary reporting files do not accumulate over time.
Exit Codes and Monitoring
At the end, the script checks whether any backup job failed.
Conceptually:
if [ "$FAILURES" -eq 0 ]; then
exit 0
else
exit 1
fi
This is particularly useful when the script is executed as an OpenMediaVault scheduled job.
0 means everything completed successfully.
1 means at least one backup failed.
The script also writes its summary and detailed rclone output to standard output, allowing OMV’s scheduled-job reporting to capture the complete backup report.
Scheduling the Backup in OpenMediaVault
I run the complete synchronization once a week.
This can conveniently be configured through OpenMediaVault’s scheduled jobs.
The important part is that the scheduled job executes the script rather than containing all the rclone commands itself.
For example:
/path/to/onedrive-backup.sh
This has several advantages.
The OMV scheduler only needs to know when the backup should run.
All of the actual logic remains inside the script:
OMV Scheduled Job
│
▼
Backup Script
│
├── Lock
├── Check destinations
├── Check cloud folders
├── Run rclone jobs
├── Archive changes
├── Write logs
├── Generate statistics
├── Clean archive
└── Return status
That makes the setup much easier to maintain.
Is This a Real Backup?
There is an important distinction here.
rclone sync itself is primarily a synchronization mechanism, not a traditional versioned backup system.
However, combining it with:
--backup-dir
and timestamped archive directories means deleted or replaced destination files are retained for a period of time.
In my case, that period is 90 days.
So my setup provides:
OneDrive
│
│ synchronization
▼
Current local copy
│
│ changed/deleted files
▼
90-day archive
For my use case, this provides a useful additional local recovery layer.
Still, particularly important data should always exist independently in multiple locations.
Final Result
After completing the migration, my old QNAP now runs a current OpenMediaVault installation instead of relying on its original NAS operating system.
The final setup provides:
┌───────────────┐
│ OneDrive │
└───────┬───────┘
│
rclone
│
┌─────────────┴─────────────┐
▼ ▼
Normal Data Pictures
│ │
▼ ▼
Data Disk RAID1
│
└────────────┬──────────────┘
│
changed/deleted files
│
▼
90-Day Archive
For hardware that is around 13 years old, I am genuinely satisfied with the result.
The installation itself was much easier than I originally expected. The installer allowed me to select my external SSD as the operating-system disk, the internal drives could then be completely reinitialized, and after restoring the roughly 3.5 TB of data the NAS was ready to use again.
The additional rclone automation gives me something I did not simply want to leave to manual processes: regular local copies of my cloud data, a recovery period for deleted files, logs, safety checks and clear reporting.
I also found it interesting how the backup script evolved. I used ChatGPT to help create and iteratively improve it, especially when adding the safety mechanisms, logging, archive handling and reporting.
Would I replace a modern high-performance NAS with a TS-469L today?
Probably not.
But if you already own one?
There is surprisingly little reason to throw away perfectly functional x86 hardware just because it is old.
For file storage, RAID, SMB and automated backups, my TS-469L still does exactly what I need it to do.
And OpenMediaVault gave it a second life.


Leave a Reply