FreeBSD for Small Business: Server Setup Guide
A single FreeBSD server can replace Windows Server for most small business needs -- file sharing, email, web hosting, backups, VPN, and print services. The licensing cost is zero. The hardware requirements are modest. The reliability is exceptional.
This guide builds a complete small business server from scratch. Every service is configured with production-ready settings, not toy examples.
Why FreeBSD for Small Business
The practical arguments:
- No licensing cost. Windows Server 2025 Standard starts at $1,069. Add CALs at $44 per user. FreeBSD is free.
- Lower hardware requirements. FreeBSD runs file and print services comfortably on 4 GB of RAM. Windows Server wants 16 GB minimum for comparable workloads.
- ZFS. Built-in enterprise filesystem with snapshots, compression, and checksumming. No RAID controller needed.
- Security. Smaller attack surface. Less malware targeting. Jails for service isolation.
- Longevity. FreeBSD servers routinely run for 5-10 years with only security updates. No forced feature upgrades.
Hardware Recommendations
For an office of 5-25 users:
- CPU: Any modern 4-core (Intel i3/Xeon E or AMD Ryzen)
- RAM: 8-16 GB (more if running ZFS with large datasets)
- Storage: 2x SSD for OS (ZFS mirror), 2-4x HDD for data (ZFS mirror or RAIDZ)
- Network: Gigabit Ethernet (two ports if you want failover)
- UPS: Required. ZFS survives power loss gracefully, but a UPS prevents it entirely.
Total hardware cost: $500-1,500 depending on storage capacity.
Base Installation
Install FreeBSD 14 with ZFS as the root filesystem. During the installer:
- Select ZFS as the partitioning scheme
- Choose mirror (stripe of mirrors) for the boot pool
- Set a strong root password
- Create an admin user in the
wheelgroup - Enable
sshd
After first boot, update everything:
shfreebsd-update fetch install pkg update && pkg upgrade -y
File Server: Samba for Windows Clients
Most small businesses have Windows desktops. Samba provides seamless file sharing.
Install Samba
shpkg install samba419
Configure Samba
shcat > /usr/local/etc/smb4.conf << 'EOF' [global] workgroup = OFFICE server string = FreeBSD File Server security = user map to guest = Bad User dns proxy = no log file = /var/log/samba4/log.%m max log size = 1000 server role = standalone server passdb backend = tdbsam # Performance socket options = TCP_NODELAY IPTOS_LOWDELAY read raw = yes write raw = yes use sendfile = yes aio read size = 16384 aio write size = 16384 [shared] path = /data/shared browseable = yes writable = yes valid users = @staff create mask = 0664 directory mask = 0775 force group = staff [finance] path = /data/finance browseable = yes writable = yes valid users = @finance create mask = 0660 directory mask = 0770 force group = finance [public] path = /data/public browseable = yes writable = yes guest ok = yes create mask = 0666 directory mask = 0777 EOF
Create ZFS Datasets for Shares
shzfs create zroot/data zfs create zroot/data/shared zfs create zroot/data/finance zfs create zroot/data/public zfs set compression=lz4 zroot/data
Create Groups and Users
shpw groupadd staff pw groupadd finance pw useradd -n jsmith -G staff -m -s /bin/sh pw useradd -n mjones -G staff,finance -m -s /bin/sh smbpasswd -a jsmith smbpasswd -a mjones
Set Permissions
shchown root:staff /data/shared chmod 2775 /data/shared chown root:finance /data/finance chmod 2770 /data/finance chmod 777 /data/public
Start Samba
shsysrc samba_server_enable="YES" service samba_server start
Windows clients can now access \\server-ip\shared from File Explorer.
ZFS Snapshots for File Recovery
Schedule automatic snapshots so users can recover deleted files:
shpkg install zfs-periodic
Add to /etc/periodic.conf:
shcat >> /etc/periodic.conf << 'EOF' daily_zfs_snapshot_enable="YES" daily_zfs_snapshot_keep="30" daily_zfs_snapshot_fs="zroot/data zroot/data/shared zroot/data/finance" weekly_zfs_snapshot_enable="YES" weekly_zfs_snapshot_keep="12" EOF
Expose snapshots through Samba by adding to the [global] section:
shcat >> /usr/local/etc/smb4.conf << 'EOF' vfs objects = shadow_copy2 shadow:snapdir = .zfs/snapshot shadow:sort = desc shadow:format = auto-%Y-%m-%d EOF
Windows users can now right-click files, select "Previous Versions," and restore from ZFS snapshots.
Web Server: Nginx with PHP
For hosting an internal wiki, CRM, or company website:
shpkg install nginx php84 php84-extensions php84-mysqli php84-gd php84-curl php84-mbstring php84-xml
Configure Nginx
shcat > /usr/local/etc/nginx/nginx.conf << 'EOF' worker_processes auto; events { worker_connections 256; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name intranet.office.local; root /data/www; index index.php index.html; location ~ \.php$ { fastcgi_pass unix:/var/run/php-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } } EOF
Configure PHP-FPM
shcp /usr/local/etc/php-fpm.d/www.conf.default /usr/local/etc/php-fpm.d/www.conf
Edit /usr/local/etc/php-fpm.d/www.conf to use a socket:
shsed -i '' 's|listen = 127.0.0.1:9000|listen = /var/run/php-fpm.sock|' /usr/local/etc/php-fpm.d/www.conf sed -i '' 's|;listen.owner = www|listen.owner = www|' /usr/local/etc/php-fpm.d/www.conf sed -i '' 's|;listen.group = www|listen.group = www|' /usr/local/etc/php-fpm.d/www.conf
Create Web Root
shzfs create zroot/data/www chown -R www:www /data/www
Start Services
shsysrc nginx_enable="YES" sysrc php_fpm_enable="YES" service nginx start service php-fpm start
Email Server: Postfix and Dovecot
For a small office that wants to self-host email (with the understanding that deliverability requires proper DNS records):
shpkg install postfix dovecot
Configure Postfix
shcat > /usr/local/etc/postfix/main.cf << 'EOF' myhostname = mail.yourdomain.com mydomain = yourdomain.com myorigin = $mydomain inet_interfaces = all mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain home_mailbox = Maildir/ smtpd_tls_cert_file = /usr/local/etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem smtpd_tls_key_file = /usr/local/etc/letsencrypt/live/mail.yourdomain.com/privkey.pem smtpd_use_tls = yes smtpd_tls_security_level = may smtp_tls_security_level = may smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination EOF
Configure Dovecot
shcat > /usr/local/etc/dovecot/dovecot.conf << 'EOF' protocols = imap listen = * mail_location = maildir:~/Maildir ssl = required ssl_cert = </usr/local/etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem ssl_key = </usr/local/etc/letsencrypt/live/mail.yourdomain.com/privkey.pem service auth { unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix } } passdb { driver = pam } userdb { driver = passwd } EOF
TLS Certificates with Let's Encrypt
shpkg install py311-certbot certbot certonly --standalone -d mail.yourdomain.com
Start Email Services
shsysrc postfix_enable="YES" sysrc dovecot_enable="YES" service postfix start service dovecot start
Configure DNS records (MX, SPF, DKIM, DMARC) with your domain registrar. Without these, your email will land in spam.
Backup Server
Local Backups with ZFS
ZFS snapshots are your first line of defense. For full offsite backup, send snapshots to a remote server:
sh# Initial full send zfs snapshot zroot/data@backup-$(date +%Y%m%d) zfs send zroot/data@backup-$(date +%Y%m%d) | ssh backup-server zfs recv tank/backup/office
Create a daily backup script at /usr/local/bin/backup.sh:
shcat > /usr/local/bin/backup.sh << 'BEOF' #!/bin/sh TODAY=$(date +%Y%m%d) YESTERDAY=$(date -v-1d +%Y%m%d) zfs snapshot -r zroot/data@backup-${TODAY} zfs send -i zroot/data@backup-${YESTERDAY} zroot/data@backup-${TODAY} | \ ssh backup-server zfs recv -F tank/backup/office # Keep 30 days of local snapshots zfs list -t snapshot -o name -H | grep "zroot/data@backup-" | head -n -30 | xargs -n1 zfs destroy BEOF chmod +x /usr/local/bin/backup.sh
Schedule it:
shecho '0 2 * * * root /usr/local/bin/backup.sh' >> /etc/crontab
Client Backups with Restic
For backing up Windows workstations to the FreeBSD server:
shpkg install restic zfs create zroot/data/backups
Install Restic on Windows clients and point them to the FreeBSD server via SFTP.
VPN Server: WireGuard
Give remote workers secure access to the office network:
shpkg install wireguard-tools
Generate Keys
shwg genkey | tee /usr/local/etc/wireguard/server_private.key | wg pubkey > /usr/local/etc/wireguard/server_public.key chmod 600 /usr/local/etc/wireguard/server_private.key
Configure WireGuard
shcat > /usr/local/etc/wireguard/wg0.conf << 'EOF' [Interface] PrivateKey = SERVER_PRIVATE_KEY_HERE ListenPort = 51820 Address = 10.0.100.1/24 [Peer] # Remote worker 1 PublicKey = CLIENT_PUBLIC_KEY_HERE AllowedIPs = 10.0.100.2/32 EOF
Enable IP Forwarding and NAT
shsysrc gateway_enable="YES" sysctl net.inet.ip.forwarding=1 cat >> /etc/pf.conf << 'EOF' nat on em0 from 10.0.100.0/24 to any -> (em0) pass in on wg0 all EOF sysrc pf_enable="YES" service pf restart
Start WireGuard
shsysrc wireguard_interfaces="wg0" sysrc wireguard_enable="YES" service wireguard start
Print Server: CUPS
Share printers across the office without Windows print server:
shpkg install cups cups-filters gutenprint avahi
Configure CUPS for Network Sharing
shsysrc cupsd_enable="YES" sysrc avahi_daemon_enable="YES" service cupsd start service avahi-daemon start
Edit /usr/local/etc/cups/cupsd.conf to allow network access:
shsed -i '' 's/Listen localhost:631/Listen 0.0.0.0:631/' /usr/local/etc/cups/cupsd.conf
Add network access rules. In the block:
shAllow from 192.168.1.0/24
Restart CUPS:
shservice cupsd restart
Access the web interface at http://server-ip:631 to add printers. Windows clients discover shared printers via DNS-SD (Bonjour), or connect manually via http://server-ip:631/printers/printer-name.
Cost Comparison: FreeBSD vs Windows Server
For a 15-user office:
| Item | Windows Server | FreeBSD |
|------|---------------|---------|
| OS License | $1,069 | $0 |
| 15 User CALs | $660 | $0 |
| Antivirus (yearly) | $300 | $0 |
| Remote Desktop CALs | $1,875 | N/A |
| Email (Exchange CALs) | $525 | $0 |
| Total Year 1 | $4,429 | $0 |
| Total 5 Years | $5,929+ | $0 |
The FreeBSD server costs only hardware and your time to set it up. After initial configuration, maintenance is minimal -- apply security updates monthly and monitor disk health.
Firewall Configuration
Protect the server with PF:
shcat > /etc/pf.conf << 'EOF' ext_if = "em0" vpn_if = "wg0" office_net = "192.168.1.0/24" vpn_net = "10.0.100.0/24" set skip on lo0 # NAT for VPN clients nat on $ext_if from $vpn_net to any -> ($ext_if) # Default deny block in all pass out all keep state # Allow from office network pass in on $ext_if from $office_net to any keep state # Allow specific services from anywhere pass in on $ext_if proto tcp to port { 22, 25, 80, 443, 993 } keep state pass in on $ext_if proto udp to port 51820 keep state # Allow all VPN traffic pass in on $vpn_if all keep state EOF sysrc pf_enable="YES" service pf start
FAQ
Q: Can Windows clients use FreeBSD file shares without any extra software?
A: Yes. Samba implements the SMB protocol natively. Windows sees the FreeBSD server as another Windows file server. No client software needed.
Q: Is self-hosted email worth the trouble?
A: For most small businesses, no. Use a hosted provider like Fastmail or Microsoft 365 for email. Self-hosting email requires ongoing maintenance, proper DNS, and deliverability monitoring. It is included here for completeness.
Q: How do I manage the server remotely?
A: SSH from any device. For a web-based management interface, install Webmin (pkg install webmin). For monitoring, set up Netdata (pkg install netdata).
Q: What happens when a disk fails?
A: If you use ZFS mirrors, the server continues operating on the surviving disk. Replace the failed disk and resilver. ZFS makes this straightforward: zpool replace zroot old-disk new-disk.
Q: Can I run Active Directory on FreeBSD?
A: Samba 4 can act as an Active Directory Domain Controller. However, for a small office (under 25 users), local Samba users are simpler and sufficient. AD adds complexity without proportional benefit at that scale.
Q: How much maintenance does a FreeBSD server need?
A: Monthly: run freebsd-update fetch install and pkg upgrade. Quarterly: check disk health with zpool status. Yearly: review logs and storage capacity. Total time: 1-2 hours per month.
Q: Can I virtualize this on existing hardware?
A: Yes. FreeBSD runs well under VMware ESXi, Proxmox (KVM), or Hyper-V. This is a good option if you already have a server and want to run FreeBSD alongside other VMs.
Q: What about compliance (HIPAA, PCI)?
A: FreeBSD can meet compliance requirements with proper hardening, encryption, access controls, and audit logging. The specifics depend on your compliance framework. Consult a compliance specialist for your industry.