Skip to content
FreeBSDHow-To July 11, 2026 4 min read

How to Set Up FreeBSD as a NAS with ZFS and Samba

Building a real network-attached storage box on FreeBSD: pool layout decisions, dataset structure, and getting Samba to serve it with correct permissions to Windows and Mac clients.

FreeBSD plus ZFS plus Samba is a genuinely solid, entirely DIY NAS stack — no appliance abstraction layer between you and the actual filesystem and file-sharing daemon, which means more visibility into what’s actually happening, at the cost of more decisions you have to make yourself instead of accepting an appliance vendor’s defaults.

Pool layout: deciding redundancy up front

The single decision that’s hardest to change later is the pool’s redundancy layout, so get this right before loading it with data. For a typical home/small-office NAS with 4 drives, a mirrored pair of mirrors (effectively RAID 10) trades capacity for simplicity and strong random I/O performance, while raidz1/raidz2 trades some of that performance for more usable capacity:

zpool create tank mirror da0 da1 mirror da2 da3

or, favoring capacity over the mirror layout’s performance characteristics:

zpool create tank raidz2 da0 da1 da2 da3

raidz2 tolerates any two drive failures without data loss, which is a meaningfully safer margin than a single mirrored pair (which only tolerates the loss of one specific drive per mirror without risking that mirror). For a NAS holding data you actually care about, raidz2 over 4+ drives is a reasonable default unless a specific performance requirement argues otherwise.

Dataset structure, not one giant filesystem

Resist the temptation to just dump everything into the pool’s root dataset. Separate datasets per logical share let you set different properties — quotas, compression, snapshot policy — independently per use case:

zfs create tank/media
zfs create tank/backups
zfs create tank/documents
zfs set compression=lz4 tank/media
zfs set compression=zstd tank/documents
zfs set quota=2T tank/backups

lz4 is a good default for media (already-compressed video/audio gains little from further compression, and lz4’s near-zero CPU cost means there’s essentially no downside to leaving it on everywhere as a baseline). zstd is worth the extra CPU cost specifically for datasets holding genuinely compressible data like documents and source code, where it meaningfully outperforms lz4’s compression ratio.

Installing and configuring Samba

pkg install samba419

(the exact package name/version suffix changes as Samba releases progress — pkg search samba shows what’s currently available). The core configuration lives in /usr/local/etc/smb4.conf:

[global]
    workgroup = WORKGROUP
    server string = FreeBSD NAS
    security = user
    map to guest = never

[media]
    path = /tank/media
    valid users = @mediausers
    read only = no
    create mask = 0664
    directory mask = 0775

[backups]
    path = /tank/backups
    valid users = @backupusers
    read only = no
    create mask = 0660
    directory mask = 0770

security = user requires authenticated Samba users rather than allowing guest access — for a NAS holding anything beyond truly public files, this is the correct default, and map to guest = never closes off Samba’s fallback-to-guest behavior explicitly rather than leaving it implicit.

Getting Unix and Samba permissions to actually agree

The most common real-world NAS problem isn’t Samba configuration syntax — it’s the interaction between Unix filesystem permissions and Samba’s own ACL/mask handling producing files that one client can read but another can’t, or that the wrong users can write to. Create dedicated Unix groups matching your Samba share’s valid users groups, and make sure directories have the setgid bit set so new files inherit the group correctly rather than defaulting to each creating user’s primary group:

pw groupadd mediausers
pw usermod alice -G mediausers
chown -R root:mediausers /tank/media
chmod -R 2775 /tank/media

The 2 in 2775 sets the setgid bit — every new file or directory created under /tank/media inherits the mediausers group automatically, rather than inheriting whichever user created it, which is what actually makes multi-user shared directories behave sanely without needing to manually fix group ownership after every file is added.

Adding Samba users

Samba maintains its own password database, separate from the underlying Unix account passwords (this separation is intentional — it lets you have accounts that can authenticate to Samba without having a usable Unix login shell at all):

pw useradd alice -m -s /usr/sbin/nologin
smbpasswd -a alice

-s /usr/sbin/nologin gives the underlying Unix account no shell access, which is correct for accounts that exist purely to own files and authenticate to Samba — there’s no reason a NAS user needs an actual Unix shell login unless you specifically want them to have one.

Starting the service and confirming it persists across reboots

sysrc samba_server_enable="YES"
service samba_server start

sysrc writes the enable line into /etc/rc.conf correctly (rather than hand-editing the file, which risks a typo breaking the rc.d parsing for every other service in the file), and service samba_server start brings it up immediately without requiring a reboot to test.

Verifying from a client before calling it done

Connect from an actual Windows or macOS client (\\<nas-ip>\media on Windows, smb://<nas-ip>/media via Finder’s Connect to Server on macOS) and confirm both read and write access work as the specific user account you configured, not just that the share is visible. A share that mounts and lists files but silently fails on write due to a permissions mismatch is a common, easy-to-miss failure mode that only shows up when a client actually tries to save something — testing “does it mount” alone isn’t sufficient verification that the NAS is actually usable for its intended purpose.