Is there an app to remote backup with rsync?

I’m setting up an EX2 Ultra as a NAS drive for a client to use in their office, but they want everything backed up offsite as well. I have a web server so I wrote a script to rsync to my server using rsa keys and dropped it in the crontab. It all looked fine and worked perfectly up until the point where the crontab entry was deleted by the device and on reboot so was my script and rsa keys from the home directory.

I’ve read a few things on here that I can try to get it to persist my cron job and store the keys and script somewhere that doesn’t get zapped at reboot, but I wonder if I’m making it too complicated? It’s frustrating to get so close to having it set up and then it goes pear shaped for silly reasons. My concern is that even if I get it working reliably and consistently, a firmware update will stop it working again.

Is there another way of doing this task without essentially having to hack the system, an app perhaps?

tia

Darren

Hi,

See if this helps

Thanks for the reply.

I’ve got around the EX2’s habit of removing the scripts and keys by storing them on the physically mounted drive and copying them into the home directory when the rsync script is triggered. Just need to get around the crontab reset now, but I see some others have managed this by modifying config.xml to add a new crontab entry:

I’m a little bit loathe to test this in case it stops the device from booting if I get it wrong. Would a factory reset restore it if it did?

resilio sync which is what you are looking for .

https://help.getsync.com/hc/en-us/articles/206664870-Western-Digital

@Darren_Ryan

I had the same task to solve and ended up with creating a little custom WD-App that can be installed on the cloud device. This way it persists all settings across reboots and firmware updates and it seems like the only valid option to achieve this.

I’ll give a little intro how to build this custom app that uses RSA keys to connect to the remote server and uses rsync to download all backup files from the server to your local WD Cloud device. I used a WD MyCloudMirror Gen2 here, but I’m sure this script can also be used for other models.

All custom apps are built with Docker, a virtualization software that keeps every application in it’s own little container with it’s own Operating System - yes. We need to develop the custom app on the WD device itself, because it has limited capabilities and that way we can spot issues a bit better. Check http://developer.mycloud.com/MCDSDKindex.html for details about how to develop apps for the WD Cloud Devices.

1. Enable SSH on your WD Cloud device

  • Go to the admin dashboard and open Settings → Network
  • Enable ssh and create a password. The ssh login username is sshd
  • You can use any SSH client such as Putty.

2. Connect to the device via SSH

Once connected, first check the docker version installed on the machine. Type:

docker version

if should display something like this:

Client version: 1.7.0
OS/Arch (client): linux/amd64

For EX2 devices, it’ll probably display armv7.

3. Docker Base Image

Now before you can create an app, you need to install the base image.

Installing Docker base image on My Cloud DL2100 and DL4100:
docker pull ubuntu:14.04

Installing Docker base image on My Cloud EX2100, EX4100 and Mirror - Gen 2
docker pull armv7/armhf-ubuntu:14.04

4. Get familiar with docker commands

If something does not work or you screwed things up, it’s good to know at least these simple commands to get an overview:

show installed images:
docker images

show running container:
docker ps

show all available container:
docker ps -a

start new container with direct shell access:
docker run -it --name="helloworld_build" -v /shares/Public/helloworld:/helloworld ubuntu:14.04 /bin/bash

stop container:
docker stop helloworld_build

remove container:
docker rm helloworld_build

remove image:
docker rmi ubuntu:14.04

5. Prepare Docker App

In order to build the app, we need a working folder first. Goto your Public folder and create a folder. I’ll use RSyncSSH so it’ll be located at /shares/public/RSyncSSH/

Within that folder we place the files of our application. I ended up with this directory structure:

  • backup-rsync.sh
  • build/
    • app.json
    • icon.png
  • Dockerfile
  • keys/
    • id_rsa
    • id_rsa.pub
  • root.crontab
  • start.sh

My backup rsync script looks like the following (adjust this for your needs):

backup-rsync.sh:

#!/bin/bash
# Simple backup with rsync
# local-mode, tossh-mode, fromssh-mode

NAME="MyServer"
SOURCE="/backups/"
TARGET="/shares/Backup-MyServer"

#RSYNCCONF=(--delete)
RSYNCCONF=
# check local mountpoint
#MOUNTPOINT="/mnt/HD"               
#MAILREC="mail@myserver.com"
NOTIFYURI="https://myserver.com/backup-notify/?data="

SSHUSER="wdbackup"
FROMSSH="myserver.com"
SSHPORT=22

### do not edit ###

MOUNT="/bin/mount"; FGREP="/bin/fgrep"; SSH="/usr/bin/ssh"
LN="/bin/ln"; ECHO="/bin/echo"; DATE="/bin/date"; RM="/bin/rm"
DPKG="/usr/bin/dpkg"; AWK="/usr/bin/awk"; MAIL="/usr/bin/mail"
CUT="/usr/bin/cut"; TR="/usr/bin/tr"; RSYNC="/usr/bin/rsync"
LAST="last"; INC="--link-dest=$TARGET/$LAST"

#LOG=$0.log
LOG="${TARGET}/backup.log"
$DATE > $LOG

if [ "${TARGET:${#TARGET}-1:1}" != "/" ]; then
  TARGET=$TARGET/
fi

if [ "$LISTPACKAGES" ] && [ -z "$FROMSSH" ]; then
  $ECHO "$DPKG --get-selections | $AWK '!/deinstall|purge|hold/'|$CUT -f1 | $TR '\n' ' '" >> $LOG
  $DPKG --get-selections | $AWK '!/deinstall|purge|hold/'|$CUT -f1 |$TR '\n' ' '  >> $LOG  2>&1 
fi

if [ "$MOUNTPOINT" ]; then
  MOUNTED=$($MOUNT | $FGREP "$MOUNTPOINT");
fi

if [ -z "$MOUNTPOINT" ] || [ "$MOUNTED" ]; then

  if [ "$SSHUSER" ] && [ "$SSHPORT" ]; then
    S="$SSH -oStrictHostKeyChecking=no -p $SSHPORT -i /root/.ssh/id_rsa";
  fi

  if [ "$S" ] && [ "$FROMSSH" ]; then
	$ECHO "$RSYNC -av -e \"$S\" $SSHUSER@$FROMSSH:$SOURCE ${RSYNCCONF[@]} $TARGET"  >> $LOG 
	$RSYNC -av -e "$S" $SSHUSER@$FROMSSH:$SOURCE ${RSYNCCONF[@]} $TARGET >> $LOG 2>&1 
	if [ $? -ne 0 ]; then
	  ERROR=1
	fi 
	chmod -R 777 $TARGET
  fi 
      
else
  $ECHO "$MOUNTPOINT not mounted" >> $LOG
  ERROR=1
fi
$DATE >> $LOG
if [ -n "$MAILREC" ]; then
  if [ $ERROR ];then
    $MAIL -s "Error Backup $LOG" $MAILREC < $LOG
  else
    $MAIL -s "Backup $LOG" $MAILREC < $LOG
  fi
fi
if [ -n "$NOTIFYURI" ]; then
  if [ $ERROR ];then
    #wget -q "$NOTIFYURI:Error Backup:" < $LOG > NUL
	LOGCONTENT=$(<$LOG)
    wget -qO- "${NOTIFYURI}ERROR Backup $NAME: $LOGCONTENT" &> /dev/null
  else
    #wget -q "$NOTIFYURI:Backup $LOG" > NUL
	LOGCONTENT=$(<$LOG)
	LOGSPLIT=$(echo "$LOGCONTENT" | grep -A1 ^sent)
	wget -qO- "${NOTIFYURI}Backup complete: $NAME - $FROMSSH $LOGSPLIT" &> /dev/null
  fi
fi

I didn’t get it to work to send the notification emails, but I successfully call a URL after the rsync-backup is complete, so I can notify myself or write another log file entry.

Next the Dockerfile. This is used to install and prepare additional services to the OS within the app container:

# The FROM keyword must precede all other instructions. This specifies the Base image.
FROM armv7/armhf-ubuntu:14.04

MAINTAINER ikkez

# install requirements
RUN apt-get -q update
RUN apt-get install -y openssh-client && \
    apt-get install -y rsync && \
    apt-get install -y wget && \
    apt-get clean

# copy backup keys
RUN mkdir /root/.ssh
COPY keys/id_* /root/.ssh/
RUN chmod 600 /root/.ssh/*

# copy start script
COPY backup-rsync.sh /backup-rsync.sh
RUN chmod u+x /backup-rsync.sh

# copy container start script
COPY start.sh /start.sh
RUN chmod u+x /start.sh

#set timezone
RUN rm /etc/localtime
RUN ln -s /usr/share/zoneinfo/Europe/Berlin /etc/localtime

# setup cron tasks
ADD root.crontab /etc/cron.d/hello-cron
RUN chmod 0644 /etc/cron.d/hello-cron
RUN touch /var/log/cron.log
RUN /usr/bin/crontab /etc/cron.d/hello-cron

# add group to be able to set ownership correctly after transfer
RUN groupadd share

# The command to run when your Docker App container starts.
CMD [ "/start.sh" ]
####

Now the root.crontab file. This contains the crontab settings. I let my backups run at 2am. Adjust as you like.

0 2 * * * /backup-rsync.sh > /dev/null 2>&1
#* * * * * echo "Hello world" >> /var/log/cron.log 2>&1
# An empty line is required at the end of this file for a valid cron file.

And finally the start.sh file. This is used to start and stop the container properly:

#!/bin/bash

# When using a bash script as the entrypoint, you need to handle SIGTERM properly,
# Otherwise, Docker may fail to stop your app and forcefully kill it.
# An alternative is to use supervisord as the entrypoint to start your app. In that case,
# you will need to apt-get install supervisor in your Dockerfile.
function sighandler()
{
  kill -TERM $PID
  
}
trap sighandler TERM INT

echo "Starting RSyncSSH App"

exec /usr/sbin/cron -f


PID=$!
wait $PID

The file at /build/app.json contains some required information to install the final app on the WD device:

{
    "SDKVersion": "1.0",
    "Name": "RSyncSSH-myServer",
    "DisplayName": "RSync Backup myServer.com",
    "IconFile": "icon.png",
    "Description": "RSyncSSH Backup from remote Server",
    "Description.en_US": "RSyncSSH Backup from remote Server",
    "Description.cs_CZ": "RSyncSSH Backup from remote Server",
    "Description.de_DE": "RSyncSSH Backup from remote Server",
    "Description.es_ES": "RSyncSSH Backup from remote Server",
    "Description.fr_FR": "RSyncSSH Backup from remote Server",
    "Description.hu_HU": "RSyncSSH Backup from remote Server",
    "Description.it_IT": "RSyncSSH Backup from remote Server",
    "Description.ja_JP": "RSyncSSH Backup from remote Server",
    "Description.ko_KR": "RSyncSSH Backup from remote Server",
    "Description.no_NO": "RSyncSSH Backup from remote Server",
    "Description.nl_NL": "RSyncSSH Backup from remote Server",
    "Description.pl_PL": "RSyncSSH Backup from remote Server",
    "Description.pt_BR": "RSyncSSH Backup from remote Server",
    "Description.ru_RU": "RSyncSSH Backup from remote Server",
    "Description.sv_SE": "RSyncSSH Backup from remote Server",
    "Description.tr_TR": "RSyncSSH Backup from remote Server",
    "Description.zh_CN": "RSyncSSH Backup from remote Server",
    "Description.zh_TW": "RSyncSSH Backup from remote Server",
    "Vendor": "ikkez",
    "VendorURL": "http://www.myServer.de",
    "SupportURL": "http://www.myServer.de",
    "Version": "1.0",
    "ProductArchitecture": "armv7",
    "DockerImageFile": "rsync-ssh.tar.gz",
    "ConfigURLPort": 80,
    "ConfigURLPath": "",
    "ConfigAllUsers": true,
    "Configuration":
    {
        "Network":
        {
            "Mode": "host"
        },
        "Volumes":
        {
            "RequireAllVolumes": true         
        }
    }
}

The image file at build/icon.png can be any icon for you app. Mine is 363x363px and does work fine.
The key files at keys/ are used to connect via SSH to the remote server. The private key file does NOT have a passphrase set, as the installed OpenSSH version in this container isn’t able to deal with it and there doesn’t seem to be a way to upgrade it :confused:
The public key needs to be added to your remote servers .ssh/authorized_keys file of course.

Now the files are ready. Please ensure that the owner of this files is root. You can change the file owner like this:

cd /shares/public/RSyncSSH/
chown -R root:root *

Please note that you probably cannot change the files anymore via the network shared folder once you’ve changed the owner, but you can use a software like WinSCP or Transmit (Mac) to connect via ssh and open&edit files that way.

6. Build the Image

cd /shares/public/RSyncSSH/
dos2unix start.sh
dos2unix backup.sh
docker build --rm -t ikkez/rsync-ssh:1.0 .

when you have edited the .sh scripts with a windows editor, the line endings could have changes, which could result in a failed script execution. That’s why I’ve added dos2unix, just to make sure this issue doesn’t steal your time ( like it happend to me).

7. Create and run new container

Start the container in background:

docker run -dit --net="host" --name="RSyncSSH" -v /shares:/shares -v /mnt/HD/HD_a2:/mnt/HD/HD_a2 ikkez/rsync-ssh:1.0

optionally check some things manually:

check system time: (important if you want to run exact sheduled backups)

docker exec RSyncSSH date

You can change the timezone in the Dockerfile above. I’ve used Europe/Berlin.

Manually test the backup-script:

docker exec RSyncSSH ./backup-rsync.sh

If that works, it’ll take a while to complete and free the terminal, depending on how much it has to download. If you can find the files in the TARGET shared folder that was specified in the backup script, you’re ready to go.

8. Create App Package:

Export container, this can take some minutes:

docker save ikkez/rsync-ssh:1.0 | gzip > build/rsync-ssh.tar.gz

Create WD Package:

cd build/
tar -cvf rsync-ssh-app_myserver.tar -C . .

The dots . are important.

9. Clean up:

docker stop RSyncSSH
docker rm RSyncSSH
docker rmi ikkez/rsync-ssh:1.0

10. Download & Install

Now download the rsync-ssh-app_myserver.tar file from public shared folder and install it via web interface on your device. On the Apps Tab there is a link “Install an app manually”. Click this link, select the downloaded .tar file and wait for it to finish. After some time the new container has installed and should show up as usual application:

I have zipped all important files from this little guide here: http://bit.ly/2rhFMnH but not sure if I’ll keep them online there forever.

I hope this can be helpful for anyone to dive into creating custom apps or just to get a nice rsync backup to work. It took me some days to figure out all this stuff so leave a like if it was helpful. Thank you and have a nice day :slight_smile:

2 Likes