<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: iatxako</title>
    <description>The latest articles on DEV Community by iatxako (@iatxako).</description>
    <link>https://dev.to/iatxako</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3963388%2F739d3c45-d9f6-4f31-9b29-114c2351b0ce.png</url>
      <title>DEV Community: iatxako</title>
      <link>https://dev.to/iatxako</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iatxako"/>
    <language>en</language>
    <item>
      <title>Your NAS Is Loud Because of Docker and Syncthing (and How to Fix It)</title>
      <dc:creator>iatxako</dc:creator>
      <pubDate>Mon, 01 Jun 2026 21:19:53 +0000</pubDate>
      <link>https://dev.to/iatxako/your-nas-is-loud-because-of-docker-and-syncthing-and-how-to-fix-it-pg8</link>
      <guid>https://dev.to/iatxako/your-nas-is-loud-because-of-docker-and-syncthing-and-how-to-fix-it-pg8</guid>
      <description>&lt;p&gt;You buy a NAS for silent, always-on storage. It sits in a corner, humming quietly, doing its thing. Then you install Docker. Then Syncthing. Then a few containers.&lt;/p&gt;

&lt;p&gt;Suddenly the HDDs never stop. Seeking, spinning, clicking. Not occasionally - constantly. At 2am you can hear it from the next room.&lt;/p&gt;

&lt;p&gt;This is what happened, why it happens, and how to make it stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Actually Causing the Noise
&lt;/h2&gt;

&lt;p&gt;Mechanical HDDs make noise when the read/write head moves. The more random the I/O - small reads and writes scattered across the disk - the more seeking, the more noise. Sequential writes to a single file are quiet. Random I/O across thousands of small files is loud.&lt;/p&gt;

&lt;p&gt;Docker and Syncthing are both pathological for HDDs in different ways.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker overlay2
&lt;/h3&gt;

&lt;p&gt;Docker's default storage driver is overlay2. Every container runs on top of layered filesystems - the image layers are stacked, and a thin writable layer sits on top for each running container.&lt;/p&gt;

&lt;p&gt;Every file operation inside a container that touches a file from a lower layer triggers a &lt;strong&gt;copy-on-write&lt;/strong&gt;: the entire file gets copied up to the writable layer before the write happens. On an SSD this is fast and silent. On spinning HDDs with mechanical heads, every copy-on-write is a seek, a read, and a write - often scattered across the disk.&lt;/p&gt;

&lt;p&gt;And it's not just copy-on-write. Docker's overlay2 metadata lives in small files across a deep directory tree. Container startup reads dozens of these. Log rotation writes to them. Health checks touch them. Any container doing anything at all generates constant scattered I/O.&lt;/p&gt;

&lt;h3&gt;
  
  
  Syncthing's 60-Second Heartbeat
&lt;/h3&gt;

&lt;p&gt;Syncthing uses BoltDB as its internal database - it stores file indexes, sync state, and peer information there. BoltDB flushes to disk &lt;strong&gt;every 60 seconds&lt;/strong&gt; regardless of whether anything changed.&lt;/p&gt;

&lt;p&gt;On a busy sync folder with thousands of files, this flush isn't a single sequential write. It rewrites pages across the B-tree structure, which means multiple seeks across the database file. Quiet when it's an SSD. Audible on HDDs - a short burst of activity every minute, on the minute, forever.&lt;/p&gt;

&lt;p&gt;Once you know this, you'll recognize the pattern. Every 60 seconds: click-click-seek. Every 60 seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Everything Else Piling On
&lt;/h3&gt;

&lt;p&gt;Beyond Docker and Syncthing, a typical homelab NAS has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System monitoring tools running on cron (every 5-10 minutes, writing stats to disk)&lt;/li&gt;
&lt;li&gt;systemd journal flushing logs&lt;/li&gt;
&lt;li&gt;The NAS OS itself doing housekeeping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these alone would be noticeable. All of them together, on top of Docker and Syncthing, means the HDDs are never idle long enough to spin down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagnosing Which Process Is the Problem
&lt;/h2&gt;

&lt;p&gt;Before moving anything, confirm what's actually hitting the disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Real-time I/O per process (needs sysstat)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;iotop &lt;span class="nt"&gt;-o&lt;/span&gt;

&lt;span class="c"&gt;# Disk utilization over time&lt;/span&gt;
iostat &lt;span class="nt"&gt;-x&lt;/span&gt; 2 10

&lt;span class="c"&gt;# Which files are being written most&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;fatrace | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'W|O'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;iotop -o&lt;/code&gt; shows only processes with active I/O. On a typical Docker + Syncthing setup you'll see the Docker daemon and the Syncthing process trading places at the top, with periodic spikes from cron jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix: Move the Noisy Workloads Off the HDDs
&lt;/h2&gt;

&lt;p&gt;The HDDs are loud because they're doing work they shouldn't be doing. The solution is to give that work to something that doesn't make noise.&lt;/p&gt;

&lt;p&gt;An external SSD connected via USB is cheap, silent, and fast enough for everything Docker and Syncthing need. USB 3.0 to a SATA SSD delivers 400+ MB/s - far more than any container workload requires.&lt;/p&gt;

&lt;p&gt;The goal: &lt;strong&gt;HDDs handle only the NAS OS and system logs&lt;/strong&gt;. Everything else moves to the SSD.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to Migrate
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Docker data-root&lt;/strong&gt; - the overlay2 layers, image cache, container writable layers. By default this lives in a path managed by the NAS OS. Moving it to the SSD means all container I/O hits flash storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/docker/daemon.json&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"data-root"&lt;/span&gt;: &lt;span class="s2"&gt;"/mnt/external-ssd/@docker"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bind-mount volumes&lt;/strong&gt; - the persistent data your containers read and write (databases, config files, sync folders). If these live on the HDD, container writes hit the HDD. Move them to the SSD.&lt;/p&gt;

&lt;p&gt;For bind mounts, a symlink keeps things transparent - containers keep using the same paths, no reconfiguration needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Original path stays the same from Docker's perspective&lt;/span&gt;
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /mnt/external-ssd/volumes /original/volumes/path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Syncthing database&lt;/strong&gt; - if you can point Syncthing's home directory to the SSD, the 60-second BoltDB flush hits flash instead of spinning metal.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Stays on the HDDs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The NAS operating system&lt;/li&gt;
&lt;li&gt;System logs&lt;/li&gt;
&lt;li&gt;Your actual data files (documents, media, backups) - these have sequential I/O patterns that HDDs handle well and that don't cause the constant seeking noise&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Note on Copying Files (UGOS Pro Caveat)
&lt;/h2&gt;

&lt;p&gt;If your NAS runs UGOS Pro (UGREEN's Debian-based OS), there's a critical gotcha: &lt;strong&gt;rsync will silently corrupt permissions&lt;/strong&gt; when copying from the NAS filesystem to an external drive. This is caused by proprietary kernel-level xattr hooks in UGOS Pro.&lt;/p&gt;

&lt;p&gt;I ran into this the hard way. Both &lt;code&gt;rsync -aHX&lt;/code&gt; and &lt;code&gt;rsync -aH --no-xattrs&lt;/code&gt; result in all files getting reset to &lt;code&gt;600&lt;/code&gt; permissions - containers fail to start, nothing works.&lt;/p&gt;

&lt;p&gt;The fix and the full technical explanation are in a separate post: &lt;a href="https://dev.to/iatxako/why-rsync-destroys-permissions-on-ugos-pro-and-the-only-fix-that-works-olh"&gt;Why rsync Destroys Permissions on UGOS Pro - and the Only Fix That Works&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Short version: use &lt;code&gt;tar --xattrs-exclude='ug.*'&lt;/code&gt; instead of rsync for any file copy on UGOS Pro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mount the SSD Correctly
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/fstab&lt;/span&gt;
&lt;span class="nv"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-uuid&amp;gt; /mnt/external-ssd ext4 defaults,noatime,nofail 0 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two flags matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;noatime&lt;/code&gt; - disables access time updates on every file read. Eliminates a whole class of unnecessary writes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nofail&lt;/code&gt; - if the SSD disconnects and the NAS reboots, it boots normally instead of hanging at the fstab error. Containers won't start, but the NAS stays accessible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;After migration: the HDDs are nearly silent. You can hear them spin up occasionally - system logs flushing, a cron job writing stats - but the constant background noise is gone. The 60-second Syncthing heartbeat is inaudible. Container I/O is invisible.&lt;/p&gt;

&lt;p&gt;The NAS is back to being the quiet box in the corner it was always supposed to be.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If your NAS runs UGOS Pro, read the companion post before attempting the migration - the rsync issue will cost you time if you hit it blind: &lt;a href="https://dev.to/iatxako/why-rsync-destroys-permissions-on-ugos-pro-and-the-only-fix-that-works-olh"&gt;Why rsync Destroys Permissions on UGOS Pro&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>homelab</category>
      <category>nas</category>
      <category>syncthing</category>
    </item>
    <item>
      <title>Why rsync Destroys Permissions on UGOS Pro - and the Only Fix That Works</title>
      <dc:creator>iatxako</dc:creator>
      <pubDate>Mon, 01 Jun 2026 21:13:51 +0000</pubDate>
      <link>https://dev.to/iatxako/why-rsync-destroys-permissions-on-ugos-pro-and-the-only-fix-that-works-olh</link>
      <guid>https://dev.to/iatxako/why-rsync-destroys-permissions-on-ugos-pro-and-the-only-fix-that-works-olh</guid>
      <description>&lt;p&gt;Moving Docker from HDDs to an external SSD on an ARM64 NAS running UGOS Pro (Debian 12) looked simple. It took two failed approaches to find out the OS itself was the obstacle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;A UGREEN NAS running UGOS Pro - a customized Debian 12 on ARM64 - hosting several Docker containers. All Docker data sitting on slow mechanical HDDs: both the &lt;code&gt;data-root&lt;/code&gt; (overlay2 layers) and bind-mount volumes. Goal: migrate everything to an external SSD connected via USB to eliminate HDD I/O noise from containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Attempt: rsync -aHX
&lt;/h2&gt;

&lt;p&gt;Standard approach for Docker migrations. Copy everything, stop Docker, delta-sync, update &lt;code&gt;daemon.json&lt;/code&gt;, restart.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rsync &lt;span class="nt"&gt;-aHX&lt;/span&gt; /volume1/@docker/ /mnt/external-ssd/@docker/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy succeeded. Docker started. Containers launched. Two minutes later - every container crashed with permission errors. All binaries inside the overlay2 layers had been reset to &lt;code&gt;600&lt;/code&gt;. Not executable. Just broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second Attempt: rsync Without Xattrs
&lt;/h2&gt;

&lt;p&gt;Suspected xattr copy was the problem. Excluded them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rsync &lt;span class="nt"&gt;-aH&lt;/span&gt; &lt;span class="nt"&gt;--no-xattrs&lt;/span&gt; /volume1/@docker/ /mnt/external-ssd/@docker/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same result. All files &lt;code&gt;600&lt;/code&gt; again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause: UGOS Pro's Kernel VFS Hook
&lt;/h2&gt;

&lt;p&gt;UGOS Pro adds two proprietary extended attributes to every file on its native filesystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ug.archive_bit&lt;/code&gt; - tracks archive state for backup tooling&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;system.ugacl_self&lt;/code&gt; - stores the NAS's custom ACL data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The custom ARM64 kernel includes VFS-level hooks tied to these xattrs. The hook behavior:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When &lt;code&gt;ug.archive_bit&lt;/code&gt; is written to any filesystem&lt;/strong&gt; - including ext4 on the SSD - the kernel resets that file's permissions to &lt;code&gt;600&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This fires in both rsync modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;-X&lt;/code&gt;: rsync explicitly copies &lt;code&gt;ug.*&lt;/code&gt; xattrs to the destination ? hook fires&lt;/li&gt;
&lt;li&gt;Without xattrs: rsync calls &lt;code&gt;chmod()&lt;/code&gt; after writing files ? the kernel hook intercepts the chmod and applies &lt;code&gt;ug.*&lt;/code&gt; to the new file ? hook fires again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No rsync flag combination avoids this. The hook is below userspace.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix: tar with --xattrs-exclude
&lt;/h2&gt;

&lt;p&gt;The solution is &lt;code&gt;tar&lt;/code&gt; with explicit xattr exclusion. Unlike rsync, tar applies the file mode &lt;strong&gt;atomically during extraction&lt;/strong&gt; - the kernel doesn't get a separate chmod syscall to intercept.&lt;/p&gt;

&lt;p&gt;Excluding &lt;code&gt;ug.*&lt;/code&gt; ensures they're never written to the destination:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo tar&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs-include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'*.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs-exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ug.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cpf&lt;/span&gt; - &lt;span class="nt"&gt;-C&lt;/span&gt; /source/path directory-name &lt;span class="se"&gt;\&lt;/span&gt;
| &lt;span class="nb"&gt;sudo tar&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs-include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'*.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs-exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ug.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-xpf&lt;/span&gt; - &lt;span class="nt"&gt;-C&lt;/span&gt; /destination/path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipe avoids writing to disk twice. The &lt;code&gt;--xattrs-include='*.*'&lt;/code&gt; is required - without it, &lt;code&gt;--xattrs-exclude&lt;/code&gt; is silently ignored.&lt;/p&gt;

&lt;p&gt;Expected warning during extraction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tar&lt;/span&gt;: system.ugacl_self: Operation not supported
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Harmless. The ext4 SSD doesn't support this xattr type, tar reports it and continues normally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prepare the SSD
&lt;/h3&gt;

&lt;p&gt;Add to &lt;code&gt;/etc/fstab&lt;/code&gt; for persistent mount:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;=&amp;lt;&lt;span class="n"&gt;your&lt;/span&gt;-&lt;span class="n"&gt;uuid&lt;/span&gt;&amp;gt; /&lt;span class="n"&gt;mnt&lt;/span&gt;/&lt;span class="n"&gt;external&lt;/span&gt;-&lt;span class="n"&gt;ssd&lt;/span&gt; &lt;span class="n"&gt;ext4&lt;/span&gt; &lt;span class="n"&gt;defaults&lt;/span&gt;,&lt;span class="n"&gt;noatime&lt;/span&gt;,&lt;span class="n"&gt;nofail&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;nofail&lt;/code&gt; flag is critical - without it, a disconnected SSD during boot will hang the NAS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /mnt/external-ssd
&lt;span class="nb"&gt;sudo &lt;/span&gt;mount &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phase 1: Migrate Docker data-root
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stop Docker completely - both socket and service&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop docker.socket docker.service

&lt;span class="c"&gt;# Copy with tar pipe&lt;/span&gt;
&lt;span class="nb"&gt;sudo tar&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs&lt;/span&gt; &lt;span class="nt"&gt;--xattrs-include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'*.*'&lt;/span&gt; &lt;span class="nt"&gt;--xattrs-exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ug.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cpf&lt;/span&gt; - &lt;span class="nt"&gt;-C&lt;/span&gt; /original/docker/path @docker &lt;span class="se"&gt;\&lt;/span&gt;
| &lt;span class="nb"&gt;sudo tar&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs&lt;/span&gt; &lt;span class="nt"&gt;--xattrs-include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'*.*'&lt;/span&gt; &lt;span class="nt"&gt;--xattrs-exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ug.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-xpf&lt;/span&gt; - &lt;span class="nt"&gt;-C&lt;/span&gt; /mnt/external-ssd

&lt;span class="c"&gt;# Update daemon.json&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"data-root": "/mnt/external-ssd/@docker"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/docker/daemon.json

&lt;span class="c"&gt;# Restart and verify&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start docker
docker info | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'Docker Root Dir'&lt;/span&gt;
docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Phase 2: Migrate bind-mount volumes
&lt;/h3&gt;

&lt;p&gt;The symlink approach avoids recreating any containers - Docker sees the same path, it just resolves to the SSD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop docker.socket docker.service

&lt;span class="nb"&gt;sudo tar&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs&lt;/span&gt; &lt;span class="nt"&gt;--xattrs-include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'*.*'&lt;/span&gt; &lt;span class="nt"&gt;--xattrs-exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ug.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-cpf&lt;/span&gt; - &lt;span class="nt"&gt;-C&lt;/span&gt; /original/volumes/path &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
| &lt;span class="nb"&gt;sudo tar&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--xattrs&lt;/span&gt; &lt;span class="nt"&gt;--xattrs-include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'*.*'&lt;/span&gt; &lt;span class="nt"&gt;--xattrs-exclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'ug.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-xpf&lt;/span&gt; - &lt;span class="nt"&gt;-C&lt;/span&gt; /mnt/external-ssd/volumes

&lt;span class="c"&gt;# Replace original directory with symlink&lt;/span&gt;
&lt;span class="nb"&gt;sudo mv&lt;/span&gt; /original/volumes/path /original/volumes/path.bak
&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /mnt/external-ssd/volumes /original/volumes/path

&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start docker
docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /original/volumes/path
&lt;span class="nb"&gt;readlink&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /original/volumes/path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;All containers running from SSD. HDD I/O dropped significantly. Mechanical drives now only handle the OS, logs, and background system processes. The symlink approach meant zero container reconfiguration.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rule for UGOS Pro
&lt;/h2&gt;

&lt;p&gt;Any time you copy files &lt;strong&gt;from&lt;/strong&gt; UGOS Pro's native filesystem to another filesystem (ext4, btrfs, tmpfs), use &lt;code&gt;tar --xattrs-exclude='ug.*'&lt;/code&gt;. rsync cannot be made safe for this operation regardless of flags.&lt;/p&gt;

&lt;p&gt;This applies to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker data-root migrations&lt;/li&gt;
&lt;li&gt;Backup operations targeting external drives&lt;/li&gt;
&lt;li&gt;Any bulk copy from UGOS-managed paths to a non-UGOS filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The warning &lt;code&gt;system.ugacl_self: Operation not supported&lt;/code&gt; will appear during extraction - it's harmless.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tested on UGOS Pro with a custom ARM64 kernel. If you hit this on a different NAS OS with proprietary xattr hooks, the same pattern applies - find the vendor xattr prefix and exclude it from tar.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>nas</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
