vps·web

Proxmox NAT

Proxmox NAT Configuration with iptables MASQUERADE — Complete Guide

Server · Proxmox NAT

Proxmox NAT Configuration: A Complete Guide to iptables MASQUERADE for VMs and Containers

Running multiple virtual machines and LXC containers on a single Proxmox VE host is one of the great advantages of the platform — you get density, isolation, and snapshots without the overhead of separate physical servers. But the moment you start spinning up internal-only VMs on a private bridge like vmbr1 with a 192.168.23.1/24 subnet, you hit a wall: those guests can talk to each other, but they cannot reach the internet. The host has the public connection, the guests do not, and Proxmox does not configure the NAT translation between them automatically.

This is where iptables NAT comes in. With three short commands on the Proxmox host, you can turn it into a router for your private VM network, give every guest outbound internet access, and make the configuration survive a reboot. This guide walks through exactly what those rules do, why each one is needed, and how to use the Proxmox NAT generator to produce the correct commands for your environment in seconds.

Why Proxmox Does Not Configure NAT for You

Proxmox VE ships with a default Linux bridge called vmbr0, which is normally bridged directly to your physical NIC and your provider's public network. Any VM attached to vmbr0 gets a public IP (or a DHCP lease from your LAN) and works out of the box. That is the simple case.

The harder — and far more common — case is when you want to run private VMs that should not be exposed to the public network. Maybe you are running a Proxmox node at a hosting provider that gave you exactly one IPv4 address. Maybe you want to isolate a Kubernetes test cluster, a Windows AD lab, or a stack of internal services behind a single edge VM. In all of these scenarios, you create a second bridge — vmbr1 is the conventional name — assign it a private subnet such as 192.168.23.0/24, and attach your guests to that bridge instead.

At this point your guests can ping each other and the gateway address (the Proxmox host's IP on vmbr1), but nothing else. The Linux kernel on the host knows how to route the packets out — that part works automatically once IP forwarding is enabled — but the response packets coming back from the internet have no idea that 192.168.23.0/24 exists. That subnet is private. It is not announced to your provider's router, and even if it were, your provider would drop it. The fix is Network Address Translation: you rewrite the source address of every outbound packet from the private subnet to the host's public IP, so the return traffic comes back to the host, which then translates it back and forwards it to the original guest. That is exactly what iptables MASQUERADE does.

What the Generator Produces

The Proxmox NAT generator takes two inputs — the public interface name and the private subnet — and produces three blocks of iptables commands. Each block addresses a different part of the NAT setup, and understanding what each one does is what separates "I copied something from a forum" from "I know what is running on my router." Let's go through them.

Block 1: SNAT via MASQUERADE

The first command is the heart of the configuration:

iptables -t nat -A POSTROUTING -s '172.16.16.1/24' -o vmbr0 -j MASQUERADE

This adds a rule to the POSTROUTING chain of the nat table. POSTROUTING is the last chain a packet traverses before leaving the host, which is exactly when you want to rewrite the source address. The rule says: any packet coming from the 192.168.23.1/24 subnet that is being sent out through vmbr0 should have its source address replaced with the address currently configured on vmbr0. That is the MASQUERADE target. It is a special variant of SNAT (Source NAT) that does not require you to hardcode the public IP — it picks it up from the outbound interface at runtime. This is critical when your public IP can change, for example on a home connection with a dynamic address or after a provider migration.

The single quotes around the subnet are a small detail worth noticing. Some shells will try to interpret characters in CIDR notation, and the quotes make sure the literal string is passed to iptables. It is a defensive habit.

Block 2: Conntrack for Return Traffic

The second block enables the Linux connection tracking subsystem to do its job:

iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

If the FORWARD chain on your host has a default DROP policy — which it should on any router, and which Proxmox sometimes configures depending on the firewall settings — then return packets will be dropped before they ever reach your guest. The fix is to explicitly allow packets that belong to a connection that is already ESTABLISHED (the TCP handshake completed and traffic is flowing) or RELATED (a new connection that is logically tied to an existing one, like an FTP data channel or an ICMP error message about an existing UDP flow).

The conntrack module is what makes stateful firewalling possible on Linux. Every time a guest opens a connection to the internet, conntrack creates an entry in a kernel table recording the source, destination, ports, and current state. When the response comes back, conntrack looks up the entry and marks the packet as ESTABLISHED. This rule then accepts it. Without conntrack, you would need a complex set of stateless rules to accept all the legitimate return traffic — and you would inevitably get them wrong. With this one line, you get correct stateful behavior for free.

Block 3: Persistence Across Reboots

The third block solves the most common pitfall with iptables-based NAT:

apt-get install iptables-persistent -y
iptables-save > /etc/iptables/rules.v4
cat /etc/iptables/rules.v4

iptables rules live in memory. They are gone the moment you reboot the Proxmox host or restart the networking stack. Plenty of administrators have set up NAT successfully, gone home satisfied, and then come back to a panicked Monday morning when a routine reboot during maintenance broke connectivity for every VM on the host.

The iptables-persistent package solves this. On Debian and Ubuntu — and Proxmox is Debian-based — it installs a systemd service that loads rules from /etc/iptables/rules.v4 (and rules.v6 for IPv6) at boot. The iptables-save command serializes the current in-memory ruleset into the format that file expects, and the cat at the end is just a sanity check so you can verify the file was written correctly before you trust your reboot.

If you ever change the rules later, remember to run iptables-save > /etc/iptables/rules.v4 again. That is the single most common mistake people make: they edit a rule, test it, find it works, and assume it is permanent. It is not. The rule is in memory only until the file is rewritten.

One More Thing: IP Forwarding

The generator focuses on iptables, but iptables alone is not enough. The Linux kernel will not route packets between interfaces unless IP forwarding is explicitly enabled. On a fresh Proxmox install, this is sometimes already on, but it is worth checking and making it persistent.

To enable it for the current session:

sysctl -w net.ipv4.ip_forward=1

To make it survive reboots, edit /etc/sysctl.conf (or drop a file in /etc/sysctl.d/) and add: net.ipv4.ip_forward = 1

Then run sysctl -p to apply. Without this, none of the iptables rules above will do anything — the packets will never reach POSTROUTING because the host will refuse to forward them in the first place. This is the second most common pitfall, after forgetting to save the rules.

Configuring the Bridge Itself

The generator assumes your private bridge is already set up. If it is not, the configuration goes in /etc/network/interfaces on the Proxmox host. A typical entry for vmbr1 with the 192.168.23.0/24 subnet looks like this:

auto vmbr1 iface vmbr1 inet static address 192.168.23.1/24 bridge-ports none bridge-stp off bridge-fd 0

Notice bridge-ports none. This is what makes the bridge "internal" — it is not connected to any physical NIC, only to the virtual interfaces of your VMs and containers. The address 192.168.23.1/24 line sets the host as the gateway for that subnet, which is the IP your guests will use as their default route.

Apply with ifreload -a (Proxmox uses ifupdown2) or reboot, and your bridge is live. Attach a VM to vmbr1, give it an address like 192.168.23.10/24 with gateway 192.168.23.1 and a DNS server like 1.1.1.1, and once the iptables rules from the generator are in place, it will have working internet access.

When to Use the "Removal" Operation

The generator includes a "Dodawanie" (Add) and "Usuwanie" (Remove) toggle. The remove operation produces the same rules but with -D instead of -A, which deletes them from the running configuration. This is useful when you are reorganizing your network — for example, switching from 192.168.23.1/24 to a larger 10.0.0.0/16 because you are running out of addresses, or moving the public interface from vmbr0 to a bonded interface like bond0.

When making changes, the safest order is: generate the remove commands for the old configuration, run them, verify with iptables -t nat -L POSTROUTING -n -v and iptables -L FORWARD -n -v that the rules are gone, then generate and apply the new add commands, and finally run iptables-save > /etc/iptables/rules.v4 to persist the new state. Skipping the verification step is how you end up with stale rules accumulating over time, which makes troubleshooting a nightmare months later when nothing matches what you think is configured.

Verifying the Setup

Once the rules are in place, a few quick checks will tell you whether NAT is actually working:

# View the NAT rules
iptables -t nat -L POSTROUTING -n -v

# View the forward rules
iptables -L FORWARD -n -v

# Watch the MASQUERADE counter increment as a guest sends traffic
watch -n 1 'iptables -t nat -L POSTROUTING -n -v'

The packet and byte counters next to each rule increment in real time. If you start a ping from a guest and the counter stays at zero, packets are not reaching the rule — usually because the source address does not match the subnet you specified, or because IP forwarding is off. If the counter increments but the guest still has no internet, the problem is almost certainly the FORWARD chain or DNS resolution on the guest itself.

A direct connectivity test from inside the guest:

# Test raw IP connectivity (bypasses DNS)
ping -c 3 1.1.1.1

# Test DNS resolution
ping -c 3 google.com

# Test TCP outbound
curl -v https://example.com

If ping 1.1.1.1 works but ping google.com does not, the NAT is fine and you have a DNS configuration problem on the guest. If neither works, work backwards: ping the gateway (192.168.23.1), then check IP forwarding and conntrack on the host.

Security Considerations

Putting a Proxmox host directly on the public internet and turning it into a NAT router is a common pattern, but it does expand the attack surface. A few things are worth doing alongside the basic NAT setup. Restrict SSH access to specific source IPs using either iptables INPUT rules or /etc/hosts.allow. Consider running fail2ban to throttle brute-force attempts. If your guests do not need to talk to each other, add explicit FORWARD rules between them rather than relying on the implicit "same bridge" behavior. And if any guest is running a service that should be reachable from the internet, use the companion Proxmox Port Forwarding generator to add DNAT rules — never expose the entire guest by giving it a second NIC on vmbr0.

The Proxmox host itself should also have a minimal FORWARD policy that only allows what you need. The generator's conntrack rule is necessary but not sufficient for a hardened router; in production environments you would typically combine it with a default DROP policy and explicit ACCEPT rules per service. That is a deeper topic than this article can cover, but the key point is: the three-line generator output is the minimum to get NAT working, not the maximum to make it secure.

Why a Generator Helps

iptables syntax is unforgiving. A typo in the chain name, a missing flag, or a subtle confusion between the nat and filter tables produces rules that either silently do nothing or — worse — match the wrong traffic. The generator removes that whole class of mistakes by producing the exact, tested syntax for the parameters you provide. You spend your attention on the architectural decisions (which interface, which subnet, add or remove) rather than on remembering whether MASQUERADE belongs in PREROUTING or POSTROUTING.

It is also a small piece of self-documentation. Pasting the three blocks into your runbook gives anyone on your team a clear, complete picture of what was configured and why. Six months from now, when a colleague is debugging the network at 2 a.m., that clarity is worth a lot more than a one-line shell history entry.

Try the Proxmox NAT generator and pair it with the Proxmox Port Forwarding generator for a complete inbound + outbound NAT setup on your Proxmox host.