> /home/jd

Automated Rsync Backup from Synology NAS to USB via Proxmox LXC

Automated Incremental Contingency System using rsync between Synology DSM and an LXC Container.

Context and Architecture

đź”™ Main Context: This guide is part of the extensive architecture detailed in the Infrastructure MOC.

Objective: Create an automated, local, and internet outage-resistant backup system that incrementally copies folders Dropbox and G-Drive from the Synology NAS (Source) to an external hard drive. Target Hardware: 320GB External HDD. The exFAT format is used for portability, allowing the disk to be disconnected and read natively and immediately on the main system (Hackintosh). Architecture: Synology NAS -> Local Network -> Proxmox Node -> Privileged LXC Container -> 320GB USB HDD.


Phase 1: Preparation of the Mother Source (Synology DSM)

To maintain security and the principle of least privilege, the container will not access with an administrator account, but rather with a unique and restricted user account.

  1. Go to Control Panel > User and Group > Create.
  2. Credentials: * User: backupjd
    • Secure password assigned (e.g. Generic2026Sys).
  3. Shared Folder Permissions: Assign Read-Only strictly to the folder Drive (where data resides).
  4. Application Permissions: Ensure that the SMB service is marked as Allowed.

Phase 2: Persistent Mounting of HDD on Proxmox (Host)

Avoid the common mistake where Proxmox changes the letter of the unit (from /dev/sdb to /dev/sde) when reconnecting the USB hot. It is necessary to anchor by its unique identity (UUID).

  1. Get the disk’s UUID:
Bash
   blkid /dev/sde2  # Reemplazar por la particiĂłn correcta

Note the alphanumeric code, e.g., 69A3-7677.

  1. Edit the system assembly table:
Bash
nano /etc/fstab
  1. Add the mounting rule (At the end of the file):
Text
    UUID=69A3-7677 /mnt/backup_contingencia exfat defaults,nofail 0 0

Note: The nofail flag is crucial. If the server restarts after a power outage and the USB is not connected, Proxmox will ignore the mount and continue booting without getting stuck in a kernel panic.

  1. Reload the daemon and mount:
Bash
    systemctl daemon-reload
    mount -a

Phase 3: Container Creation and Configuration (LXC)

The container that acts as an intermediary must have elevated permissions to interact with network protocols at the kernel level.

  1. Create the LXC:

    • ID: 102 (Name: rsync backup)
    • OS: Debian 12
    • Resources: 1 Core, 1024MB RAM, DHCP Network.
    • CRITICAL: In the General tab, DISABLE the option Unprivileged container mandatorily.
  2. Enable Network Features:

    • With the LXC created (but turned off), go to Options > Features.
    • Enable the SMB/CIFS checkbox. Without this, AppArmor will block any attempt to use mount.cifs.
  3. Create the bridge (Bind Mount) from the Host to LXC:

    Run in the main console of the Proxmox node (not inside the LXC):

Bash
    pct set 102 -mp0 /mnt/backup_contingencia,mp=/mnt/usb_contingencia

Phase 4: Internal Scripting and Automation (LXC)

  1. Start the LXC, open its console and install dependencies:
Bash
    apt update && apt install rsync cifs-utils nano -y
    mkdir -p /mnt/dsm_drive
  1. Create the Bash script:
Bash
    nano /root/backup.sh
  1. Definitive code (backup.sh):
Bash
#!/bin/bash

LOG_GENERAL="/var/log/backup_estado.log"
echo "========================================" >> $LOG_GENERAL
echo "Iniciando contingencia: $(date)" >> $LOG_GENERAL

# Se agregaron echo_interval=60 y serverino para mantener vivo el tunel CIFS
if mount -t cifs -o username=[TU_USUARIO], password=[TU_PASSWORD], ro,vers=3.0,echo_interval=60,serverino //192.168.X.X/Drive /mnt/dsm_drive; then
    
    echo "Conexion OK. Copiando..." >> $LOG_GENERAL

    # Espejar Dropbox con tolerancia a latencia de I/O (--timeout)
    rsync -rtvh --delete --timeout=600 --log-file=/var/log/backup_archivos.log /mnt/dsm_drive/Dropbox/ /mnt/usb_contingencia/Dropbox/

    # Espejar G-Drive con tolerancia a latencia de I/O (--timeout)
    rsync -rtvh --delete --timeout=600 --log-file=/var/log/backup_archivos.log /mnt/dsm_drive/G-Drive/ /mnt/usb_contingencia/G-Drive/

    umount /mnt/dsm_drive
    echo "Exito total. Red desconectada: $(date)" >> $LOG_GENERAL

else
    echo "ERROR CRITICO: No se pudo conectar a DSM." >> $LOG_GENERAL
    exit 1
fi
  1. Grant execution permissions:
Bash
    chmod +x /root/backup.sh
  1. Scheduling the Cron Job (Every day at 1:00 AM):
Bash
    crontab -e
  • Add to the end of the file:
Text
    0 1 * * * /root/backup.sh > /var/log/cron_backup.log 2>&1

Troubleshooting Log and Solutions

During the development of this architecture, multiple roadblocks emerged. Below is the documentation for each error code and its resolution:

  • Error: mount error(1): Operation not permitted

    • Diagnostic: The container was created as “Unprivileged” (Without privileges). The Linux kernel prohibits mounting network file systems (SMB/CIFS) for perimeter security reasons.

    • Solution: Remove the LXC and recreate it by untitled “Unprivileged container” in the initial configuration.

  • Error: mount error(13): Permission denied (With 100% correct credentials).

    • Diagnosis (AppArmor): The internal security module of Proxmox was blocking the operation. It was checked by reviewing kernel logs (dmesg | tail -n 10), which showed: apparmor="DENIED" operation="mount" fstype="cifs".

    • Solution: In the LXC options > Features, check the box SMB/CIFS. Restart the container.

  • Error: mount error(13): Permission denied (Protocol rejection).

    • Diagnostic: Conflict between NTLM dialects between Debian 12 (modern) and Synology DSM.

    • Solution: Inject the parameter vers=3.0 into the mount.cifs command in the script.

  • Error: rsync error: some files/attrs were not transferred (code 23)

    • Diagnosis: The standard flag -a (archive) was used with rsync, which attempts to replicate the owners (chown) and permissions (chmod) of Linux. The target disk, formatted in exFAT, does not understand permissions and returns an error at the end of the transfer.

    • Solution: Modify the rsync line by changing -avh to -rtvh (recursive, preserves modification times, verbose, human-readable).

  • Error: Disconnecting the USB to verify data and reconnecting it throws “can’t find in /etc/fstab” when trying to mount.

    • Diagnostic: Dynamic block assignment (/dev/sdb became /dev/sde).

    • Solution: Extract the UUID with blkid and permanently embed it in /etc/fstab (Phase 2).

  • Error: rsync: [sender] write error: Broken pipe (32) and code 23 constant.

    • Diagnostic: Network micro-cuts due to timeouts between the LXC container and Synology DSM when processing thousands of small files (e.g., Python virtual environments). The connection closes due to inactivity.
    • Solution: Modify the CIFS tunnel by adding echo_interval=60,serverino to the mount command to keep ping active. In the rsync command, inject the parameter --timeout=600 to tolerate latency spikes in reading.
  • Error: rsync: [receiver] mkstemp ... failed: Invalid argument (22)

    • Diagnosis: Format conflict. The contingency disk uses exFAT, which prohibits the use of special characters in file names (?, ", |, <, >, *, :, \, /) due to architecture restrictions. Rsync is unable to write them and aborts the file.
    • Solution: Rename problematic files in the source master (Synology/Local) by removing prohibited characters.

Automated translation (technical mode).