FreeNas Remote Backups

So I love that ZFS allows automated snapshots and that my FreeNas box is set up with a 3 disk Raid.  However, I’m paranoid.  What if the house burns down, or someone breaks in and steals all our computers?  A smart guy would have a remote backup somewhere.  So, I decided it was time to get my remote backup groove on.

I know that you can do a ZFS replication to another FreeNas box. The issue I have with that approach is that you have to replicate the entire ZFS volume. I needed something more granular.  So, I busted out some python and started working on a remote backup script. To give credit where it is due, my brother helped me get started…so thanks big brother. 

*Disclaimer*

I am not a programmer.  This code and instructions are provided “as is” with no warranty, promise that it works, promise that is won’t melt your computer or even cause the end of the World.  Use at your own risk.

The general overview of how the remote backup program works is like this. First the program connects to the remote computer and rsync’s all of your files. It’s setup so that you can have four different sets of remote backups all running on different days if you want. I personally am only using one backup that runs every day. Next, it determines the disk usage of the remote backup disk. It then calculates how long the backup took. Once it has all of that done, it compiles an email with a general status at the top and the details at the bottom.

So here’s the setup.  FreeNas 8.2 at home.  Mac Pro running OS X 10.6.8 at work with a 3TB drive attached. (This probably will not work “as is” if the remote machine isn’t “unix” based) I already have ssh access to the work computer. Decided the best way to push out the files was to use rsync. I really don’t care about old versions of my files on the remote backup. If a person did care about that they could use rdiff-backup…or duplicity if you wanted the backups to be encrypted, but that will require some changes to the code.

Alright, alright, alright. So before I get too far off coarse. This will be pretty easy for other people to do. I’ll break it down into steps.

  1. Create a user on your FreeNas box that you can ssh in to. Create or copy your ssh keys into the .ssh folder of your new user on the FreeNas box. Then copy the public key of the pair into the authorized_keys file on your remote computer.
  2. ssh into your FreeNas box and create a file named config.py  The easy way to do that is:
    vi config.py
    

    Then download this file and make changes to the config options so they make sense for you. config.py (I’ll paste this in as text at the bottom) The program is designed to allow 4 different backups to be done…hopefully that will be enough granularity. When you are done setting it up, copy it and then paste it into the config.py file you just created on your FreeNas box. When you are done pasting, type :wq to save and quit out of vi.

  3. Now you need to download the FreeNasBackup.py file.(I’ll paste this in as text at the bottom, but use the download as white space matters in python and WordPress has messed up a bunch of the code)  This file shouldn’t need to change…unless you want to improve it 😉 Get that onto your FreeNas box the same way you got config.py there. ***IMPORTANT*** config.py and FreeNasBackup.py need to be in the same directory.  You can change the name of FreeNasBackup.py to whatever.py you want…but config.py needs to stay named config.py.
  4. ***MORE IMPORTANT STUFF*** I highly recommend that you do an initial backup to the remote drive locally before running this program.  Now, on the FreeNas box, cd to the location of the FreeNasBackup.py program and then type (It is going to run for a long time):
    python FreeNasBackup.py

    With any luck, the backup will run successfully and you’ll get a status report email with the results. It should look something like this:

    Remote Backup - Users: OK
    
    Checking remote disk usage: OK
    
    Backup Runtime (hh:mm:ss) 0:19:49
    
    Remote backup - Users - Details
    Number of files: 995547
    Number of files transferred: 49
    Total file size: 1002.69G bytes
    Total transferred file size: 64.19M bytes
    Literal data: 64.09M bytes
    Matched data: 102.93K bytes
    File list size: 29.81M
    File list generation time: 0.001 seconds
    File list transfer time: 0.000 seconds
    Total bytes sent: 94.11M
    Total bytes received: 279.08K
    
    sent 94.11M bytes  received 279.08K bytes  79.42K bytes/sec
    total size is 1002.69G  speedup is 10623.07
    --------------------------------------------------
    
    Remote Disk Usage Details
    
    Filesystem     Size   Used   Avail  Cap  Mounted on
    /dev/disk14s2  2.7Ti  940Gi  1.8Ti  34%  /Volumes/RemoteBackup
    
    --------------------------------------------------
  5. log in to the FreeNas webGUI and setup a new cron job to run your shiny new remote backup program. The user should be set to root.  The command you want is something like this: python /mnt/some/directory/FreeNasBackup.py  Set the criteria for how often it runs as you wish.

Well, that’s pretty much it.  I’m sure I’m forgetting a bunch of stuff…so I’ll fill in the blanks if I think of them.  Let me know how it works for you. Good Luck.

Also, if you find this super useful, I wouldn’t turn down paypal donations.

Here’s the config.py file contents:

###E-mail configuration###
#08-26-2012
#Written by Joe Paetzel
#Servername is a descriptive name to describe the server that is getting backed up
SERVERNAME = "Freenas.local"
SMTPSERVER = "mail.something.com"
#who the email status report comes from
SENDER = "someone@somewhere.com"
#who gets the status report
RECIP = "someone.else@somewhere.com"
#email port will probably be 25 or 587
EMAIL_PORT = "587"
#user name you authenticate with to your mail server
MAIL_AUTH_NAME = "someone@somewhere.com"
#password you authenticate with to your mail server
MAIL_AUTH_PASS = "some_password"

###SSH configuration###
#path to your ssh private key
SSH_IDENT = "-i /mnt/Files/joe-freenas/.ssh/id_rsa"
#port to ssh to on the remote computer, standard is 22
SSH_PORT = "-p 22222"
#the user name and host you are copying files to
SSH_HOST = "user@some.doamin.com"

###Backup configuration###
#user name and host for rsync to connect to user@some.host.com: (must include the trailing ":")
REM_HOST = "user@some.host.com:"
#Name of the volume to backup to. Used in pulling drive usage.
BACKUP_DRIVE = "RemoteBackup"

###Backup Set 1###
#Choose the day you want this set to run: Sunday=0, Saturday=6 (0-6) & Everyday=7
REM_BACKUP_DAY1 = 7
#Files to backup remotely - use complete paths. For more than 1 backup directory
#change the 0 to a quoted full path.
REM_BACKUP_DIR1 = "/mnt/Files/Users/"
#descriptive title for this backup source
RB_SHORT_DIR1 = "Users"
#Remote backup destinations - use complete paths. For more than 1 backup directory
#change the 0 to a quoted full path.
REM_DEST_DIR1 = "/Volumes/RemoteBackup/"

###Backup Set 2###
#Choose the day you want this set to run: Sunday=0, Saturday=6 (0-6) & Everyday=7 None=8
REM_BACKUP_DAY2 = 8
#Files to backup remotely - use complete paths. For more than 1 backup directory
#change the 0 to a quoted full path.
REM_BACKUP_DIR2 = 0
#descriptive title for this backup source
RB_SHORT_DIR2 = ""
#Remote backup destinations - use complete paths. For more than 1 backup directory
#change the 0 to a quoted full path.
REM_DEST_DIR2 = 0

###Backup Set 3###
#Choose the day you want this set to run: Sunday=0, Saturday=6 (0-6) & Everyday=7 None=8
REM_BACKUP_DAY3 = 8
#Files to backup remotely - use complete paths. For more than 1 backup directory
#change the 0 to a quoted full path.
REM_BACKUP_DIR3 = 0
#descriptive title for this backup source
RB_SHORT_DIR3 = ""
#Remote backup destinations - use complete paths. For more than 1 backup directory
#change the 0 to a quoted full path.
REM_DEST_DIR3 = 0

###Backup Set 4###
#Choose the day you want this set to run: Sunday=0, Saturday=6 (0-6) & Everyday=7 None=8
REM_BACKUP_DAY4 = 8
#Files to backup remotely - use complete paths. For more than 1 backup directory
#change the 0 to a quoted full path.
REM_BACKUP_DIR4 = 0
#descriptive title for this backup source
RB_SHORT_DIR4 = ""
#Remote backup destinations - use complete paths. For more than 1 backup directory
#change the 0 to a quoted full path.
REM_DEST_DIR4 = 0

Here’s the FreeNasBackup.py file contents in a somewhat mangled form ***DO NOT COPY AND PASTE THIS…IT WON’T WORK***:

##################################################################################################################
######################## The Code - No need to edit any of this if everything is working #########################
##################################################################################################################
#08-26-2012
#Written by Joe Paetzel
#Python options
import config, os, smtplib, time, subprocess, datetime

os.environ['PATH'] = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:"

DAYOFWEEK = int(time.strftime("%w"))

#####
#Push out the Backups to a remote location
#####

#Remote Backup notification email
REM_DETAIL_STATUS_REPORT = """\

"""

REM_STATUS_REPORT = """\
To: %s
From: %s
Subject: Remote Backup Script - %s
MIME-Version: 1.0
Content-Type: text/html; charset=ISO-8859-1""" % (config.RECIP, config.SENDER, config.SERVERNAME)

TIME3 = time.time()

#Set which day of the week to run
if DAYOFWEEK == config.REM_BACKUP_DAY1 or config.REM_BACKUP_DAY1 == 7:

    ##Mount Remote Encrypted Disk Image
      ##This section is here if you want to backup to an encrypted disk image on
      ##your remote drive.  I'm no longer using this, so it's commented out
      ##but here if someone might find it useful. Was having a problem mounting
      ##the disk image with an ssh command so ended up making a little script
      ##to mount it. That script looks like this - which makes the encrypted
      ##part of the remote backup pretty insecure
      ###! /bin/sh
       ##printf password_that_encrypted_diskimage | hdiutil attach
       ## /path/to/Encrypted.sparseimage -stdinpass -noverify

    # try:
#      cmd = "ssh %s %s %s /bin/sh /Volumes/RemoteBackups/mount.sh" % (config.SSH_IDENT, config.SSH_PORT, config.SSH_HOST)
#      process = subprocess.Popen([cmd], shell=1,  stdin=subprocess.PIPE,     
#      stdout=subprocess.PIPE,  stderr=subprocess.PIPE)
#      stdoutdata, stderrdata = process.communicate()
#      exitcode = process.returncode
#      if exitcode != 0:
#        REM_STATUS_REPORT += "************************************************
"
#        REM_STATUS_REPORT += "Mounting Remote Encrypted Disk Image:strong span style="color: #ff0000;" FAILED! /span /strong
"
#        REM_STATUS_REPORT += "************************************************
"
#      else:
#        REM_STATUS_REPORT += "
Mount Remote Encrpyted Disk Image:strong span style="color: #01df01;" OK /span /strong
"
#      if stdoutdata:
#        ret = stdoutdata
#        ret2 = ret.decode("utf-8")
#        REM_DETAIL_STATUS_REPORT += "Mount Remote Encrpyted Disk Image:
"
#        REM_DETAIL_STATUS_REPORT += "
"
#        REM_DETAIL_STATUS_REPORT += ret2
#        REM_DETAIL_STATUS_REPORT += "/pre
"
# REM_DETAIL_STATUS_REPORT += "
"
# REM_DETAIL_STATUS_REPORT += "---------------------------------------------------------------------------------
"
# if stderrdata:
# ret = stderrdata
# ret2 = ret.decode("utf-8")
# REM_STATUS_REPORT += ret2
# REM_STATUS_REPORT += "
"
# except OSError:
# # all bets are off, chances are cmd was invalid
# REM_STATUS_REPORT += "caught OSError running Mount Remote Encrpyted Disk Image: %s
" % str(ret)

#Remote Backup Set 1
try:
cmd = "/usr/local/bin/rsync -rHhgotE -e 'ssh %s %s' --stats --del %s %s | grep -v skipping" % (config.SSH_IDENT, config.SSH_PORT, config.REM_BACKUP_DIR1, config.REM_HOST+config.REM_DEST_DIR1)
process = subprocess.Popen([cmd], shell=1, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutdata, stderrdata = process.communicate()
exitcode = process.returncode
if exitcode != 0:
REM_STATUS_REPORT += "************************************************
"
REM_STATUS_REPORT += "Remote Backup - %s: strong span style="color: #ff0000;" FAILED! /span /strong
" % config.RB_SHORT_DIR1
REM_STATUS_REPORT += "************************************************
"
else:
REM_STATUS_REPORT += "Remote Backup - %s: strong span style="color: #01df01;" OK /span /strong
" % config.RB_SHORT_DIR1
if stdoutdata:
ret = stdoutdata
ret2 = ret.decode("utf-8")
REM_DETAIL_STATUS_REPORT += "
Remote backup - %s - Details
" % config.RB_SHORT_DIR1
REM_DETAIL_STATUS_REPORT += "
"
       REM_DETAIL_STATUS_REPORT += ret2
       REM_DETAIL_STATUS_REPORT += "/pre
"
REM_DETAIL_STATUS_REPORT += "
"
REM_DETAIL_STATUS_REPORT += "---------------------------------------------------------------------------------
"
if stderrdata:
ret = stderrdata
ret2 = ret.decode("utf-8")
REM_STATUS_REPORT += ret2
REM_STATUS_REPORT += "
"
except OSError:
# all bets are off, chances are cmd was invalid
REM_STATUS_REPORT += "caught OSError running Remote Backup - %s: %s
" % (config.RB_SHORT_DIR1, str(ret))

#Remote Backup Set 2
#Set which day of the week to run
if DAYOFWEEK == config.REM_BACKUP_DAY2 or config.REM_BACKUP_DAY2 == 7:
if config.REM_BACKUP_DIR2 > 0:
try:
cmd = "/usr/local/bin/rsync -rHhgotE -e 'ssh %s %s' --stats --del %s %s | grep -v skipping" % (config.SSH_IDENT, config.SSH_PORT, config.REM_BACKUP_DIR2, config.REM_HOST+config.REM_DEST_DIR2)
process = subprocess.Popen([cmd], shell=1, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutdata, stderrdata = process.communicate()
exitcode = process.returncode
if exitcode != 0:
REM_STATUS_REPORT += "************************************************
"
REM_STATUS_REPORT += "Remote Backup - %s: strong span style="color: #ff0000;" FAILED! /span /strong
" % config.RB_SHORT_DIR2
REM_STATUS_REPORT += "************************************************
"
else:
REM_STATUS_REPORT += "Remote Backup - %s: strong span style="color: #01df01;" OK /span /strong
" % config.RB_SHORT_DIR2
if stdoutdata:
ret = stdoutdata
ret2 = ret.decode("utf-8")
REM_DETAIL_STATUS_REPORT += "

Remote backup - %s - Details
" % config.RB_SHORT_DIR2
REM_DETAIL_STATUS_REPORT += "
pre"
			   REM_DETAIL_STATUS_REPORT += ret2
			   REM_DETAIL_STATUS_REPORT += "/pre
"
REM_DETAIL_STATUS_REPORT += "
"
REM_DETAIL_STATUS_REPORT += "---------------------------------------------------------------------------------
"
if stderrdata:
ret = stderrdata
ret2 = ret.decode("utf-8")
REM_STATUS_REPORT += ret2
REM_STATUS_REPORT += "
"
except OSError:
# all bets are off, chances are cmd was invalid
REM_STATUS_REPORT += "caught OSError running Remote Backup - %s: %s
" % (config.RB_SHORT_DIR2, str(ret))

#Remote Backup Set 3
#Set which day of the week to run
if DAYOFWEEK == config.REM_BACKUP_DAY3 or config.REM_BACKUP_DAY3 == 7:
if config.REM_BACKUP_DIR3 > 0:
try:
cmd = "/usr/local/bin/rsync -rHhgotE -e 'ssh %s %s' --stats --del %s %s | grep -v skipping" % (config.SSH_IDENT, config.SSH_PORT, config.REM_BACKUP_DIR3, config.REM_HOST+config.REM_DEST_DIR3)
process = subprocess.Popen([cmd], shell=1, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutdata, stderrdata = process.communicate()
exitcode = process.returncode
if exitcode != 0:
REM_STATUS_REPORT += "************************************************
"
REM_STATUS_REPORT += "Remote Backup - %s: strong span style="color: #ff0000;" FAILED! /span /strong
" % config.RB_SHORT_DIR3
REM_STATUS_REPORT += "************************************************
"
else:
REM_STATUS_REPORT += "Remote Backup - %s: strong span style="color: #01df01;" OK /span /strong
" % config.RB_SHORT_DIR3
if stdoutdata:
ret = stdoutdata
ret2 = ret.decode("utf-8")
REM_DETAIL_STATUS_REPORT += "

Remote backup - %s - Details
" % config.RB_SHORT_DIR3
REM_DETAIL_STATUS_REPORT += "
pre"
			   REM_DETAIL_STATUS_REPORT += ret2
			   REM_DETAIL_STATUS_REPORT += "/pre
"
REM_DETAIL_STATUS_REPORT += "
"
REM_DETAIL_STATUS_REPORT += "---------------------------------------------------------------------------------
"
if stderrdata:
ret = stderrdata
ret2 = ret.decode("utf-8")
REM_STATUS_REPORT += ret2
REM_STATUS_REPORT += "
"
except OSError:
# all bets are off, chances are cmd was invalid
REM_STATUS_REPORT += "caught OSError running Remote Backup - %s: %s
" % (config.RB_SHORT_DIR3, str(ret))

#Remote Backup Set 4
#Set which day of the week to run
if DAYOFWEEK == config.REM_BACKUP_DAY4 or config.REM_BACKUP_DAY4 == 7:
if config.REM_BACKUP_DIR4 > 0:
try:
cmd = "/usr/local/bin/rsync -rHhgotE -e 'ssh %s %s' --stats --del %s %s | grep -v skipping" % (config.SSH_IDENT, config.SSH_PORT, config.REM_BACKUP_DIR4, config.REM_HOST+config.REM_DEST_DIR4)
process = subprocess.Popen([cmd], shell=1, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutdata, stderrdata = process.communicate()
exitcode = process.returncode
if exitcode != 0:
REM_STATUS_REPORT += "************************************************
"
REM_STATUS_REPORT += "Remote Backup - %s: strong span style="color: #ff0000;" FAILED! /span /strong
" % config.RB_SHORT_DIR4
REM_STATUS_REPORT += "************************************************
"
else:
REM_STATUS_REPORT += "Remote Backup - %s: strong span style="color: #01df01;" OK /span /strong
" % config.RB_SHORT_DIR4
if stdoutdata:
ret = stdoutdata
ret2 = ret.decode("utf-8")
REM_DETAIL_STATUS_REPORT += "

Remote backup - %s - Details
" % config.RB_SHORT_DIR4
REM_DETAIL_STATUS_REPORT += "
pre"
			   REM_DETAIL_STATUS_REPORT += ret2
			   REM_DETAIL_STATUS_REPORT += "/pre
"
REM_DETAIL_STATUS_REPORT += "
"
REM_DETAIL_STATUS_REPORT += "---------------------------------------------------------------------------------
"
if stderrdata:
ret = stderrdata
ret2 = ret.decode("utf-8")
REM_STATUS_REPORT += ret2
REM_STATUS_REPORT += "
"
except OSError:
# all bets are off, chances are cmd was invalid
REM_STATUS_REPORT += "caught OSError running Remote Backup - %s: %s
" % (config.RB_SHORT_DIR4, str(ret))

#Check Available Spacce on the Remote Disk
try:
cmd = "ssh %s %s %s df -hl | grep %s" % (config.SSH_IDENT, config.SSH_PORT, config.SSH_HOST, config.BACKUP_DRIVE)
process = subprocess.Popen([cmd], shell=1, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutdata, stderrdata = process.communicate()
exitcode = process.returncode
if exitcode != 0:
REM_STATUS_REPORT += "************************************************
"
REM_STATUS_REPORT += "Checking Remote Disk Usage:strong span style="color: #ff0000;" FAILED! /span /strong
"
REM_STATUS_REPORT += "************************************************
"
else:
REM_STATUS_REPORT += "
Checking remote disk usage:strong span style="color: #01df01;" OK /span /strong
"
if stdoutdata:
ret = stdoutdata
ret2 = ret.decode("utf-8")
REM_DETAIL_STATUS_REPORT += "Remote Disk Usage Details
"
REM_DETAIL_STATUS_REPORT += "Filesystem            Size     Used     Avail     Cap         Mounted on
"
REM_DETAIL_STATUS_REPORT += "
pre"
       REM_DETAIL_STATUS_REPORT += ret2
       REM_DETAIL_STATUS_REPORT += "/pre
"
REM_DETAIL_STATUS_REPORT += "
"
REM_DETAIL_STATUS_REPORT += "---------------------------------------------------------------------------------
"
if stderrdata:
ret = stderrdata
ret2 = ret.decode("utf-8")
REM_STATUS_REPORT += ret2
REM_STATUS_REPORT += "
"
except OSError:
# all bets are off, chances are cmd was invalid
REM_STATUS_REPORT += "caught OSError running Checking Remote Disk Usage: %s
" % str(ret)

##Unmount Remote Encrypted Disk Image
# try:
# cmd = "ssh %s %s %s hdiutil detach -force /Volumes/EncryptedBackup" % (config.SSH_IDENT, config.SSH_PORT, config.SSH_HOST)
# process = subprocess.Popen([cmd], shell=1, stdin=subprocess.PIPE,
# stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# stdoutdata, stderrdata = process.communicate()
# exitcode = process.returncode
# if exitcode != 0:
# REM_STATUS_REPORT += "************************************************
"
# REM_STATUS_REPORT += "Unmounting Encrpyted Disk Image:strong span style="color: #ff0000;" FAILED! /span /strong
"
# REM_STATUS_REPORT += "************************************************
"
# else:
# REM_STATUS_REPORT += "
Unmounting Remote Encrpyted Disk Image:strong span style="color: #01df01;" OK /span /strong
"
# if stdoutdata:
# ret = stdoutdata
# ret2 = ret.decode("utf-8")
# REM_DETAIL_STATUS_REPORT += "Removing old System file Details
"
# REM_DETAIL_STATUS_REPORT += "
pre"
#        REM_DETAIL_STATUS_REPORT += ret2
#        REM_DETAIL_STATUS_REPORT += "/pre
"
# REM_DETAIL_STATUS_REPORT += "
"
# REM_DETAIL_STATUS_REPORT += "---------------------------------------------------------------------------------
"
# if stderrdata:
# ret = stderrdata
# ret2 = ret.decode("utf-8")
# REM_STATUS_REPORT += ret2
# REM_STATUS_REPORT += "
"
# except OSError:
# # all bets are off, chances are cmd was invalid
# REM_STATUS_REPORT += "caught OSError running Unmounting Remote Encrpyted Disk Image: %s
" % str(ret)

#Check how long the backup took to run
TIME4 = time.time()
RUNTIME = str(datetime.timedelta(seconds=(round(TIME4, 0) - round(TIME3, 0))))
REM_STATUS_REPORT += "
Backup Runtime (hh:mm:ss) %s

" % RUNTIME

#Close the Status_Report and send it
REM_STATUS_REPORT += "pre"
 session2 = smtplib.SMTP(config.SMTPSERVER, config.EMAIL_PORT)
 session2.login(config.MAIL_AUTH_NAME, config.MAIL_AUTH_PASS)
 session2.sendmail(config.SENDER, config.RECIP, REM_STATUS_REPORT+REM_DETAIL_STATUS_REPORT)

25 thoughts on “FreeNas Remote Backups

  1. Hi Joe – Thanks, I’ve seen http://www.rsync.net, however, the annual plan pricing for 1TB of storage is pretty steep ($1800) in comparison to CrashPlans+ “unlimited” service ($50 annually). Additionally, CrashPlan offers the initial seed service, where they send the 1TB USB drive to you, I send it back with the data, saves the headache of the initial transfer.

  2. Pingback: FreeNas Remote Backups | NAS Guide

  3. Pingback: My Homepage

  4. hi joe, thnx for posting this. would i be able to ask if you think my set up will work if i follow your instructions.

    i have a freenas 0.7.1 at home. i have a tonido plug, which is a commercial product with linux as underlying os, which sits at my in laws house.

    i want to essentially create my own offsite automated backup instead of using crashplan. the plan is to rsync files from freenas box to the tonidoplug over the internet.

    so what do you think? if i follow your steps exactly, will this work?

    i’m not a prgrammer. thanks for your time

    • Thanks for the nice comment. I’m glad that someone is finding it useful. I know some of the posts are a bit rambling with a lot of important info in the comments. Never claimed to be a professional writer 🙂 Really using this blog as notes to myself more than anything else.

  5. Hi Joe

    I completed following your guide and ran the python script as the last step. This is the error that I got. I have no idea what to do next. Any insight is much appreciated. Thanks.

    • What version of FreeNas are you running? On 8.3.1 it looks like python is 2.7. That could be the issue as it looks like you are running python 2.6. I guess I would start with either upgrading FreeNas if you aren’t on 8.3.1 or manually upgrade python to 2.7 using ports. Let me know if that helps.

  6. Not sure if perhaps things changed and some point over the years, but zfs replication does not require you specify the whole volume. In fact in freenas 9+ I don’t remember even seeing that as an option. Instead you specify what datasets you want replicated (and when).

    What zfs replication lacks IMO with freenas GUI is retention policies. There doesn’t seem to be an easy way to define a different retention of snapshots on the remote destination of a zfs replication. I believe zfs can do this though. This is very useful in a situation where you want to take local snapshots frequently ( say 5-10min max) and the local storage is more expensive and fast. You want those snapshots to only be retained for 1 day. The snapshots are replicated to cheap slower disks for long term retention.archiving. Maybe even want to clean those up and retain only 1 snapshot/day for 10 years or something.

    Also if you use rsync, it is built unto freenas so should be minimal effort.

  7. Hey man!
    Nice post by the way!
    Maybe you´ll be able to answer my question …

    It´s possible to use just at one side Freenas to get the data that i wanna sent from another location?
    Or by default has to be in both sides?
    I wanna send extra backup from local area network (work) to freenas to ensure just an extra backup

    Regards mate!

    • Depends on a bunch of stuff, but you should be able to setup a rsync job from work to home without freenas on both ends. That is assuming you can get rsync working on the non-freenas machine and you have open network ports and all that.

Leave a comment