The Handbook

    Theme
    • Guides
        • Check a system before installing FreeBSD
        • Orient a Linux administrator on FreeBSD
        • Supported FreeBSD releases
        • Choose a FreeBSD documentation and support channel
        • Move files safely without GNU mv -t
        • Update, upgrade, or update packages?
        • Upgrade 14.4 or 15.0 to FreeBSD 15.1
        • Choose packages, ports, or poudriere
        • Choose the quarterly or latest package branch
        • Choose a FreeBSD download or package mirror
        • Make a system setting persistent
        • Configure locale, keyboard, and time zone
        • Configure a serial console for recovery
        • Choose a custom kernel, module, or loader setting
        • Run a Linux binary with the compatibility layer
        • Check desktop and laptop hardware before installation
        • Choose and check a graphics driver
        • Choose Xorg or Wayland
        • Build a maintainable desktop baseline
        • Install and check a desktop browser
        • Check laptop Wi-Fi, power, and suspend
        • Check multimedia readiness
        • Choose and configure a printing stack
        • Run Windows applications with Wine
        • Snapshot and replicate a ZFS dataset
        • Choose a filesystem and storage layout
        • Operate ZFS without losing the recovery path
        • Restore files from a ZFS snapshot
        • Read ZFS pool health and run a scrub
        • Replace a failed device in a ZFS mirror
        • Replicate a ZFS dataset over SSH
        • Change PF safely on a remote host
        • Configure a narrow WireGuard tunnel
        • Plan a FreeBSD home server
        • Choose a mail server or an outgoing relay
        • Publish a network service safely
        • Choose a jail network model
        • Choose native jails or a jail manager
        • Choose a jail or a bhyve virtual machine
        • Establish a FreeBSD security baseline
        • Choose a MAC policy
        • Audit security-relevant activity
        • Start a DTrace performance investigation
    • Integrations
        • Create a first jail with Bastille
        • Compare jail managers and OCI tooling
        • Publish a Bastille service through PF
        • Mount a ZFS dataset in a Bastille jail
        • Update and upgrade Bastille jails
        • Back up and restore a Bastille jail
        • Prepare bhyve and vm-bhyve
        • Choose NFS or Samba for file sharing
        • Choose ZFS backup automation
        • Operate a signed poudriere repository
        • Manage FreeBSD configuration with Ansible or Salt
        • Run Motion with webcamd on FreeBSD
        • Design a reverse proxy, certificates, and monitoring
    • FAQ
      • Troubleshooting
          • Recover an interrupted freebsd-update run
          • Resolve a package repository or ABI mismatch
          • Diagnose the FreeBSD boot path
          • Recover with a ZFS boot environment
          • Diagnose DNS, routing, and firewall paths
          • Diagnose network mbuf exhaustion
          • Bind a service to a low port without running it as root
          • Diagnose audio output or input
          • Diagnose webcamd, cuse, and a webcam
          • Fix USB device permissions without opening every device
      • About this handbook
      • Synopsis
      • Define ownership and recovery first
      • Create the host dataset
      • Add the persistent Bastille mount
      • Move existing data deliberately
      • Back up both boundaries
      • Primary references

      Mount a ZFS dataset in a Bastille jail

      Last reviewed
      13 August 2026
      Applies to
      15.1-RELEASE, 15.0-RELEASE, 14.4-RELEASE

      Synopsis #

      Application data does not need to live inside a jail’s root filesystem. A dedicated host-managed ZFS dataset gives the data its own snapshot, quota, replication, and retention policy while Bastille adds a persistent nullfs mount into the jail.

      This procedure does not delegate ZFS administration to the jail. The host retains control, which is the simpler boundary for most application jails. Delegated datasets require additional jail permissions and a separate threat review.

      Define ownership and recovery first #

      This example uses jail web, host dataset tank/jaildata/web, host mount point /srv/jaildata/web, and jail path /srv/data. Confirm that none of these names already serve another workload:

      $ zfs list tank/jaildata/web
      $ ls -ld /srv/jaildata/web
      # bastille list jail
      

      Record the numeric UID and GID used by the service inside the jail. A nullfs mount preserves numeric ownership; matching account names do not repair different numeric identifiers.

      Create the host dataset #

      Create a parent and child dataset with an explicit mount point:

      # zfs create -o mountpoint=/srv/jaildata tank/jaildata
      # zfs create -o mountpoint=/srv/jaildata/web tank/jaildata/web
      $ zfs get mountpoint,mounted,readonly tank/jaildata/web
      

      If the parent already exists, create only the child. Apply quotas or reservations only from measured capacity requirements. Compression may be set according to the host’s existing storage policy; it is not required for the mount.

      Set ownership using the service’s numeric identity, then verify it:

      # chown 80:80 /srv/jaildata/web
      $ ls -ldn /srv/jaildata/web
      

      The value 80:80 is only an example. Substitute the actual UID and GID obtained from the jail.

      Add the persistent Bastille mount #

      Stop the application before moving existing data. Add a read-write nullfs mount:

      # bastille mount web /srv/jaildata/web /srv/data nullfs rw 0 0
      # bastille cmd web mount
      # bastille cmd web ls -ldn /srv/data
      

      For configuration or reference data that the jail must not modify, use ro instead of rw. Do not mount host secrets, /etc, device trees, or broad parent directories merely for convenience.

      Inspect the jail-specific fstab after the command:

      # less /usr/local/bastille/jails/web/fstab
      

      The exact Bastille prefix can be changed in bastille.conf; use the configured prefix rather than assuming the default on a customized installation.

      Move existing data deliberately #

      When the jail already contains application data, stop the service and jail, copy the data into the dataset while preserving ownership and metadata, then mount and verify before restarting. Keep the original copy until the application has been checked and an independent backup exists.

      Do not copy into an actively mounted empty dataset over the original path and assume the hidden files were transferred. Work from an alternate path or a stopped jail so that source and destination are unambiguous.

      Back up both boundaries #

      A Bastille export covers the managed jail root. A separately mounted dataset is an independent storage object and must have its own backup policy. Use Snapshot and replicate a ZFS dataset for tank/jaildata/web, and use Back up and restore a Bastille jail for the jail configuration and root.

      Coordinate snapshots with the application. A filesystem-consistent snapshot of a running database may still require database-specific recovery or quiescing.

      Primary references #

      • Bastille mount command
      • FreeBSD Handbook: Jails and ZFS
      • FreeBSD Handbook: ZFS
      • mount_nullfs(8)
      • fstab(5)

      Independent documentation. Not affiliated with or endorsed by the FreeBSD Project or the FreeBSD Foundation.

      Report a bug
      • Synopsis
      • Define ownership and recovery first
      • Create the host dataset
      • Add the persistent Bastille mount
      • Move existing data deliberately
      • Back up both boundaries
      • Primary references