fix: Move VPN masquerade rules from iptables PostUp to nftables

iptables-nft rules added by WireGuard's PostUp were being flushed by
Docker on startup, breaking VPN LAN routing until the next reboot.
The nftables inet wild-central table survives Docker restarts.
This commit is contained in:
2026-10-23 13:32:41 +00:00
parent 1176c7715a
commit d35d0854cb
4 changed files with 76 additions and 20 deletions

View File

@@ -35,7 +35,8 @@ func (m *Manager) GetRulesPath() string {
// Policy is always "accept" — the allowed_tcp_ports set documents what is in use
// and enables strict WAN filtering when wanInterface is configured.
// extraTCPPorts and extraUDPPorts are user-specified ports to allow beyond the HAProxy set.
func (m *Manager) Generate(haproxyPorts []int, extraTCPPorts []int, extraUDPPorts []int, wanInterface string) string {
// vpnCIDR, when non-empty (e.g. "10.8.0.0/24"), adds forward and masquerade rules for VPN traffic.
func (m *Manager) Generate(haproxyPorts []int, extraTCPPorts []int, extraUDPPorts []int, wanInterface string, vpnCIDR string) string {
// Merge and deduplicate TCP ports (HAProxy + extra TCP)
seen := make(map[int]bool)
var tcpPorts []int
@@ -108,6 +109,23 @@ func (m *Manager) Generate(haproxyPorts []int, extraTCPPorts []int, extraUDPPort
}
sb.WriteString(" }\n")
// VPN forwarding and masquerade: when vpnCIDR is set, allow forwarding between
// wg0 and LAN, and masquerade VPN traffic leaving the VPN subnet.
// These rules live in the nftables table (not iptables PostUp) so they survive
// Docker restarts, which flush the iptables-nft compatibility tables.
if vpnCIDR != "" {
sb.WriteString("\n chain vpn-forward {\n")
sb.WriteString(" type filter hook forward priority filter; policy accept;\n")
sb.WriteString(" iif \"wg0\" accept\n")
sb.WriteString(" oif \"wg0\" ct state { established, related } accept\n")
sb.WriteString(" }\n")
sb.WriteString("\n chain vpn-postrouting {\n")
sb.WriteString(" type nat hook postrouting priority srcnat; policy accept;\n")
fmt.Fprintf(&sb, " ip saddr %s ip daddr != %s masquerade\n", vpnCIDR, vpnCIDR)
sb.WriteString(" }\n")
}
sb.WriteString("}\n")
return sb.String()