macOS — Firewall Setup
Rabtly uses pf (packet filter) via pfctl to enforce port-level access control rules on macOS. Rules are loaded into a named anchor (cloud.rabtly) that only filters traffic on the WireGuard interface — your regular network traffic is never touched.
Requirements
- macOS 13 (Ventura) or later is recommended
- Works on macOS 10.7+ (pf has shipped since Lion)
pfctlis always present — no installation needed
Check if pf is enabled
sudo pfctl -s info 2>/dev/null | grep StatusExpected output: Status: Enabled
If it shows Status: Disabled, enable it:
sudo pfctl -eCheck if the Rabtly anchor is wired
The daemon auto-wires the anchor into /etc/pf.conf on first run. Verify:
grep 'anchor.*cloud.rabtly' /etc/pf.confIf you see anchor "cloud.rabtly", you’re good.
Manual setup (if auto-wire failed)
In rare cases (read-only filesystem, unusual permissions), the auto-wire fails. Fix it manually:
1. Add the anchor to /etc/pf.conf:
sudo sh -c 'echo "anchor \"cloud.rabtly\"" >> /etc/pf.conf'2. Reload the main ruleset:
sudo pfctl -e -f /etc/pf.conf3. Restart the daemon:
sudo launchctl kickstart -k system/cloud.rabtly.daemonVerify
# Check daemon status
rabtly status
# Should show firewall_enforced=true
# Inspect active rules in the anchor
sudo pfctl -a cloud.rabtly -srYou should see output like:
pass out quick on utun4 all keep state
pass in quick on utun4 inet from 100.64.0.2/32 to any keep state # rabtly: rule#0 all
pass in quick on utun4 inet proto tcp from 100.64.1.1/32 to any port 5432 keep state # rabtly: rule#1 tcp
block drop in quick on utun4 allTroubleshooting
”pf is disabled; rules will load but not filter”
pf is turned off system-wide. Enable it:
sudo pfctl -eTo make it persist across reboots, ensure /etc/pf.conf exists (macOS loads it at boot via com.apple.pfctl launchd job).
“could not auto-wire pf anchor into /etc/pf.conf”
The daemon couldn’t edit /etc/pf.conf. Common causes:
- SIP (System Integrity Protection) does NOT protect
/etc/pf.conf— it’s a regular root-owned file. - Read-only boot volume on macOS Big Sur+ —
/etcis on the signed system volume but/etc/pf.confis symlinked to the writable data volume. If this symlink is broken, fix it:
# Check the symlink
ls -la /etc/pf.conf
# If it's pointing nowhere, recreate it
sudo ln -sf /private/etc/pf.conf /etc/pf.confRules loaded but traffic isn’t filtered
This happens when the anchor isn’t wired into the main ruleset:
# Verify the anchor reference exists
grep 'cloud.rabtly' /etc/pf.conf
# If missing, add it and reload
sudo sh -c 'echo "anchor \"cloud.rabtly\"" >> /etc/pf.conf'
sudo pfctl -f /etc/pf.confLegacy “com.rabtly” anchor
Early builds used the anchor name com.rabtly. The daemon automatically migrates to cloud.rabtly and removes the old reference. If you see both in /etc/pf.conf, remove the old one:
sudo sed -i '' '/anchor.*com\.rabtly/d' /etc/pf.conf
sudo pfctl -f /etc/pf.confConflict with Little Snitch / Lulu / other pf-based firewalls
Rabtly uses a named anchor which is completely isolated from the main ruleset and from other anchors. It does not conflict with:
- Little Snitch (uses its own Network Extension, not pf)
- Lulu (uses its own anchor)
- Murus/Vallum (use their own anchors)
These applications coexist safely because each operates in its own namespace.
”pfctl: Use of -f option, could not obtain token”
Another process holds the pfctl lock. Wait a moment and retry — this usually resolves within seconds. If persistent, check for stuck pf-management tools:
ps aux | grep pfctlHow Rabtly uses pf
- Anchor:
cloud.rabtly(isolated from the main ruleset) - All rules are
quick: First-match-wins semantics, so macOS’s built-in rules can’t override our anchor’s verdict - Stateful outbound:
pass out quick on <iface> all keep state— replies to connections you initiate always flow back - Per-rule inbound passes: Each ACL rule becomes a
pass in quickwithkeep state - Default deny:
block drop in quick on <iface> allat the end catches anything not explicitly allowed - Syntax: OpenBSD 4.7 (macOS’s frozen pf version) — no 4.8+ features like
matchorset skip - Atomicity: Loaded via
pfctl -a cloud.rabtly -f -(all-or-nothing within the anchor)
Interface names
On macOS, WireGuard typically uses utun3, utun4, utun5, etc. The exact number depends on how many tunnel interfaces are active. Rabtly scopes all rules to the interface it creates, so other utun interfaces (VPN clients, iCloud Private Relay) are unaffected.