This is my personal guide on how to set up a NAS with FreeBSD 13 and ZFS on Pine64's RockPro64.
Installation
Download a FreeBSD 13 image for rockpro64 board (under aarch64 section)
Write an image to a micro SD card (BSD install)
A white LED should indicate that OS has successfully started.
- If white LED is off this indicates that OS could not boot. Your best option is to debug boot process with serial connection.
- HDMI output should also be available nowadays. If you screen's resolution is 4K or larger than FreeBSD won't boot.
You can connect to your device with SSH since FreeBSD starts a SSH server by default. Users:
- root - root
- freebsd - freebsd
Upon first boot FreeBSD should resize root partition to fill all space on micro SD card.
freebsd@nas:~ % df -h Filesystem Size Used Avail Capacity Mounted on /dev/ufs/rootfs 58G 3.2G 50G 6% / #...
- If this doesn't happen you might need to check your boot log with
dmesg.
- If this doesn't happen you might need to check your boot log with
Enable and start ZFS:
service zfs enable && service zfs startDisable SSH for root:
- Add/uncomment
PermitRootLogin noline in/etc/ssh/sshd_config service sshd restart
- Add/uncomment
Install
pkgpkg help(will prompt to install)- If pkg could not be installed then change url in
/etc/pkg/FreeBSD.conf(Docs)
Edit hostname in
/etc/rc.confEnable and start
ntpdservice to sync time- Add
ntpd_sync_on_start=YESto/etc/rc.conf
- Add
Users
- Create new user and add to wheel group with
adduser - Remove freebsd user
rmuser freebsd - Change root password
passwd
ZFS pool
Find disks with
geom disk listGeom name: ada0 Providers: 1. Name: ada0 Mediasize: 4000787030016 (3.6T) Sectorsize: 512 Stripesize: 4096 Stripeoffset: 0 Mode: r1w1e2 descr: ST4000VN008-2DR166 lunid: 5000c500c6ff3710 ident: ZM41AR5R rotationrate: 5980 fwsectors: 63 fwheads: 16If your disks have been used before you might want to delete partitions
gpart delete -i 2 ada0. If partition table is invalid you might try to recover it withgpart recover ada0.Find ashift value to use:
# For this disk we need ashift of 12 (2^12=4096). Default ashift value is 9 (2^9=512). $ diskinfo -v ada0 | grep stripesize 4096 # stripesize
Create a mirror pool
zpool create -o ashift=12 -m /mnt/nas nas mirror /dev/diskid/DISK-ZM41AS6T /dev/diskid/...- This will mount the nas pool under
/mnt/nas - Note that we create a pool using disk IDs. This is to prevent disks from being mixed up in case you change how they are connected.
- This will mount the nas pool under
Enable compression on a pool
zfs set compression=zstd nasCreate a dataset
zfs create nas/romanzfs set quota=900G nas/roman(Allow dataset to use only 900G)zfs set snapdir=visible nas/roman(Show hidden.zfs/snapshostsdir)
Tune ZFS config (optional)
- Use
/boot/loader.confto configure ZFS (Available options) - E.g
vfs.zfs.arc_max="2G"
- Use
Regular snapshotting
Snapshots will be available under .zfs directory for each dataset.
Manual snapshot:
- Create
zfs snapshot -r nas/roman@2021-01-22(This creates a recursive snapshot ofromanand all descendant datasets) - Delete
zfs destroy nas/roman@2021-01-22
- Create
Install zfstools
pkg install zfstoolsEdit
/etc/crontab15,30,45 * * * * root /usr/local/sbin/zfs-auto-snapshot frequent 4 0 * * * * root /usr/local/sbin/zfs-auto-snapshot hourly 24 7 0 * * * root /usr/local/sbin/zfs-auto-snapshot daily 7 14 0 * * 7 root /usr/local/sbin/zfs-auto-snapshot weekly 4 28 0 1 * * root /usr/local/sbin/zfs-auto-snapshot monthly 12
Ideally, you would use periodic instead.
Enable regular snapshotting for all datasets:
zfs set com.sun:auto-snapshot=true nasList all snapshots and used space:
zfs list -rt allRollback to snapshot:
zfs rollback nas/roman@2021-01-22
I went with running everything from monit.
check program zfs-auto-snapshot-frequent with path "/usr/local/sbin/zfs-auto-snapshot frequent 4"
if status != 0 then alert
every "15,30,45 * * * *"
group cronScrubbing
Once in a while you want ZFS to go through your disks and verify that data blocks are not corrupted.
Edit
/etc/crontab# Scrub ZFS pool once a month 27 0 1 * * root zpool scrub nas
Useful commands
| Description | Command |
|---|---|
| List pools and datasets | zfs list |
| Show pools/pool status | zpool status [nas] |
| List all snapshots | zfs list -rt all |
| Replace a disk | zpool replace nas ada1 ada2 |
| Export a pool to be used on another device | zpool export nas |
| List pools available for import | zpool import |
| Import a pool | zpool import -o altroot=/mnt nas (will mount under /mnt/nas) |
| List pools that could use latest ZFS features | zpool upgrade |
| Upgrade a pool | zpool upgrade nas |
| View pool history | zpool history [nas] |
| Remove a pool or a dataset | zfs destroy nas/roman |
| Rename a dataset | zfs rename nas/roman nas/bond |
| List dataset properties | zfs get all nas/roman |
| Compare with a snapshot | zfs diff nas/roman@2021-01-22 (Lists which files have been changed/added/removed) |
Share ZFS pool with Samba
Install samba
pkg install samba413Add config to
/usr/local/etc/smb4.conf[global] workgroup = HOMENAS [roman] comment = PublicRoman path = /mnt/nas/roman public = no writeable = yes write list = @public directory mask = 0770 create mask = 0770service samba_server enable && service samba_server startAdd group
pw groupadd publicAdd user to group
pw groupmod public -M freebsdSet SMB password for user
smbpasswd -a freebsdChown the ZFS dataset so that user has access to it
On Windows:
- Right click in File Explorer and select "Add a network location"
- Custom location:
\\192.168.1.123\roman - Use freebsd user and SMB password configured above
Monitoring and email alerting
I decided to go with monit for monitoring and alerting.
pkg install monit- Copy sample configuration
cp /usr/local/etc/monitrc.sample /usr/local/etc/monitrc service monit enable && service monit start- Check that config is correct
monit -t - Reload config
monit reload - View summary in the terminal
monit summary - View summary in the browser http://localhost:2812 (default credentials admin/monit)
Sample script to check for CPU temperature:
#!/usr/bin/env sh
set -e
# Check CPU temperature (located: /etc/monit/scripts/cpu-temp.sh)
TEMP=`sysctl -n hw.temperature.CPU`
echo $TEMP
VALUE=`echo $TEMP | cut -c1-2`
exit $VALUEThen you can set up an alert in monit that will check for the exit code. It will alert if temperature is higher than 60 degrees. Notice that we also print to the stdout so that monit could show that value in the web UI.
# CPU temperature
check program CPU-temp with path "/etc/monit/scripts/cpu-temp.sh"
if status > 60 then alert
if status < 10 then alert
group temperature

If you use monit to run cron tasks then set
set daemon 35 # check services at 35 seconds intervalsso that cron tasks could run once at a specific minute.
Temperatures
- Board temperature
sysctl hw.temperatureorsysctl -a | grep temp - HDD temperatures:
pkg install smartmontools- Verify is supported
smartctl -i /dev/ada0(Should haveSMART support is: Enabled) smartctl -A /dev/ada0 | grep -i temperature
ZeroTier
Access your NAS from anywhere without exposing it to the public internet.
- Install
pkg install zerotier - Enable and start
zerotierservice - Connect
zerotier-cli join [network-id] - Accept this device in the web interface