Fix macOS pf port forwarding lost after reboot/sleep#98
Merged
Conversation
PF rules (80→8080, 443→8443) were wiped on reboot and sleep/wake, breaking .test domains until manual intervention. Root causes: - LaunchDaemon used an inline one-liner that swallowed all errors (2>/dev/null + exit 0), making failures invisible - launchctl load (deprecated) could fail silently on modern macOS - magebox start never verified pf state, so there was no safety net Fix: - Replace inline plist command with dedicated helper script (/usr/local/bin/magebox-pf-restore) that logs to /var/log/magebox-portforward.log for diagnosability - Use launchctl bootstrap/bootout with legacy load/unload fallback - Add EnsureRulesActive() called on every magebox start (macOS only) — verifies rules, restores if missing, reports to user - Add Port Forwarding section to magebox check for diagnostics - Bump LaunchDaemon version to force upgrade on existing installs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When PHP is installed via `brew install php` (the default/current formula), it lives in Cellar/php/8.4.x/ — not Cellar/php@8.4/. Both PHPBinary/PHPFPMBinary in Go and find_php_binary in the wrapper script now check the unversioned Cellar path as a fallback, matching the version prefix (e.g. 8.4.*) to avoid false positives. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Script log() now writes to stdout (captured by launchd) instead of double-writing to the log file via >>. Fixes missing log messages. - pfctl stderr merged to stdout (2>&1) so all output goes to one stream. - magebox restart now calls ensurePortForwarding() like start does. - Bump daemon version to 6 to deploy fixed script on next bootstrap. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
macOS pf rules were fundamentally unreliable — Apple's own pf management would override custom anchors after reboot and sleep/wake, silently breaking all .test domains. New approach: a persistent TCP proxy daemon (magebox _portforward) that listens on 80/443 and forwards to nginx on 8080/8443. Managed by launchd with KeepAlive:true — survives reboot, sleep/wake, and process crashes automatically. - Add internal/portforward/proxy.go: lightweight TCP forwarder - Add cmd/magebox/portforward_daemon.go: hidden _portforward command - Rewrite pf.go: LaunchDaemon now runs magebox _portforward instead of manipulating kernel pf rules - Clean up legacy pf files on upgrade (anchor, helper script, pf.conf) - Update bootstrap message and CHANGELOG Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.testdomains/usr/local/bin/magebox-pf-restore) with proper logging to/var/log/magebox-portforward.logmagebox startnow auto-restores pf rules if they're missing (self-healing safety net)magebox checknow reports Port Forwarding status on macOSWhat changed
internal/portforward/pf.goEnsureRulesActive()method, helper script instead of inline one-liner,launchctl bootstrap/bootoutwith legacy fallback, exportedAreRulesActive(), bumped daemon version to force upgradecmd/magebox/start.goensurePortForwarding()on macOS before project startupcmd/magebox/check.goVERSIONCHANGELOG.mdWhy the old approach broke
The LaunchDaemon plist used an inline shell one-liner with
2>/dev/nulleverywhere andexit 0at the end, making all failures invisible. Additionally,launchctl load -w(deprecated) could fail silently on modern macOS. Sincemagebox startnever checked pf state, there was no recovery path.Test plan
magebox bootstrapon macOS — should install helper script and upgraded LaunchDaemon/usr/local/bin/magebox-pf-restoreexists and is executablesudo launchctl list com.magebox.portforwardshows the daemon loadedmagebox startafter reboot without bootstrap → should auto-restore pf rulesmagebox check→ should show Port Forwarding section with LaunchDaemon and PF Rules status/var/log/magebox-portforward.logfor restore activity after rebootgo test ./...— all tests pass🤖 Generated with Claude Code