I’m setting up a WireGuard VPN server with NAT and forwarding rules applied via `iptables-persistent` (netfilter-persistent). After reboot, the VPN interface `wg0` comes up, but NAT masquerade rules and forwarding rules are **not consistently applied**, causing traffic from the VPN subnet (10.10.0.0/24) to fail.
WireGuard itself works when the rules are manually reapplied. The root cause appears to be systemd starting the wg-quick@wg0.service before netfilter-persistent.service has loaded firewall rules.
Expected behavior:
NAT and forwarding rules are loaded before the WireGuard interface comes up.
VPN clients can route traffic through the server immediately after boot.
Observed behavior:
After a reboot, health checks report missing NAT and forwarding rules.
Temporary fixes include manually running wg-quick down/up and reapplying NAT/forwarding rules.
Relevant System Information:
iptables-persistent version: 1.0.14
netfilter-persistent version: 1.0.14
WireGuard kernel module: 5.15.0-76-generic
Oracle Cloud Ubuntu image with default InstanceServices firewall rules
Saved firewall rules with sudo netfilter-persistent save and reloaded daemon.
Created a health-check script that reapplies rules if missing.
Result: After this, the system behaves correctly if the script is run, but rules are still inconsistently applied immediately at boot without the script, suggesting a race condition in systemd startup order.
You could try studying the boot sequence diagram, to identify those possible race conditions, using the SVG chart generated from the following command:
You can create a similar one for the condition you require to be met.
You can also look at the output of the following report to see the “heavy hitters” in terms of CPU usage during boot, which might give a related hint regarding which service or target needs to be incorporated into a local-custom systemd dependency target.
pattern="boot"
report="systemd_analyze__timing_${pattern}"
sudo systemd-analyze blame >${report}.txt
more ${report}.txt
Or … you could create an “rc.local” file to contain any specialized command sequence to be completed at boot time, for your case, possibly
wg-quick down wg0
{commands to restart iptables/nftables for your circumstance}
wg-quick up wg0
My own “/etc/rc.local” file deals with an unrelated issue, and works just fine!
Hi @ericmarceau — thank you very much for the detailed suggestions and for taking the time to share your diagnostic approach.
In my particular case, it turned out to be a startup race condition between wg-quick@wg0.service and netfilter-persistent.service (iptables restore). I addressed it by creating a systemd override file at:
I also added a lightweight verification script (/usr/local/bin/wgcheck.sh) that runs at boot via cron (@reboot) to confirm that WireGuard, NAT, and forwarding rules are healthy — it automatically repairs the configuration if anything’s missing.
Since applying these changes, the system has been stable across multiple reboots, and WireGuard comes up cleanly every time.
Your suggestions about systemd-analyze and rc.local are excellent — I’ll keep those in mind for future troubleshooting. Thanks again for contributing your insights!