How are you doing it now?
WireGuard, wg-quick
, and Route Monitoring: GhostBSD vs. Linux
Since you're running GhostBSD (a FreeBSD-based system focused on desktop usability), the behavior of WireGuard and wg-quick
follows FreeBSD’s implementation rather than Linux’s. This explains why you're not seeing the same issue with orphaned route -n monitor
processes on GhostBSD, as you noted in your original question:
"This doesn’t happen on FreeBSD. Just checked."
Why does WireGuard launch route -n monitor
after bringing up the interface?
On GhostBSD (and FreeBSD), wg-quick
launches a route monitoring process, specifically route monitor
(without -n
, which is Linux-specific), to watch for routing table changes. This function is part of the monitor_daemon
in the FreeBSD version of the wg-quick
script (wireguard-tools/src/wg-quick/freebsd.bash
).
Its purpose is the same as on Linux: to dynamically adjust routes (e.g., handling endpoint exceptions) when network conditions change. For example, if you're routing all traffic through the VPN (AllowedIPs = 0.0.0.0/0
), the monitor ensures packets to the VPN endpoint itself don’t get trapped inside the tunnel.
However, on GhostBSD, this monitoring is less intrusive and cleans up more effectively than on Linux.
Why doesn’t GhostBSD leave the monitor process running after stopping the interface?
On GhostBSD, when you run wg-quick down
, the route monitor
process doesn’t linger like it does on Linux. This happens because:
- FreeBSD’s
wg-quick
script handles cleanup more effectively.
- The process exits naturally when the associated interface disappears.
- The script’s teardown logic (e.g., via trap handlers or interface state checks) ensures termination.
Even though wg-quick
doesn’t explicitly kill the monitor process, FreeBSD’s networking model ensures it doesn’t persist as an orphan. This matches your observation: no leftover processes on GhostBSD after stopping the interface.
Why does Linux start a new instance each time, but GhostBSD does not?
On Linux, every time you run wg-quick up
, it spawns a new route -n monitor
process without tracking the previous instance, there's no PID file or state management. This leads to orphaned processes.
On GhostBSD, this doesn’t happen because:
- The FreeBSD
wg-quick
script either avoids spawning duplicates (likely by checking interface state) or
- The previous
route monitor
process exits automatically when the interface goes down.
This cleaner behavior is due to FreeBSD’s better process management and tighter networking integration.
Why is There a Difference Between Linux and GhostBSD?
Differences in wg-quick
Script Implementation
- Linux (
wg-quick
in linux.bash
)
- Uses
route -n monitor
with netlink to track routing changes.
- Launches it in the background without tracking its PID.
- Assumes it will eventually exit on its own—but it doesn’t, leading to orphaned processes.
- FreeBSD (
wg-quick
in freebsd.bash
)
- Uses
route monitor
, but its lifecycle is tied to the interface.
- Either exits cleanly when the interface goes down or is properly handled by the script.
System Philosophy
- Linux’s networking stack (via
iproute2
) is more modular and dynamic, so wg-quick
relies on constant monitoring, but lacks cleanup.
- FreeBSD’s networking stack is more unified, where interface state changes naturally signal dependent processes to exit, reducing the need for explicit cleanup.
Minimalism vs. Practicality
WireGuard’s minimalist design means no PID files or complex process tracking.
This limitation is more visible on Linux, where route -n monitor
persists unnecessarily.
Correct Behavior on GhostBSD
Since you're using GhostBSD and not seeing the issue, your setup is working as intended.
✅ wg-quick up
starts the monitor.
✅ wg-quick down
cleans up automatically.
✅ No orphaned processes remain.
No action is needed on GhostBSD—this is expected behavior.
Handling the Linux Case (If Relevant)
If you're also managing a Linux system and need to fix the orphaned route -n monitor
processes, here are practical solutions:
Add a PostDown
Hook in WireGuard Config
Edit your WireGuard config (/etc/wireguard/wg0.conf
) on Linux:
[Interface]
# ... other settings ...
PostDown = pkill -f "route -n monitor"
This forcefully kills all route -n monitor
processes when stopping the interface.
🔹 Best for simple setups with one WireGuard interface.
Use a Wrapper Script (More Precise)
Instead of modifying the config, use a wrapper script:
#!/bin/bash
INTERFACE="wg0"
PID_FILE="/tmp/wg-quick-$INTERFACE-monitor.pid"
case "$1" in
up)
wg-quick up "$INTERFACE"
pidof "route" | grep -f <(ps -o ppid= -p $$) > "$PID_FILE" # Capture PID
;;
down)
wg-quick down "$INTERFACE"
[ -f "$PID_FILE" ] && kill $(cat "$PID_FILE") && rm "$PID_FILE"
;;
*)
echo "Usage: $0 {up|down}"
exit 1
;;
esac
🔹 Tracks the monitor process via a PID file and ensures cleanup.
Use a Systemd ExecStopPost
Command
If using wg-quick@wg0.service
, add cleanup logic:
[Service]
ExecStopPost=/bin/sh -c 'pkill -f "route -n monitor"'
Then reload systemd:
systemctl daemon-reload
🔹 Ideal for systemd-managed WireGuard setups.
Conclusion
✅ On GhostBSD, no action is needed,wg-quick
handles monitoring correctly.
⚠️ On Linux, wg-quick
does not clean up properly, leading to orphaned route -n monitor
processes.
💡 Fix: Use PostDown hooks, wrapper scripts, or systemd cleanup to manage route -n monitor
processes.