FreeNAS/NAS4Free Install Notes

This document contains notes on installing and using FreeNAS/NAS4Free to run a ZFS-based Network Attached Storage system.

By "FreeNAS" we mean versions of the product 7.x and less, not the currently-available product called FreeNAS. Originally, FreeNAS was all there was. Then, the name got sold and the company buying the name diverged the product to fit more in line with their business needs. Since the name was no longer available to them, the supporters of the original FreeNAS picked a new name when they opted to continue development on FreeNAS in the same vein as before. The new name is NAS4Free.

If you were using FreeNAS 7.x or 6.x and you wish to upgrade to something that looks and feels the same (but is just better), you will want to switch to NAS4Free. If you are planning a new installation, you can use these notes to instll either FreeNAS 7.x or NAS4Free 9.x (there is no NAS4Free 8.x). If you are undecided and are planning a new installation, there are copious opinions on the Internet about which is better (FreeNAS or NAS4Free). Obviously, we prefer NAS4Free but the choice is yours. You'll need a different set of install notes if you are going to install FreeNAS 8.x or greater.

To avoid confusion, we shall henceforth refer to the product as NAS4Free with the understanding that these notes may be used to install an earlier version of FreeNAS such as 7.x

Provisioning NAS4Free

Before you begin provisioning or installing NAS4Free, you may want to read the ZFS best practices guide at the Solaris Internals Wiki:

     http://www.solarisinternals.com/wiki/index.php/ZFS_Best_Practices_Guide

Admittedly, this best practices guide is pitched more towards someone who is setting up a ZFS repository with 50 disks, etc., but it may provide you with some insights that will be helpful. It certainly gives you a good idea about what is possible.

One thing we do learn is that ZFS is potentially a memory hog. It uses a lot of memory to do caching and buffering while it is computing checksums so at least a couple of gigabytes is a good thing. Fortunately, this amount of memory will set you back less than twenty-five bucks, at today's prices.

And speaking of checksums, the processor needs to be relatively snappy to be able to constantly compute checksums, which is a key operation in ZFS. However, computing checksums ain't the same thing as compressing an hour of video data so you can safely consider one of the low-power, moderateperformance single or dual core processors (e.g. a 2.4 GHz Celeron, also cheap at today's prices). Probably the most important consideration is that the processor be a 64-bit processor, since ZFS runs best under the 64-bit version of NAS4Free.

NAS4Free itself can run from the installation CD or a USB stick or, presumably, anything else you can write to (a big enough floppy disk?). It has even been optimzed to not write anything back to the source media, once it has installed itself into memory at boot up, to ensure the longevity of flash memory-based devices such as USB sticks.

Call us traditionalists, but we like to use a small hard disk or SSD for the NAS4Free system itself. This allows us to make changes to the system, add scripts to do various tasks such as backups, etc. A small hard disk or 64GB SSD is cheap and should be reliable enough to run your system for a long time. If the hard disk does crash or something goes wrong with the SSD, the system can be easily reconstructed from backups, since no critical data (except for configuration information) is held on it.

One or two further thoughs on the concept of a separate, small system disk. Installing NAS4Free on one of the disks that will be used for the ZFS pool or trying to use the system disk for data storage is too complicated and is not really recommended. Thus, a separate, possibly low-power, green hard disk or SSD for your system is a good idea. If you wish to preserve all of the SATA ports on an older motherboard (many have four) for the ZFS disks, you should use an IDE drive for the system disk, since most older motherboards still have a single IDE connection which can be employed for a single hard disk as well as a DVD ROM drive for installation, or possibly a DVD R/W drive for installation and backup.

Depending on how you wish to configure the ZFS disk pool, you will probably want to add two or more big disks for data storage. In a mirrored configuration a pair of 1TB or 2TB disks work well. In this configuration, a third disk might be added as a hot spare. If you are going to be using one of the mirrored + striping RAID configurations, you will probably have three or more large disks.

Large SATA drives such as 1TB and 2TB green drives are ideal for the ZFS pool. One disk manufacturer even has a special line of disks designed particularly for NAS use that are low power but which have TLER to allow effective error reporting to ZFS. ZFS knows how to handle advanced format disks which is the format used by many 1TB and 2TB drives. Unless you are going to be pounding the ZFS pool with I/Os, the green drives are more than zippy enough for backing up other systems, supplying realtime video feeds, etc. Their big pluses are that they are easy on the power supply and they run very cool. If you care, most are extremely quiet too. Just be sure that you buy drives that are all exactly the same or nearly the same size, since RAID configurations do not appreciate differently-sized disks.

We now come, in a roundabout way, to the motherboard that you procure to build your NAS4Free system. We could have all sorts of discussions about server-class boards, how many PCI slots and what kind are needed, etc., etc.

Suffice to say that, in a simple NAS4Free system, any motherboard that supports your choice of processor, as much memory as you want to install and that has built-in video should work. If you want to run a lot of disks in your ZFS pool, you might look for one that has a lot of SATA ports or one that will allow you to add one or more SATA controller cards with JBOD arrays.

Probably the most important feature is one or more built-in gigabit ethernet ports. These will allow you to connect the NAS4Free system to your network and handle large volumes of data into and out of it. Incidentally, built-in gigabit ethernet is definitely better than adding gigabit ethernet via a PCI bus adapter, since most built-in gigabit ethernet adapters funnel data directly into and out of the system through its main bus, rather than through the much slower PCI bus. And, fortunately, the later versions of FreeNAS (e.g. 0.7.2) or NAS4Free (e.g. 9.x) now support even the dreaded RTL8111C chipset which seems to be the favorite chipset of many motherboard manufacturers.

Installing NAS4Free

If, before or during the course your NAS4Free installation, you wish to consult the NAS4Free documentation, you can find it at:

     http://wiki.nas4free.org/doku.php?id=documentation:setup_and_user_guide

ZFS runs best on the 64-bit version of NAS4Free. On earlier versions of FreeNAS (e.g. 0.7.2) one would install the latest AMD64 release of FreeNAS because, despite the name AMD64, this version ran on 64-bit processors that were not from AMD. Now, the two versions are simply called x86 and x64 so the x64 version is the one to get. Out of the three x64 choices, the LiveCD or LiveUSB versions allow you to install NAS4Free on a hard drive, etc., so it is probably either of these two versions that you want. You can find the latest release at:

     http://sourceforge.net/projects/nas4free/files/

When you boot the installation CD or USB stick, the initial boot process has a couple of distinct parts:

     After the system goes through the POST and loads the OS from the boot
     device the NAS4Free boot menu will appear.  This menu is visible for a few
     seconds (long enough to allow you to choose one of the other boot options,
     if you are awake and on the ball).  At this step, you need do nothing.
     Just let the system take the default and boot normally.
     The system will continue booting as a NAS4Free server and, when it is
     complete, the system menu will appear.  It is at this point that you can
     commence your installation by choosing the install option.

The install menu gives you a number of choices about how you'd like to install NAS4Free. Basically, the two choices are "full" or "embedded". If you choose the "embedded" version, NAS4Free installs itself so that any changes that are made to the system are wiped out whenever the system is rebooted. This refreshing of the system means that it is protected against inadvertent updates, software failures, malicious hacks, etc. If anything goes wrong, you simply reboot the system.

On the other hand, if you'll be wanting to make any system changes (e.g. adding device drivers), storing programs or scripts on the system partition, etc., you should choose the "full" version.

Other than that, you need to decide whether you want to provide swap space for the system (we always add at a minimum the same amount as main memory, and up to a maximum of double the amount as main memory, in swap space, so that the system keeps limping along even when it runs out of main memory -- although you may prefer a kernel panic in this situation). Especially if your system disk is an SSD, adding swap space from such a device provides low cost, extra pages with only a minor impact in performance.

You also need to decide how much disk space you want to allow for the system (just by way of example, a typical NAS4Free installation on an 16GB hard disk partition uses about 270MB or about 2% of the partition). Thus, unless you are planning on installing a boat load of your own software on the system, we wouldn't recommend anything more than a 16GB partition.

Given these considerations (and given that you've chosen to install NAS4Free on a smallish hard disk or SSD), you should install either the "'full' OS on HDD + DATA + SWAP partiton" or the "'embedded' OS on HDD/Flash/USB + DATA + SWAP partition". As we said above, if you plan on modifying the OS, choose the "full" installation, otherwise choose the "embedded" installation.

After you've decided which installation type you'll do, you'll be asked to select the partition sizes. Since there's probably plenty of space on your system disk, you can allow a large partition for the OS. We like to use 8GB or 16GB. As we said above, we like to provide at least one or two times the amount of swap space as there is main memory. With 2GB of main memory, this implies 4GB of swap space, while with 8GB of main memory this implies 16GB of swap space (once again, there's probably pleny of disk space). The installaion process will take care of assigning the remaining disk space to the data partition. The UFS file system is fine for this partition.

Let the install rip. Make a note of the data and swap partition names when install tells you what they are (you'll need them later). Then reboot the system without the installation disk. The NAS4Free system console should come up.

The immediate goal is now to get the network up and running because all of the ensuing NAS4Free configuration is done from the Web UI.

If your system has multiple NICs, you may need to select the "Assign Interaces" menu item. Usually, the system will "do the right thing" but, if you have a preference for which NIC should be the main one, etc., you can check what it has done and, if necessary, move the NICs around.

What about if your network card isn't found at all? Other than the obvious, the card isn't plugged in correctly, this means that your network card is not supported by NAS4Free or more specifically, by the underlying FreeBSD.

You have two choices. You can replace the network card with one supported by FreeBSD. A quick check of the NAS4Free hardware compatibility list page will (hopefully) show your version of NAS4Free in the hardware support table, from which you can follow the link to the appropriate FreeBSD compatibility list page:

     http://wiki.nas4free.org/doku.php?id=nas4free_users_hardware

If you don't wish to replace the NIC, particularly if it is built-in to the motherboard, you can add a device driver if one is available (thankfully, the much-favored-by-motherboard-manufacturers 8111C chipset is now supported by the latest NAS4Free). Since it is likely that your NIC's driver will be found in NAS4Free, we won't dwell on this topic. But, if you do need to add a driver, Hani Ibrahim's blog may prove helpful:

     http://blog.hani-ibrahim.de/en/netzwerktreiber-auf-freenas-installieren.html

The default IPv4 address for NAS4Free is 192.168.1.250, which will be assigned to the first or only network adapter. If this works out for your network, you can just leave it unchanged. Note, however, that when we tried this option under NAS4Free 9.1.0.1.636, no DNS servers were filled in. Not that this is a problem, per se, but when the Web UI was brought up later on, an error message saying "No DNS setting found" appeared. At this point, it would seem that there is a bug in the Web UI because as long as the error message was present, the complete UI did not get produced by index.php and it was not possible to do anything from the UI since all of the menu dropdown items were missing.

This being the case, the next step is probably to select the "Set LAN IP Address" menu item. The dialog that follows will allow you select whether the system will use DHCP or be assigned a static IP address. If don't choose DHCP, you should supply the desired IP address and the subnet mask, the default gateway, and at least one DNS sever's address. In a local network, there's no real need for IPv6 so turn it off.

That's about it. You should now be able to get to the NAS4Free Web UI by aiming a Web browser, on another system, at the IP address that you assigned (or that was assigned). You will see the NAS4Free login screen. Logon using the default userid which is "admin". Its password is "nas4free". If you have problems logging in (e.g. the login screen just keeps getting replayed, reguardless of what you type), you should check that cookies are enabled for the IP address of the NAS4Free server. If you are using any kind of Web blocking or filtering software that disables or blocks cookies, you will not be able to log in.

Initial Setup

Initial setup consists of moving through all of the menu choices and tabs, and filling in the fields presented on each of the selected pages. The following paragraphs simply begin by showing the menu selections as a path, separated by slashes (e.g. "System/General/General" means choose the "System" menu item, followed by the "General" menu item, followed by the "General" tab). The choices that should be made are listed next. Notes are interspersed as full paragraphs or in parenthesis on the individual field lines. When you see the setup pages, you'll figure it out.

System/General/General (Setup)

     Hostname: (you probably want something different than "nas4free")
     Domain: (the default is "local")
     IPV4 DNS servers: (if you set the NIC up from the console, you only need
                       to add your second DNS server, if you need one)
     Time zone: (Eastern Time is GMT+4 or maybe GMT+5, in the winter)
     Enable NTP: checked (if you have a local or networked NTP server)
     NTP time server: (local or networked NTP server -- the default works OK)

System/General/Password

     Set new password (default password is "freenas")

System/Advanced/Advanced

     Console screensaver: checked (if you wish)
     Blank time: 300 seconds (5 minutes) seems about right.
     Enable Zeroconf/Bonjour to advertise services of this device: another bad
     idea whose time has come.  You may want to turn it off.
     MOTD: (may want to include the machine name in the welcome message)

System/Advanced/Email

     From email: temporarily start out by entering your to email address
     (that's intuitive)
     Outgoing mail server: your SMTP server (probably, an IP address is best)
     Once you've tested the connection to your SMTP server by clicking the
     "Send test email" button, you should then set the "From email" field to
     the address you want to use henceforth as the sender's address for
     delivering mail (e.g. "NAS4Free.NASBox"), so that all email messages will
     be sent with this from address.
     Note that, as of NAS4Free 9.1.0.1.636, clicking the "Send test email"
     button sends an inscrutable test message with a bogus UTF subject (hey,
     what's wrong with ANSI for the test message), the sender's address the
     same as the recipient's and a body that reads, "This email has been sent
     to validate your email configuration."  If you see an email that looks
     like this in your in-box, you're in business.

System/Advanced/Swap

     If you installed NAS4Free using one of the options that create a swap file,
     you must enable it first before it can be used by the system.  The install
     should have given you instructions about how to do it.  In case you didn't
     write them down, begin by checking the "Enable" box.
     Type: Device
     Device: /dev/ada2s3 (or whatever device name you were given by install)
     If you really didn't write down the swap device name when install told
     you what it was, you can go to the system console, open up a shell and
     enter the following command:
     ls -1 /dev/ada*
     Note that the flag, above, is a one, not the usual el.  You should see all
     of the hard drives listed.  The system drive will be the one that looks
     like this:
     /dev/ada2
     /dev/ada2s1
     /dev/ada2s1a
     /dev/ada2s2
     /dev/ada2s2a
     /dev/ada2s3
     The swap partition is the third partition listed (e.g. /dev/ada2s3 in
     this example).

Disks/Management/Management

     If you installed the system with one or more UFS DATA partitions on the
     system disk, you can enable it or them now.  Begin by clicking the "Plus"
     button at the right.
     Disk: ada2 (or other appropriate disk -- read the description of the disk
     until you see your system drive or SSD)
     Description: (you should provide a description -- we like to use something
     like "Data partition on System disk")
     S.M.A.R.T.: checked
     Preformatted file system: UFS
     Click the "Add" button at the bottom of the page.  The disk will show up
     as "Initializing".
     Click the "Apply changes" button to make the disk available.  The disk will
     show as "ONLINE".

Disks/Management/S.M.A.R.T.

     Begin by checking the "Enable" box.
     Power mode: Standby
     Informal: 50 (most disks run in the 35-45 degree range)
     Critical: 60 (now, we're cookin')
     Email Report: check Activate
     To email: (put your to email address here)
     Click "Apply Changes"
     If you want to run any additional SMART tests (we like to do the Long
     Self Test once a week at 5AM for each disk, picking a different day for
     each disk), click the "Plus" button at the right of the "Scheduled
     self-tests" section.
     Click "Save and Restart" when you are all done.

Disks/Mount Point/Management

     If you installed the system with one or more UFS DATA partitions on the
     system disk, you can mount it or them now.  Begin by clicking the "Plus"
     button at the right.
     Type: Disk
     Disk: ada2 (or other appropriate disk)
     Partition type: MBR partition
     Partition number: 2 (or other appropriate partition number)
     File system: UFS
     Mount point name: System (or some other descriptive name).  This name will
     appear under /mnt in the file system tree, e.g. /mnt/System.
     Description: (a description would be good -- we like "Data partition on
     System disk")
     File system check: checked
     If you really didn't write down the data device name when install told
     you what it was, see the notes in the System/Advanced/Swap section above
     about how to list the disk partitions.  The data partition is the second
     partition listed (e.g. /dev/ada2s2 in this example).
     Click the "Add" button at the bottom of the page.  The partition will show
     up as "Initializing".
     Click the "Apply changes" button to make the partition available.  The
     partition will show as "OK".  [You just never know where Martin Van Buren
     is going to turn up.]

ZFS Setup

Disks/Management/Management

     Begin setting up ZFS by adding all of the disks that will be included in
     the storage pool (here, we're assuming two).  Start by clicking the "Plus"
     button at the right.
     Disk: ada0 (or other appropriate disk)
     Description: ZFS Pool Disk 1 (you should provide a description)
     S.M.A.R.T.: checked
     Preformatted file system: Unformatted
     Click the "Add" button at the bottom of the page.  The disk will show up
     as "Initializing".  Continue clicking the "Plus" button and adding disks
     as needed.
     Disk: ada1 (or other appropriate disk)
     Description: ZFS Pool Disk 2 (you should provide a description)
     S.M.A.R.T.: checked
     Preformatted file system: Unformatted
     Again, click the "Add" button at the bottom of the page.
     Click the "Apply changes" button to make the disk or disks available.  The
     disk will show as "ONLINE".

Disks/Format

     Format each of the disks that were added in the previous section.
     Disk: ada0 (or other appropriate disk)
     File system: ZFS storage pool device
     Click the "Format disk" button to format the disk.
     Disk: ada1 (or other appropriate disk)
     File system: ZFS storage pool device
     Click the "Format disk" button to format the disk.

Disks/ZFS/Pools/Virtual device

     Each of the disks that were added and formatted must configured as part of
     a virtual device before they can be added to a ZFS pool.  Essentially,
     this step creates the equivalent of a RAID array that you can then assign
     to a ZFS pool.  Start by clicking the "Plus" button at the right.
     Name: RAID1 (use a descriptive name for the virtual device)
     Type: Mirror (or choose one of the other types like RAID 5)
     Devices: ada0
              ada1 (use the Ctrl+Click feature to pick multiple devices)
     Advanced Format: checked (especially if one or more drive is AF)
     Description: (a nice description of this virtual device)
     Click the "Add" button at the bottom of the page.  The virtual device will
     show up on the Virtual Device listing.
     Click the "Apply changes" button to make the virutal device available.

Disks/ZFS/Pools/Management

     Now, the virtual device can be added to the ZFS pool.  Do that by clicking
     the "Plus" button at the right.
     Name: Pool1 (use a descriptive name for the ZFS pool)
     Virtual devices: RAID1 (use the Ctrl+Click feature to pick multiple virtual
                      devices)
     Description: (a nice description of this pool)
     Click the "Add" button at the bottom of the page.  The pool will show up
     with no information available.
     Click the "Apply changes" button to build the storage pool.  The size and
     capacity information will become visible and the pool should show as
     "ONLINE".

Disks/ZFS/Datasets/Dataset

     Finally, a dataset can be created on the ZFS pool.  Do that by clicking
     the "Plus" button at the right.
     Name: Datastore1 (use a descriptive name for the dataset)
     Pool: Pool1 (select the ZFS pool name from the previous step)
     Compression: Off
     Canmount: checked
     Extended attributes: checked
     Description: (a nice description of this dataset)
     Click the "Add" button at the bottom of the page.
     Click the "Apply changes" button to assign the dataset to the storage pool.

Sharing With Windoze Systems

Services/CIFS SMB/Settings

     To share the volumes and datasets defined on the NAS4Free system with Windoze
     users, CIFS/SMB must be enabled.  Begin by checking the "Enable" box.
     Authentication: Anonymous
     Max Protocol: NT1
     NetBIOSname: (your system's name)
     Workgroup: WORKGROUP
     Description: (may want to add machine name to default description)
     Local Master Browser: No (you probably already have one on your network)
     Time server: No (same goes for this)
     Large read/write: checked
     Use sendfile: checked
     Null passwords: checked (if you so desire)
     Asynchronous I/O (AIO): checked
     Click "Save and Restart" to save the changes.
     Incidentally, here is a little note about setting the "Max Protocol" value.
     There is a bug in Samba (https://bugzilla.samba.org/show_bug.cgi?id=8726)
     having to do with the SMB2 protocol which causes random crashes when large
     files are transfered from/to NAS4Free using SMB/CIFS.  Until this bug is
     fixed and rolled into the NAS4Free build, it is probably a good idea to
     stick with "NT1" and not use "SMB2".  Admittedly, this will force CIFS/SMB
     to run slower (due to the chattiness of the original SMB protocol) but it
     will work.  After the bug is fixed, you should be able to turn SMB2 on and
     Samba will negotiate with its clients to use either SMB2 or NT1, depending
     on what they can hack.

Services/CIFS SMB/Shares

     Each volume or dataset that is to be shared must be configured by clicking
     the "Plus" button.
     Name: Datastore1 (use a descriptive name for the share)
     Comment: (a nice description of this share)
     Path: /mnt/Pool1/Datastore1 (select the path from the dialog box)
     Read only: unchecked
     Browseable: checked
     Guest: unchecked
     Recycle bin: unchecked
     Hide dot files: unchecked
     Shadow Copy: unchecked
     ZFS ACL: unchecked
     Click the "Add" button at the bottom of the page.
     Name: System (use a descriptive name for the share)
     Comment: (a nice description of this share)
     Path: /mnt/System (select the path from the dialog box)
     Read only: unchecked
     Browseable: checked
     Guest: unchecked
     Recycle bin: unchecked
     Hide dot files: unchecked
     Click the "Add" button at the bottom of the page.
     Click the "Apply changes" button to make the shares visible.

Enabling SSH

There's no need to use the console for tasks that can't be done through the Web UI. Instead, you can establish an SSH connection and then do all of your work through the login shell. To use SSH, the service must be enabled via the Web UI Services configuration page.

Services/SSH

     Begin by checking the "Enable" box.
     Permit root login: checked (unless you don't want to allow this)
     Click the "Save and Restart" button.

Once you've save the configuration changes, you should be able to login to NAS4Free using a terminal client that supports SSH. The userid is "root" (not "admin") and the password is whatever password you set for the "admin" user under the Web UI.

Adding Hostnames

If you wish to use local host names, that cannot to be found via DNS lookup, you can add those names to the /etc/hosts file through the NAS4Free Web UI.

Network/Hosts

     Click the "Plus" button to add a new host name.
     Hostname: (the name of the host)
     IP address: (the host's IP address)
     Click the "Add" button at the bottom of the page.
     Click the "Apply changes" button to make the host names usable.
     Click "Save and Restart" because you can never have too many buttons to
     click.

Setting Up an Rsync Server on Windoze

If you wish to automatically back up files from one or more Windoze systems, the way to do it is definitely via rsync. Rsync uses a sophisticated checksum algorithm to only copy the actually changed portions of the files it copies so it works perfectly for maintaining backup copies. Furthermore, it can be set up to delete previously-copied files that are deleted from the source directory so that the backup directory becomes a true mirror of the source directory that it backs up.

An rsync client on the NAS4Free system requests copies of files from an rsync server on the Windoze system that is to be backed up. This being the case, the rsync server must be installed on each Windoze box. The easiest way to do this is get the latest copy of DeltaCopy from:

     http://www.aboutmyip.com/AboutMyXApp/DeltaCopy.jsp

Download the "With Installer" version of DeltaCopy, unzip it and run the installer. Follow the instructions for each install step. You might want to change the install directory to "\Program Files\DeltaCopy" instead of the default directory (in the top-level of the directory tree).

Once you've installed DeltaCopy, you need to register the server as a service with Windoze. Registration will take place the first time you run the DeltaCopy server. It will cause Windoze to start up DeltaCopy when the system boots and ensure that the service stays up and running. Note that, when you register the service, you should check the log on as "Local System account" button and eschew supplying a username and password. This will allow the service to run as a system service (its a good thing).

Next, you should create aliases for all of the directories on each of the Windows systems that you want to back up. This is done by clicking on the "Virtual Directories" tab of the DeltaCopy Server Console. Under that tab, you can click on "<Add New Directory>" to add one or more directory aliases to be shared via rsync. Unfortunately, you can't include more than one directory under an rsync alias so you'll have to define as many aliases as the directories that you want to back up (making the top level directory an alias is not recommended). You should check the "Read only" box to ensure that rsync on the NAS4Free system does not monkey with any of the local files. You may want to delete the default "Backup" directory that appears automagically, when DeltaCopy is set up. It serves no purpose for us.

That's about it for Windoze. You can check that the rsync server is working, from the NAS4Free system, with this command:

     /usr/local/bin/rsync rsync://mysys

Where "mysys" is the name of the system that is running the DeltaCopy server. You should see a list of modules (share points).

Setting Up an Rsync Server on Linux

To set up an rsync server on Linux, you can either use the version of rsync that is supplied with your system and installed via the system's software installation interface. We prefer to get the latest version of the source from:

     http://samba.anu.edu.au/rsync/

Download then unpack the tar file:

     tar xzvf rsync-3.0.7.tar.gz

Change to the source directory, run configure and make the source:

     cd rsync-3.0.7
     ./configure
     make

Install rsync as root:

     su
     make install

Many installation guides suggest that the rsync server be run, on demand, by xinetd. This is OK for the occasionaly rsync file transfer but we think that running rsync as a daemon is a better idea. To do this, you'll need a start/stop script for init.d. Here is our script:

/etc/init.d/rsync:

     #!/bin/sh
     #
     # rsync - Script to start/stop the rsync daemon.
     #
     # Revision History:
     # ewilde      2011Mar26  Initial coding.
     #
     # chkconfig: 2345 18 92
     # description: Rsync remote file/directory synchronization daemon
     #
     # pidfile: /var/lock/subsys/rsyncd.pid
     #
     #
     # Define the install path for the rsync binary, etc.
     #
     INSTALL_PATH="/usr/local/bin"
     CONFIG_FILE="/etc/rsync/rsyncd.conf"
     PID_RSYNCDAEMON="/var/run/rsyncd.pid"
     #
     # Load the RedHat functions.
     #
     if [ -f /etc/redhat-release ]; then
         . /etc/rc.d/init.d/functions
     fi
     #
     # Check that rsync has been installed (sometimes not the case).
     #
     [ -f $INSTALL_PATH/rsync ] || exit 0
     #
     # Upon startup, we start rsync as a daemon.
     #
     start()
         {
         action "Starting rsync daemon: " \
             $INSTALL_PATH/rsync --daemon --config=$CONFIG_FILE
         return $?
         }
     #
     # Upon shutdown, we stop the rsync daemon.
     #
     stop()
         {
         echo -n "Stopping rsync daemon: "
         killproc -p $PID_RSYNCDAEMON  rsync >/dev/null 2>&1
         StopVal=$?
      if [ $StopVal = 0 ] ; then
          echo_success
      else
          echo_failure
      fi
      echo
      return $StopVal
      }

#
# See how we were called.
#
case "$1" in

      #
      # Start.
      #
      start)
          start
          RETVAL=$?
          ;;
      #
      # Stop.
      #
      stop)
          stop
          RETVAL=$?
          ;;
      #
      # Restart or reload (whatever).
      #
      restart|reload)
          stop
          start
          RETVAL=$?
          ;;
      #
      # Conditional restart.
      #
      condrestart)
          if [ -f $PID_RSYNCDAEMON ]; then
              stop
              start
              RETVAL=$?
          fi
          ;;
      #
      # Give the status of the rsync daemon.
      #
      status)
          if [ ! -f $PID_RSYNCDAEMON ]; then
              echo The rsync daemon is down
              exit 1
          fi
          echo The rsync daemon is running
          RETVAL=0
          ;;
      #
      # Help text.
      #
      *)
          echo $"Usage: $0 {start|stop|restart|condrestart|status}"
          exit 1

esac

     exit $RETVAL

After you install this script into /etc/init.d, you need to set its ownership and permissions:

     su
     chown root:root /etc/init.d/rsync
     chmod u=rwx,go=rx /etc/init.d/rsync

You will also need to add this script to the startup sequence, for example like this:

     su
     /sbin/chkconfig --add rsync
     /sbin/chkconfig rsync on

You can check that it did get added to the startup sequence like this:

     /sbin/chkconfig --list rsync

The next thing to do is create a configuration file that tells the rsync daemon how to run and which directories it should expose as modules (share points). We choose to create an rsync directory under /etc, to hold the config files:

     su
     mkdir /etc/rsync
     chown root:root /etc/rsync
     chmod u=rwx,go=rx /etc/rsync

This sample config file should give you an idea of what your config file can look like. You can add as many modules (share points) as you wish. The rsync docs describe how to assign permissions to them, etc. We have chosen not to set any permissions (not always a wise idea), but you may want to have your remote backup login before it can copy secure directories.

/etc/rsync/rsyncd.conf:

     #
     # Rsync daemon configuration file.
     #
     #
     # Global options.  These apply to all connections unless specificaly
     # overridden.
     #
     # Note that the pid file path should match the path set in the rsync daemon
     # startup script (/etc/init.d/rsync).
     #
     pid file = /var/run/rsyncd.pid
     lock file = /var/run/rsync.lock
     read only = yes
     list = yes
     uid = nobody
     gid = nobody
     #
     # Modules (share points).
     #
     [mail]
         path = /var/spool/mail
         uid = root
         gid = mail
     [mysql]
         path = /var/mysql
         uid = mysql
         gid = mysql
     [home-jsmith]
         path = /home/jsmith
         uid = jsmith
         gid = jsmith
     [home-jblow]
         path = /home/jblow
         uid = jblow
         gid = jblow

Note that, if you want to specifically exclude subdirectories from under a module, you can use the "exclude" directive, like this:

     [www]
         path = /var/www
         uid = apache
         gid = apache
         exclude = Bugzilla/ manual/

Also note that the action of the gid parameter may violate the principal of least astonishment in that it doesn't mean what you think it does. If you specify a groupname via the gid parameter, it is only that exact group which is used to obtain permission to access the files found under the module's path. To access files under several groups, you must specify them all in a list following the gid parameter.

If, instead, you wish to have rsync access the files in the module with all of the groups that the user, specified by the gid parameter, is a member of, you should specify the group as '*'. This would look like:

     [packages]
         path = /packages
         uid = jblow
         gid = *

You'll probably want to set the ownership and permissions for your new config file, like this:

     su
     chown root:root /etc/rsync/rsyncd.conf
     chmod u=rw,go=r /etc/rsync/rsyncd.conf

Now that you've completed your config file, you can start the rsync service (it should start automatically, the next time the system boots):

     su
     /etc/init.d/rsync start

From the local system, you can check that the rsync service is running by entering:

     /etc/init.d/rsync status

You can check that the rsync service is running properly, from the NAS4Free system, with this command:

     /usr/local/bin/rsync rsync://mysys

Where "mysys" is the name of the system that is running the rsync server. You should see a list of modules (share points).

If you should happen to get an error that says this:

     rsync: read error: Connection reset by peer (54)
     rsync error: error in rsync protocol data stream (12) ...

It is most likely due to a preexisting inetd or xinetd grabbing the packets being sent to port 873 (rsync). You can look in /var/log/messages on the remote system to see what's going on. If inetd or xinetd is involved, you need to get rid of the rsync configuration in /etc/inetd.conf, /etc/xinetd.conf or /etc/xinetd.d/* (probably rsync). If the rsync package was installed by an RPM, you should remove it with yum, the package manager, apt or whatever.

Also, you'll need to restart inetd or xinetd to get it to give up on the rsync port. But, be advised that xinetd in particular is quite persistent and you may have to cancel it by hand. Try (if you're running inetd, substitute its name instead):

     su
     /etc/init.d/xinetd restart

If this fails, try:

     ps x | grep xinetd
then
     kill -9 pidnum (where pidnum was returned by ps)
     /etc/init.d/xinetd restart

If you get an error that says:

     rsync: failed to connect to mysys: Connection refused (61)
     rsync error: error in socket IO (code 10) ...

It is due to a the rsync daemon not listening on port 873 (rsync). Try restarting (or starting) the daemon, especially if you've just fixed the inetd/xinetd problem described above:

     su
     /etc/init.d/rsync restart

Finally, we should say a few things about security. You'll note that we specified "uid = nobody" and "gid = nobody" in the global options and then overrode these options for each of the modules (share points). For example, the "mail" module uses "uid = root" and "gid = mail". These settings are necessary to allow rsync to have proper access to the subdirectories and files under the specified directories.

However, since we didn't specify any of the "auth users", "secrets file", "hosts allow" or "hosts deny" parameters, this essentially leaves these modules (share points) wide open to any rsync client on your system. You might want to consider at the very least a "hosts allow" parameter in the global options section of /etc/rsync/rsyncd.conf, to allow only the NAS4Free server access to the modules:

.

       .

uid = nobody
gid = nobody
hosts allow = 192.168.1.nnn

       .
       .
       .

Use the actual IP address of the NAS4Free server instead of 192.168.1.nnn.

Backing Up With Rsync

Before you try any backups from the NAS4Free system, you may wish to see what files and directories will actually be backed up from each system on your network. After you've installed DeltaCopy on Windoze, or rsyncd on your Linux boxes, you can use this command from the console on the NAS4Free system or a logged-in terminal to see what rsync modules are available for backup:

     /usr/local/bin/rsync rsync://mysys

For each of the modules listed, you can verify what files and directories will be backed up by passing the individual module names to rsync, one at a time, like this:

     /usr/local/bin/rsync --recursive --list-only rsync://mysys/modname

Once everything looks good, the following script can be used to back up files from Windoze or Linux remote systems using rsync. Copy it to your System share and then, using a copy command from the console or a logged-in terminal, move it to the OS volume, where nobody will monkey with it:

     su
     mkdir /etc/rsync
     cp /mnt/System/backup /etc/rsync
     chown root:wheel /etc/rsync/backup
     chmod u=rwx,go=rx /etc/rsync/backup

Here is the backup script. You should change the email variables, FromAddr and ToAddr, before you install the script. You may also wish to change the defalut ZFS pool, if you don't plan on setting it via the command line. And, the default backup file ownership and permissions should be set to something other than "root:wheel", etc., if you don't like those settings and don't wish to set them for each backed up directory, in the config file.

/etc/rsync/backup:

     #!/bin/bash
     #
     # Shell script to back up files from remote systems, using rsync, to the
     # ZFS pool on NAS4Free.
     #
     # This script should be run at regular intervals (typically hourly), by
     # cron, under the root userid.  It can be run whenever backups should be
     # done with the times set in the config file determining when the backups
     # are actually done.  The command line looks like this:
     #
     #      backup [-d|--debug] [-h|--help] [-n|--noemail] [-v|--verbose]
     #             configfile [zfspool]
     #
     # The parameters are:
     #
     #      -d|--debug             Set this debug flag to test the config file,
     #                             etc.  Doesn't actually run rsync.
     #
     #      -h|--help              Setting this flag displays help information.
     #
     #      -n|--noemail           If this flag is set, don't send an e-mail with
     #                             the results.  Normally, if the email variables
     #                             are set (below), email is sent to the specified
     #                             address, giving the results of the backup.
     #
     #      -v|--verbose           If this flag is present, output status
     #                             information to stdout, as the backup
     #                             progresses.
     #
     #      configfile             The configuration file that drives the backups
     #                             to be done (see below).
     #
     #      zfspool                Optional ZFS pool name, if you wish to
     #                             override the internal value (set below).
     #
     # The configuration file that is read by this backup script is used to
     # decide which Rsync modules (share points) on one or more remote systems
     # should be backed up.
     #
     # Note that the configuration file must not contain any of the evil,
     # MS-generated carriage returns.  If it does, this script will undoubtedly
     # function incorrectly.  This ain't f**king Windoze, Sparky.
     #
     # The config file contains one or more source systems, specified by the
     # "Source" keyword, followed by an equal sign and the system's name or IP
     # address.  If a machine name is given, it must be able to be resolved via
     # DNS or the hostname must be added to the /etc/hosts file via the
     # Network/Hosts tab on the NAS4Free Web page.
     #
     # After that, you may supply one or more destination directories (in the
     # ZFS pool) and one or more time strings.  These are specified by the "Dest"
     # and "Time" keywords respectively, followed by an equal sign and the
     # destination directory or time string.
     #
     # The destination directory is given as a relative subdirectory underneath
     # the ZFS pool that is either implied or specified on the command line.
     # If the directory doesn't exist in the ZFS pool, it will be created.
     #
     # The time string is given as one or more hours, separated by spaces, in a
     # simple list.  The hour numbers use the 24-hour clock.  If this backup
     # script is run at an hour that matches one of those in the list, the
     # backup will be done.  A time string of "" will match all backup times.
     #
     # The ownership and permissions of the backed up directories and files will
     # be set to the default values set within this script.  If you don't like
     # this arrangement (e.g. if you are trying to adhere to a more diverse
     # security scheme), you may set the permissions on an individual backup
     # directory basis using the BackupOwner, DirPerms and FilePerms parameters,
     # which must occur before the module list for the directory that they are to
     # apply to.
     #
     # The values for these parameters must comply with the rules for the chown
     # and chmod commands.  The ownership parameter will be applied to both the
     # directories and files that are backed up.  The DirPerms parameter will
     # give the permissions only for directories.  The FilePerms parameter will
     # give the permissions only for files.  Sample values might be: "root:wheel";
     # "u=rwx,go=rx" for directories; and "u=rw,go=r" for files.
     #
     # Following the keywords, lists of Rsync modules to be backed up to the
     # backup directory are given to direct the actual backups.  The list can
     # consist of the string "", in which case all of the Rsync modules found
     # on the remote system will be backed up.  If the list begins with a minus
     # sign, followed by a space, all of the Rsync modules found on the remote
     # system will be backed up, except for those modules listed.  Otherwise,
     # only those modules listed will be backed up.  The list of modules should
     # be separated by blanks.
     #
      Blank lines and lines that begin with "" can be liberally interspersed
     # throughout the config file.  Comments may not be applied to the parameter
      or list lines, even if they do start with "".  Note that the keywords
     # accumulate and the current value for all three is used whenever a backup
     # list is found.
     #
     # Here is a sample config file:
     #
     #      # Backup the Profiles directory on Audrey.
     #      Source = audrey
     #
     #      Dest = Backup_Audrey
     #      Time = 0
     #        Profiles
     #
     #      # Backup all of the directories on Gabriella.
     #      Source = gabriella
     #
     #      Dest = Backup_Gabby
     #      Time = 0
     #      BackupOwner = root:gabby
     #      DirPerms = ug=rwx,o=
     #      FilePerms = ug=rw,o=
     #        *
     #
     #      # Backup all of the directories on Video-Game (at diffent times).
     #      Source = video-game
     #
     #      Dest = Backup_Windoze
     #      Time = 2,10,14,18
     #        - Profiles
     #
     #      Dest = Backup_Video-Game
     #      Time = 0
     #        Profiles
     #
     # Note that this script creates a lock file for each destination directory
     # to prevent multiple backups from running at the same time.  If the system
     # crashes while the lock is held or you need to break the lock for any other
     # reason, simply delete the file "/var/run/rsync_client_running_backupdir",
     # replacing the string "backupdir" with the actual name of the top level
     # backup directory.
     #
     ############################################################################
     #
     # Default ZFS pool where all backup files are to be stored.  You can modify
     # this parameter to reflect your NAS4Free configuration, if you don't use the
     # zfspool positional on the command line.
     #
     DefZFSPool="/mnt/Pool1/Datastore1"
     #
     # File ownership.  Rsync has its own ideas about who should own what.  We
     # may have different ideas.
     #
     DefBackupOwner="root:wheel"
     DefDirPerms="u=rwx,go=rx"
     DefFilePerms="u=rw,go=r"
     #
     # Email variables.  Set these up, if you want to have the script email you
     # backup status.
     #
     FromAddr=NAS4Free.Alexandria@gntrains.com
     ToAddr=ewilde@gntrains.com
     #
     # Email commands.
     #
     Printf=/usr/bin/printf
     MailerSMTP=/usr/local/bin/msmtp
     MailerSMTPConf=/var/etc/msmtp.conf
     #
     # Arguments.
     #
     Debug=0
     WantMail=1
     Verbose=0
     #
     # Work areas.
     #
     Body=""
     Backups=0
     Errors=0
     LineNum=0
     DestDir=""
     SourceSys=""
     TimeStr=""
     ############################################################################
     #
     # Function to do an rsync backup from the source system to the destination
     # directory.
     #
     function BackupSource
         {
         #
         # Make sure that the user has indicated the source system whose files
         # are to be backed up.
         #
         if [ x"$SourceSys" = x ]; then
             if [ $Debug = 1 ]; then
                 echo "  No source host specified for backup"
             else
                 let Errors=Errors+1
                 LogMsg "No source host specified for backup at config file \
                         line $LineNum"
             fi
             return
         fi
         #
         # Make sure that the user has specified the destination
         # directory where backups are to be put.
         #
         if [ x"$DestDir" = x ]; then
             if [ $Debug = 1 ]; then
                 echo "  No destination specified for backup"
             else
                 let Errors=Errors+1
                 LogMsg "No destination specified for backup at config file \
                         line $LineNum"
             fi
             return
         fi
         #
         # If we aren't debugging the config file, we should check that the
         # time we were given is now, before we do any work.  Otherwise, there's
         # nothing to do.
         #
         if [ x"$TimeStr" != x ] && [ "$TimeStr" != "*" ] && [ $Debug != 1 ]; then
             #
             # See if the current hour is in the run time string.
             #
             CurrHour=$CurrentHour
          for RunTime in $TimeStr; do
              if [ $RunTime = $CurrHour ]; then
                  CurrHour=""
                  break
              fi
          done
          #
          # If the current hour wasn't found in the list, we're done.
          #
          if [ x"$CurrHour" != x ]; then
              return
          fi
      fi
      #
      # If the module list that we were given is one that requires the full
      # list of modules (share points) from the remote system, or one that
      # operates on the full list, let's get it from the remote system now.
      #
      if [ "$1" = "" ] || [ "$1" = "-" ]; then
          SourceModules=`/usr/local/bin/rsync rsync://${SourceSys}`
          #
          # If the list isn't the full list, but one that we modify, let's
          # do that now.
          #
          if [ "$1" = "-" ]; then
              shift 1
              IncludedModules=""
              #
              # Compare the list from the source against the exclude list.
              #
              for Module in $SourceModules; do
                  for Exclude in "$"; do
                      if [ "$Module" = "$Exclude" ]; then
                          Module=""
                          break
                      fi
                  done
                  #
                  # This particular module isn't excluded so add it to the
                  # list.
                  #
                  if [ x"$Module" != x ]; then
                      if [ x"$IncludedModules" = x ]; then
                          IncludedModules=$Module
                      else
                          IncludedModules="${IncludedModules} ${Module}"
                      fi
                  fi
              done
              SourceModules=$IncludedModules
          fi
      else
          SourceModules="$*"
      fi
      #
      # If we're debugging the config file, we now have the list of modules
      # to be backed up so we can dump that list and get out.
      #
      if [ $Debug = 1 ]; then
          echo "Backing up \"$SourceModules\""
          return
      fi
      let Backups=Backups+1
      #
      # If the destination directory doesn't exist, create it now.
      #
      if [ ! -d ${ZFSPool}/${DestDir} ]; then
          mkdir ${ZFSPool}/${DestDir}
          chown $BackupOwner ${ZFSPool}/${DestDir}
          chmod $DirPerms ${ZFSPool}/${DestDir}
      fi
      #
      # Log the beginning of our work.
      #
      LogMsg "Starting rsync backup from ${SourceSys} to ${DestDir}"
      #
      # Check if we're already backing up the selected modules.
      #
      if [ -r /var/run/rsync_client_running_${DestDir} ]; then
          LogMsg "  Previous backup still running, skipping this one"
          return
      fi
      #
      # Set the lock file.
      #
      /usr/bin/touch /var/run/rsync_client_running_${DestDir}
      #
      # Copy all of the modules on the remote system.
      #
      for Module in $SourceModules; do
          LogMsg "  Backing up module ${Module}"
          /usr/local/bin/rsync --log-file=/var/log/rsync_client.log \
              --recursive --times --compress --archive \
              --delete --delete-delay --quiet --perms \
              "rsync://${SourceSys}/${Module}" \
              "${ZFSPool}/${DestDir}/${Module}"
          RetCode=$?
          if [ $RetCode != 0 ]; then
              let Errors=Errors+1
              LogMsg "    Backup failed with return code: $RetCode"
          fi
          #
          # Set the ownership and permissions.
          #
          # We start by setting the file permissions on everything.  This is
          # pretty fast, since we use the "-R" option on chmod.  Then, we
          # come back and set the directory permissions using find, which is
          # also pretty fast, since it only works on the directories.  Note
          # that this works, even if the file permissions take away the
          # execute (i.e. list) permission of the directory because the
          # recursive find will add the execute permission back to the
          # directory before it dives into it.
          #
          chown -R $BackupOwner ${ZFSPool}/${DestDir}/
          chmod -R $FilePerms ${ZFSPool}/${DestDir}/
          find ${ZFSPool}/${DestDir} -type d -exec chmod $DirPerms \{\} \;
      done
      #
      # Clear the lock file.
      #
      /bin/rm -f /var/run/rsync_client_running_${DestDir}
      #
      # Log the end of our work.
      #
      LogMsg "Completed backup from ${SourceSys} to ${DestDir}"
      }
     ############################################################################
     #
     # Function to add a message to the email body and/or log it to stdout.
     #
     function LogMsg
         {
         #
         # Add the message to the email body.
         #
         if [ $WantMail = 1 ]; then
             Body="${Body}${1}\n"
         fi
         #
         # Output the message to stdout, if in verbose mode.
         #
         if [ $Verbose = 1 ]; then
             echo $1
         fi
         }
     ############################################################################
     #
     # Function to send an email status message, if the user has requested it.
     #
     function SendMail
         {
         if [ $WantMail = 1 ]; then
             #
             # Create a subject.
             #
             Subject="NAS4Free rsync backup - `date +"%Y %b %d %H:%M:%S"`"
          if [ $1 -gt 0 ]; then
              Subject="${Subject}: Error Detected"
          fi
          #
          # Send the message.
          #
          $Printf "From:$FromAddr\nTo:$ToAddr\nSubject:$Subject\n\n$Body" | \
                  $MailerSMTP --file=$MailerSMTPConf -t
      fi
      }
     ############################################################################
     #
     # Process all of the arguments (flags and positionals).
     #
     Args=("$*")
     for Arg in $Args; do
         case $Arg in
             #
             # Flags.
             #
             "-d" | "--debug")
                 Debug=1
                 ;;
             "-n" | "--noemail")
                 WantMail=0
                 ;;
             "-v" | "--verbose")
                 Verbose=1
                 ;;
             "-h" | "--help")
                 echo <<-ENDHELP
     usage: $0 [-d|--debug] [-h|--help] [-n|--noemail] [-v|--verbose]
         configfile [zfspool]
      -d|--debug      Debug the config file but don't run rsync.
      -h|--help       Display this help.
      -n|--noemail    Don't send an e-mail with the results.
      -v|--verbose    Output status information to stdout.
      configfile      Config file with backup tasks defined therein.
      zfspool         ZFS pool name, if iternal name is not acceptable.
  ENDHELP
              exit
              ;;
          #
          # Positionals.
          #
          *)
              if [ x"$ConfigFile" = x ]; then
                  ConfigFile=$Arg
              else
                  if [ x"$ZFSPool" = x ]; then
                      ZFSPool=$Arg
                  fi
              fi
              ;;
      esac

done
#
# If there are no email addresses, we'll turn off email. #
if [ x"$FromAddr" = x ] || [ x"$ToAddr" = x ]; then

      WantMail=0

fi
#
# Make sure that the user has indicated where the config file is. #
if [ x"$ConfigFile" = x ]; then

      Verbose=1
      LogMsg "No config file specified listing the backup tasks"
      SendMail 1
      exit 1

fi
#
# See if the user has specified the ZFS pool where backups are to be put. #
if [ x"$ZFSPool" = x ]; then

      ZFSPool=$DefZFSPool

fi
#
# Set the default ownership and permissions. #
BackupOwner=$DefBackupOwner
DirPerms=$DefDirPerms
FilePerms=$DefFilePerms
#
# Get the current hour. Used to compare against the time string parameter # in the config file.
#
CurrentHour=`date +%k`
#
# Read the config file and process all of the backups therein. #
while read Line; do

      #
      # Count lines for error reportage.
      #
      let LineNum=LineNum+1
      if [ $Debug = 1 ]; then
          echo Line $LineNum: $Line
      fi
      #
      # If the line is not a comment, process it.
      
      if [ "`echo $Line | grep '^[^]'`"x != x ]; then
          #
          # If the line is a parameter and its value, process it.  The
          # parameter will be turned into a shell variable.  Here's what we
          # are looking for:
          #
          #      BackupOwner    The ownership string to apply to the backed up
          #                     directories and files (e.g. root:wheel).
          #
          #      DestDir        The name of the top level directory in the
          #                     ZFS pool where the remote system's files are
          #                     to be backed up.
          #
          #      DirPerms       The directory permission string (e.g.
          #                     u=rwx,go=rx).  Only applies to backed up
          #                     directories.
          #
          #      FilePerms      The file permission string (e.g. u=rw,go=r).
          #                     Only applies to backed up files.
          #
          #      SourceSys      The source remote system whose files are to
          #                     be backed up.  This is given as either an IP
          #                     address or a machine name.
          #
          #      TimeStr        The time string, containing a list of all
          #                     times when the backup should be done.  Only
          #                     the hours are given, in 24-hour format, and
          #                     separated from one another by spaces.
          #
          # Note that you are supposed to be able to turn values read into
          # variables into actual shell variables like this:
          #
          #      eval ${ParmName}=`echo -ne \""$ParmVal"\"`
          #
          # This doesn't work on the NAS4Free version of bash.  Furthermore,
          # the shell variable name that is set depends on what name the
          # user uses in the config file.
          #
          # Instead, we look for what we want and set it.  This lets us
          # control what we get and give error feedback if it ain't what we
          # want.
          #
          if [ "`echo $Line | grep -E '^[^=]+=[^=]+$'`"x != x ]; then
              #
              # Pick up the parameter name and value.  Note that the two
              # values in the square brackets of the sed lines (below) are
              # <space> and <tab>.  You cannot use "\t", "\\t", "\\\\t",
              # "\\\\\\t" or any other combination of backslashes and the
              # letter "t" that you might think of.  Too baddie!  You need
              # to use a real, hard tab.
              #
              ParmName=`echo "$Line" | awk -F"=" '{print $1}' | sed "s/[ ]\$//"`
              ParmVal=`echo "$Line" | awk -F"=" '{print $2}' | sed "s/^[ ]//"`
              if [ $Debug = 1 ]; then
                  echo "  Parm $ParmName = \"$ParmVal\""
              fi
              #
              # Look for all of our variables.
              #
              case "$ParmName" in
                  #
                  # Backup owner.
                  #
                  backupowner|owner|BackUpOwner|Owner)
                      BackupOwner=$ParmVal
                      ;;
                  #
                  # Destination.
                  #
                  dest|destination|Dest|Destination)
                      DestDir=$ParmVal
                      ;;
                  #
                  # Directory permissions.
                  #
                  dirperms|DirPerms)
                      DirPerms=$ParmVal
                      ;;
                  #
                  # File permissions.
                  #
                  fileperms|FilePerms)
                      FilePerms=$ParmVal
                      ;;
                  #
                  # Source.  Note that this parameter resets all of the
                  # other parameters so that stuff left over from the
                  # previous source isn't used with this source.
                  #
                  source|Source)
                      SourceSys=$ParmVal
                      BackupOwner=$DefBackupOwner
                      DestDir=""
                      DirPerms=$DefDirPerms
                      FilePerms=$DefFilePerms
                      TimeStr=""
                      ;;
                  #
                  # Time string.
                  #
                  time|timestr|Time|Timestr|TimeStr)
                      TimeStr="$ParmVal"
                      ;;
                  #
                  # Unknown parameter.
                  #
                  )
                      if [ $Debug = 1 ]; then
                          echo "  Invalid parameter $ParmName"
                      else
                          let Errors=Errors+1
                          LogMsg "Invalid parameter $ParmName in config file \
                                  at line $LineNum"
                      fi
              esac
          #
          # Otherwise, the line is treated is a list, unless it is blank.
          #
          else
              if [ "`echo $Line | grep -c '^\\s$'`" = 0 ]; then
                  if [ $Debug = 1 ]; then
                      echo "  List = \"$Line\""
                  fi
                  #
                  # Looks like we're good to go.
                  #
                  if [ "$Line" = "" ]; then
                      BackupSource ""
                  else
                      BackupSource $Line
                  fi
              fi
          fi
      fi

done < $ConfigFile
#
# Give a report of the number of errors. #
if [ $Errors -gt 0 ]; then

      LogMsg "$Errors error(s) occurred during backup"

fi
#
# Send email, if required.
#
if [ $Errors -gt 0 ] || [ $Backups -gt 0 ] ; then

      SendMail $Errors

fi

Before you run this script, you'll need to create a config file to tell it which sources and modules (share points) are to be backed up and where the backups are to be stored. The script itself has quite a bit of documentation about how to do this so we'll just show a sample config file here. We put it in the System share and then, using a copy command from the console or a logged-in terminal, move it to the OS volume, where nobody will monkey with it:

     su
     cp /mnt/System/backup.cfg /etc/rsync
     chown root:wheel /etc/rsync/backup.cfg
     chmod u=rwx,go=rx /etc/rsync/backup.cfg

/etc/rsync/backup.cfg:

     # This configuration file is read by the NAS4Free backup script to decide
     # which Rsync modules (share points) on one or more remote systems should
     # be backed up.
     #
     # Note that this file must not contain any of the evil, MS-generated
     # carriage returns.  This ain't f**king Windoze, Sparky.
     # Backup all of the directories on Audrey.
     Source = audrey
     Dest = Backup_Audrey
     Time = 0
       *
     # Backup all of the directories on Video-Game.
     Source = video-game
     Dest = Backup_Windoze
     Time = 2 10 14 18
       - Profiles
     Dest = Backup_Video-Game
     Time = 0
       Profiles
     # Backup the global directories on the gateway server.
     Source = gateway
     Dest = Backup_Gateway
     Time = 0
       mail mysql
     # Backup user directories on the gateway server.
     Source = gateway
     Dest = Backup_HomeDirs
     Time = 2 10 14 18
       home-jsmith home-jblow

Before you do any actual damage, you can test your config file by running the script with the debug flag:

     /etc/rsync/backup -d /etc/rsync/backup.cfg

Once you're happy with how your config file is being handled, you can test the operation of the script like this:

     su
     /etc/rsync/backup -n -v /etc/rsync/backup.cfg

If any of the backups specified in the config file occur at the current time (i.e. the current hour), you should see the results of the backup on your terminal. If the time isn't correct, you can come back later or just modify the config file to use the current times. And, if you want to test that the backup job's status message is being delivered properly, you can test it like this:

     su
     /etc/rsync/backup /etc/rsync/backup.cfg

When you are happy with the script and the config file, you should add a cron table entry to run the backup script at hourly intervals (the config file will decide which backups actually run during each hour).

System/Advanced/Cron

     Begin by clicking the "Plus" button to add a new entry.
     Command: /etc/rsync/backup /etc/rsync/backup.cfg
     Who: root
     Description: Back up source_host on a regular basis.
     Schedule time: Minutes - 0, Hours - All, Days - All, Months - All,
                    Weekdays - All
     If you want to test the script, you can click the "Run now" button.  This
     is probably a good idea because the cron job may fail silently later on.
     Click the "Add" button to save the crontab entry and then click to "Apply
     Changes" button to actually save the crontab entry.

Securing Backed Up Files

>>>>>>
<<<<<<

Rotating Logfiles

There should be no need to rotate the usual system logfiles because these are set up by default to be self-limiting in size. However, the logfile that is created by the rsync backup script (above) can grow quite large. This being the case you might wish to install logrotate and set it up to rotate certain logfiles.

The FreeBSD pkg_add command can be used to add the logrotate package to the NAS4Free system. For pkg_add to simply work, you must have a connection to the Internet. If you have a connection set up, you can try:

     su
     pkg_add -v -r logrotate

If all goes according to plan, this will install logrotate and all of its prerequisites on your NAS4Free system.

Sometimes, the repository for your system's installed OS version will not be found. For example, the AMD64 repository for FreeBSD version 7.3 does not exist. In this case, you can try installing logrotate from the base repository but you will have to specify the repository file directly. For example:

     su
     pkg_add -v -r ftp://ftp.freebsd.org/pub/FreeBSD/ports/amd64/\
       packages-7-stable/sysutils/logrotate-3.7.9.tbz

You can figure out which repository file to use by surfing through the FreeBSD directory tree starting with:

     ftp://ftp.freebsd.org/pub/FreeBSD/ports

Depending on which version of NAS4Free you installed, you'll probably want to look in the i386 or amd64 subdirectories.

If you don't have a direct network connection, you can download the package files from the FreeBSD FTP site and install them with pkg_add once you've copied them to the FreeBSD system. However, you may need to download and install the prerequisites manually first. You can find out what they are with pkg_info like this:

     su
     pkg_info -r /local/pkgs/logrotate-3.7.9.tbz

By way of example, for the above version of logrotate, you can install its prerequisites like this:

     su
     pkg_add -v /local/pkgs/libiconv-1.13.1_1.tbz
     pkg_add -v /local/pkgs/gettext-0.18.1.1.tbz
     pkg_add -v /local/pkgs/popt-1.16.tbz

Once you've downloaded and installed all of the prerequisites the actual pkg_add command for logrotate will look something like this:

     su
     pkg_add -v /local/pkgs/logrotate-3.7.9.tbz

You can copy the logrotate.conf.sample file to create a logrotate config file that provides a set of default values:

     su
     cp /usr/local/etc/logrotate.conf.sample /etc/logrotate.conf

However, we prefer a logrotate.conf that looks like this:

/etc/logrotate.conf:

     # Rotate log files weekly.
     weekly
     # Keep 4 weeks worth of logfiles.
     rotate 4
     # Create new (empty) log files after rotating old ones.
     create
     # Uncomment this if you want your log files compressed.
     #compress
     # Individual packages can place log rotation files into this directory.
     include /etc/logrotate.d

We must now create the logrotate.d directory, where the individual package rotation files can be placed:

     su
     mkdir /etc/logrotate.d
     chown root:wheel /etc/logrotate.d

Next, we can add individual package rotation files in the logrotate.d directory for each of the packages whose logfiles we wish to rotate. For the rsync backup script above, for example, we might add:

/etc/logrotate.d/rsync-backup:

     /var/log/rsync_client.log {
         missingok
         notifempty
     }

You can check that logrotate is working and rotating files properly by forcing a rotation:

     su
     /usr/local/sbin/logrotate -f -v /etc/logrotate.conf

When you are happy that logrotate is working as you wish, you should add a cron table entry to run logrotate at daily intervals. This is done from the NAS4Free Web UI, which you may recall, is accessed by aiming a Web browser, on another system, at the IP address that you assigned (or that was assigned). You will see the NAS4Free login screen whereupon you should logon using the userid "admin".

System/Advanced/Cron

     Begin by clicking the "Plus" button to add a new entry.
     Command: /usr/local/sbin/logrotate /etc/logrotate.conf
     Who: root
     Description: Rotate logfiles on a daily basis.
     Schedule time: Minutes - 0, Hours - 4, Days - All, Months - All,
                    Weekdays - All
     If you want to test the script, you can click the "Run now" button.  This
     is probably a good idea because the cron job may fail silently later on.
     Click the "Add" button to save the crontab entry and then click to "Apply
     Changes" button to actually save the crontab entry.

Scrubbing

One of the benefits of using ZFS is the ability to scrub the data, that is regularly check it to see that its integrity is intact by comparing mirrored copies and checksums. If an error that is caused by bit-rot is found, the scrub can correct it before it becomes permanent.

For commercial-grade disk drives, monthly scrubbing is recommended. For consumer-grade disk drives, weekly scrubbing is recommended. Since scrubbing is an expensive operation (all data on the ZFS pools must be checked), one must consider how often to schedule the scrub. Personally, we prefer to do it once a week, regardless of the type of storage. Sometime in the wee hours on an off day is preferred.

The following script, taken from gimpe, with a couple of small corrections, will perform scrubs in the background. Copy it to your System share and then, using a copy command from the console or a logged-in terminal, move it to the OS volume, where nobody will monkey with it:

     su
     cp /mnt/System/scrub /etc/zfs
     chown root:wheel /etc/zfs/scrub
     chmod u=rwx,go=rx /etc/zfs/scrub

You can test it like this:

     su
     /etc/zfs/scrub -n -v

You should see the results of the scrub on your terminal. If you want to test that the status message is being delivered properly, you can test it like this:

     /etc/zfs/scrub

Here is the scrub script. You should change the email variables, FROM, TO, and possibly SUBJECT, before you install the script:

/etc/zfs/scrub:

     #!/bin/bash
     #VERSION: 0.2
     #AUTHOR: gimpe
     #EMAIL: gimpe [at] hype-o-thetic.com
     #WEBSITE: http://hype-o-thetic.com
     #DESCRIPTION: Created on FreeNAS 0.7RC1 (Sardaukar)
     # This script will start a scrub on each ZFS pool (one at a time) and
     # will send an e-mail or display the result when everyting is completed.
     #CHANGELOG
     # 0.2: 2009-08-27 Code clean up
     # 0.1: 2009-08-25 Make it work
     #SOURCES:
     # http://aspiringsysadmin.com/blog/2007/06/07/
     #        scrub-your-zfs-file-systems-regularly/
     # http://www.sun.com/bigadmin/scripts/sunScripts/zfs_completion.bash.txt
     # http://www.packetwatch.net/documents/guides/2009073001.php
     # e-mail variables
     FROM=from@devnull.com
     TO=to@devnull.com
     SUBJECT="Scrub of Pools on NAS4Free"
     BODY=""
     # arguments
     VERBOSE=0
     SENDEMAIL=1
     args=("$*")
     for arg in $args; do
         case $arg in
             "-v" | "--verbose")
                 VERBOSE=1
                 ;;
             "-n" | "--noemail")
                 SENDEMAIL=0
                 ;;
             "-a" | "--author")
                 echo "by gimpe at hype-o-thetic.com"
                 exit
                 ;;
             "-h" | "--help" | *)
                 echo "
     usage: $0 [-v --verbose|-n --noemail]
         -v --verbose    output display
         -n --noemail    don't send an e-mail with result
         -a --author     display author info (by gimpe at hype-o-thetic.com)
         -h --help       display this help
     "
                 exit
                 ;;
         esac
     done
     # work variables
     ERROR=0
     SEP=" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "
     RUNNING=1
     # commands & configuration
     ZPOOL=/sbin/zpool
     PRINTF=/usr/bin/printf
     MSMTP=/usr/local/bin/msmtp
     MSMTPCONF=/var/etc/msmtp.conf
     # print a message
     function _log {
         DATE="`date +"%Y-%m-%d %H:%M:%S"`"
         # add message to e-mail body
         BODY="${BODY}$DATE: $1\n"
      # output to console if verbose mode
      if [ $VERBOSE = 1 ]; then
          echo "$DATE: $1"
      fi

}

     # find all pools
     pools=$($ZPOOL list -H -o name)
     # for each pool
     for pool in $pools; do
         # start scrub for $pool
         _log "starting scrub on $pool"
         zpool scrub $pool
         RUNNING=1
         # wait until scrub for $pool has finished running
         while [ $RUNNING = 1 ];     do
             # still running?
             if $ZPOOL status -v $pool | grep -q "scrub in progress"; then
                 sleep 60
             # not running
             else
                 # finished with this pool, exit
                 _log "scrub ended on $pool"
                 _log "`$ZPOOL status -v $pool`"
                 _log "$SEP"
                 RUNNING=0
                 # check for errors
                 if ! $ZPOOL status -v $pool | grep -q "No known data errors"; then
                     _log "data errors detected on $pool"
                     ERROR=1
                 fi
             fi
         done
     done
     # change e-mail subject if there was error
     if [ $ERROR = 1 ]; then
         SUBJECT="${SUBJECT}: Error(s) Detected"
     fi
     # send e-mail
     if [ $SENDEMAIL = 1 ]; then
         $PRINTF "From:$FROM\nTo:$TO\nSubject:$SUBJECT\n\n$BODY" | \
                 $MSMTP --file=$MSMTPCONF -t
     fi

Add a cron table entry to run the scrub script at regular intervals by adding an entry on the Cron page.

System/Advanced/Cron

     Begin by clicking the "Plus" button to add a new entry.
     Command: /etc/zfs/scrub
     Who: root
     Description: Scrub the ZFS pools on a regular basis.
     Schedule time: Minutes - 0, Hours - 1, Days - All, Months - All,
                    Weekdays - Sunday
     If you want to test the script, you can click the "Run now" button.  This
     is probably a good idea because the cron job may fail silently later on.
     Click the "Add" button to save the crontab entry and then click to "Apply
     Changes" button to actually save the crontab entry.