OpenZFS has a really cool feature that allows you to send datasets to other datasets, locally or on remote systems.

Today, I needed to send a dataset to another system but the destination was inside a FreeBSD jail. Granted, the jail was running on ZFS but I needed the destination for the recv to be an additional dataset.

TLDR
Full ZFS commands:

zfs create -o jailed=on -o mountpoint=/usr/jails/<jailname>/sftp_storage/ tank/sftp_data
zfs allow -u <backup_user> mountpoint,create,mount,receive tank/sftp_data

Full ezjail config:

export jail_<jailname>_zfs_datasets="tank/sftp_data"
export jail_<jailname>_parameters="enforce_statfs=1 allow.mount=1 allow.mount.zfs=1 allow.mount.procfs=1 allow.mount.devfs=1"

Send command:

zfs send tank/jails@now | pv | ssh <backup_user>@<sftp.fqdn> zfs recv -F tank/sftp_data/jail_1

Facts:

  • ZFS is running on the host.
  • ZFS dataset was created for the jail (via ezjail).
  • I'm using ezjail to manage the jails.
  • <backup_user> has to be created in both the jail and the host with the same UID.

I ran into a few road blocks but here's what needed to happen (assume a jail is already up and running):

  1. From the host, create a dataset for the jail:
zfs create -o jailed=on -o mountpoint=/usr/jails/<jailname>/sftp_storage/ tank/sftp_data
  1. Modify the ezjail config to allow the jail access to the dataset:
export jail_<jailname>_zfs_datasets="tank/sftp_data"
  1. Modify the ezjail config to allow the jail modify/mount to the dataset:
export jail_<jailname>_parameters="enforce_statfs=1 allow.mount=1 allow.mount.zfs=1 allow.mount.procfs=1 allow.mount.devfs=1"

So, it turns out, all the guides I found online saying I had to modify the host's sysctl were just outdated. On FreeBSD 11, you only need to modify the jail's config. I'm not entirely sure how far back this goes but it might work on some earlier versions as well.