Series: GNTECH Infrastructure Deployment Series · Part 04 of 12 · Previous: Part 03 — Dual MikroTik CHR · Next: Part 05 — Home-to-Hetzner Connectivity (planned)
A VM can reach its gateway yet still be isolated from the Internet. A firewall can protect the Proxmox host while accidentally allowing traffic between two internal zones. And a working NAT rule is not evidence that a forwarding policy is safe.
This installment builds a small, explicitly scoped lab policy for the topology introduced in Parts 02–03. It is a teaching example, not a production ruleset or a record of live GNTECH/PVR01 tests. Never apply firewall changes to your only reachable management path.
1. Know which traffic you are filtering
| Interface | Example network | Responsibility |
|---|---|---|
vmbr0 |
Provider WAN (real addresses omitted) | Host uplink and public IP routing |
vmbr1 |
10.255.1.0/30 |
Proxmox ↔ CHR-A transit |
vmbr2 |
10.255.2.0/30 |
Proxmox ↔ CHR-B transit |
vmbr3 |
10.3.0.0/24 |
General private VMs; host gateway 10.3.0.1 |
The public IPv4 routes for each CHR are provider-specific. This guide does not install, change, or infer them. A routed /32 is not automatically a NAT source, nor does the host firewall replace RouterOS’s policy for the LAN behind the CHR.
A Linux host has distinct packet paths:
- INPUT: packets addressed to the Proxmox host, including SSH and port 8006.
- OUTPUT: packets originated by the host.
- FORWARD: packets passing through the host between interfaces, including routed VM Internet traffic.
This guide demonstrates FORWARD plus POSTROUTING NAT. It intentionally leaves host INPUT/OUTPUT access under the existing firewall owner and does not open management services.
2. Choose one deliberate firewall ownership model
Proxmox ships an established pve-firewall implementation and an nftables-based proxmox-firewall implementation. Their capabilities and support status can differ by installed Proxmox release. Verify the current documentation and local services before using host-forward rules or switching backends.
Proxmox’s documentation notes that forwarded host/VNet policy requires the nftables-based backend; legacy pve-firewall ignores forward rules. It also allows custom nftables tables separate from the ones proxmox-firewall manages. Never assume an ACCEPT verdict in your custom table can override a DROP verdict in another base chain.
Read-only inventory:
|
|
Stop if you find unexplained custom forwarding/NAT tables, duplicated vmbr3 masquerade rules, pending interface changes, or a Proxmox backend migration. Consolidate ownership before adding another ruleset. Do not disable either firewall service simply to make these examples work.
3. Protect recovery before testing
You need a tested Hetzner rescue/console path independent of the two CHR VMs, a second admin connection, an outage window, and an explicit rollback operator.
Capture the running rules without changing them:
|
|
An on-host copy is useful for inspection but not an off-host backup. Keep recovery credentials and an external copy separately. A full nft -f restore from an old host dump can conflict with Proxmox-managed tables; rollback should normally remove only the tables you added, and the existing owners should regenerate their own rules.
4. Define the specific lab policy
The initial lab accepts these only:
- New IPv4 flows from
vmbr3tovmbr0, when their source is10.3.0.0/24. - Established replies from
vmbr0back tovmbr3. - No unsolicited WAN-to-
vmbr3traffic. - No forwarding between
vmbr3andvmbr1/vmbr2. - No IPv6 forwarding to or from
vmbr3until separately designed.
Not covered by this starter: authorization for CHR public /32 forwarding. It remains governed by the existing host firewall and CHR deployment design. A broad pass-through for unrelated interfaces in a lab-specific chain does not replace the host’s existing firewall.
Stage a scoped nftables filter file
The commands below create a new file only. They do not apply firewall rules.
|
|
Why an inet table? It observes both address families and can intentionally deny IPv6 on VM3 while allowing carefully scoped IPv4 forwarding. The explicit vmbr3 ingress/egress drops leave CHR transit traffic untouched by this particular table. The default ACCEPT is appropriate only because this is a supplemental, narrowly scoped chain and all other forwarding already has a separate policy owner. For a new host lacking that baseline, stop and design the complete host firewall first.
The ct state established rules should only be meaningful for traffic that entered through an approved outbound path. They do not mean another base chain cannot reject a packet.
Stage source NAT separately
Use NAT only for the general-purpose VM subnet, not for CHR-A or CHR-B public addresses:
|
|
Do not apply this if your Proxmox, RouterOS, nftables, or iptables configuration already NATs 10.3.0.0/24; duplicate NAT is difficult to debug. The masquerade statement deliberately uses the WAN’s current source address, so it is for VM3 private Internet egress—not for a CHR’s provider-routed public /32.
5. Validate the syntax and plan activation
These are checks, not a deployment:
|
|
For the route to work, IPv4 forwarding must be enabled and the authoritative forwarding policy must permit this path. To stage a persistent sysctl for later review, do not overwrite an existing value or file:
|
|
After confirming no conflicting policy and a tested independent recovery path, an operator can explicitly execute the following from a maintenance console. These actions change live packet filtering and may disrupt connections:
|
|
Neither temporary rules nor the runtime sysctl setting survives all reboot scenarios by default. Persistence is intentionally not enabled in this lab. Integrate changes with your existing Proxmox/nftables management mechanism only after the acceptance tests pass.
6. Anti-spoofing for the router transit links
For routed CHR addressing, verify source-address ownership in the appropriate existing forwarding firewall. An example design condition is that vmbr1 may originate its assigned transit address and provider-authorized CHR-A public IP, but never CHR-B’s IP.
Do not apply the following as a working WAN policy. RFC 5737 public addresses are illustrative and cannot validate provider routing:
|
|
Before implementing filters, decide whether each CHR is doing its own NAT for an internal LAN or routing prefixes transparently. The set of valid source addresses changes accordingly. Do not indiscriminately block private source traffic across CHR transit if your design legitimately carries routed private subnets; instead enumerate and permit each justified prefix under an explicit policy.
Also consider asymmetric routing and reverse-path filtering (rp_filter). Defaulting to strict reverse-path checking without understanding multiple routes can break legitimate flows; document and test before changing sysctls.
7. IPv6: never assume IPv4 NAT protects it
A Hetzner IPv6 /64 is typically routed toward the host according to the purchased product’s network model. Treat IPv6 as a separate routed and filtered service.
Our lab intentionally does not forward IPv6 on vmbr3. To enable it later you must:
- Verify the actual delegated prefix and next-hop behavior.
- Choose whether hosts use separate routed prefixes, /128 routes, or another explicitly supported design; do not assign the same /64 independently to multiple LANs.
- Review
net.ipv6.conf.all.forwardingand default-route / Router Advertisement interactions. - Permit essential ICMPv6 for Neighbor Discovery and Packet Too Big where appropriate, while restricting unsolicited service ingress.
- Test an authorized IPv6 flow and a blocked one. IPv4
masqueradedoes nothing to filter IPv6.
Useful non-destructive checks:
|
|
8. Test both allowed and denied traffic
Do not call the deployment verified because ping 1.1.1.1 succeeds. Perform the tests from a disposable VM attached to vmbr3, and from another test endpoint in a separate zone.
| Test | Intended result | Evidence to record |
|---|---|---|
VM3 → 10.3.0.1 |
Reach host gateway if INPUT policy allows | Route, ping/ARP, host counters |
| VM3 → external HTTPS IPv4 | Allowed | TCP connection, NAT counters, observed egress |
| WAN → VM3 unsolicited | Blocked | Controlled incoming TCP probe, drop counters |
| VM3 → CHR-A / CHR-B transits | Blocked | Controlled TCP probe, forward drop counters |
| CHR-A ↔ CHR-B | Only explicitly routed/authorized traffic | Existing firewall and RouterOS counters |
| VM3 → external IPv6 | Blocked at this stage | IPv6 attempt and explicit drop counter |
| Hypervisor management | Existing authorized management still works | Independent admin session |
| Host rescue | Available without CHR | Provider recovery method tested |
Example read-only commands after staged activation:
|
|
Counters are stronger than guesses, but concurrent traffic can change them. Ideally use unique controlled test destinations/ports and note the before-and-after values.
Important nuance: traffic destined for 10.3.0.1 is INPUT, not FORWARD. Likewise, Proxmox VM-to-VM traffic on the same Linux bridge may never pass through the routed host FORWARD path. Use bridge/VM firewall rules if you need to isolate guests on the same L2 network.
9. Targeted rollback and recovery
The two files above use unique table names so their rollback is narrow. If you applied them and validation fails, an operator at the independent console can remove only those tables:
|
|
If you also enabled forwarding with sysctl -w, restore the original recorded value rather than unconditionally setting it to 0: other workloads might depend on it. If Proxmox manages other tables, do not run nft flush ruleset or restart firewall services indiscriminately.
If management disappears, use Hetzner’s tested independent recovery console or rescue workflow and inspect the current host tables before changing anything. A firewall rollback is only complete once your original connectivity and zone-isolation tests pass again.
10. What is and isn’t proven
Provided: a staged, copyable filter/NAT lab, explicit policy boundaries, a test matrix, and rollback commands.
Not proven: installation of these rules on an actual server, WAN/IPv6 reachability, the source routing of CHR public IPv4, compatibility with every version/backend of Proxmox, or resistance to all forms of spoofing. A production deployment needs a complete ruleset review and measured negative tests on its own host.
Next: Part 05 — Home-to-Hetzner Connectivity, covering site-to-site transport, route ownership, routing failure modes, and recovery paths.