Frontend/Backend Containers on Proxmox
This is a walkthrough for setting up a Proxmox host to forward incoming web traffic (both IPv4 and IPv6) to containerized backend servers.
In this example, the host’s public interface (eno1) holds the public addresses, and a separate internal bridge (vmbr0) provides container connectivity. The backend container (CT) is assigned 10.10.10.114 for IPv4 and (using a ULA for clarity) fd00:1::114 for IPv6.
────────────────────────────── 1. Network Layout Overview
Public Interface (eno1):
- IPv4: [PUBLIC_IPv4]/26 with gateway 95.217.145.193
- IPv6: [PUBLIC_IPv6]::2/64 with gateway (link-local) fe80::1
Internal Bridge (vmbr0):
- IPv4: 10.10.10.1/24
- IPv6: Use a ULA (e.g., fd00:1::1/64) to avoid overlapping with the public IPv6 assignment
Backend Container (web server):
- IPv4: 10.10.10.114
- IPv6: fd00:1::114
────────────────────────────── 2. Configuring Proxmox Networking
Edit /etc/network/interfaces
so that eno1 and vmbr0 are defined as follows:
auto lo
iface lo inet loopback
iface lo inet6 loopback
auto eno1
iface eno1 inet static
address [PUBLIC_IPv4]/26
gateway [PUBLIC_GW_IPv4]
up route add -net [PUBLIC_RT_IPv4] netmask 255.255.255.192 gw [PUBLIC_GW_IPv4] dev eno1
iface eno1 inet6 static
address [PUBLIC_IPv6]::2/64
gateway fe80::1
auto vmbr0
iface vmbr0 inet static
address 10.10.10.1/24
bridge-ports none
bridge-stp off
bridge-fd 0
iface vmbr0 inet6 static
address fd00:1::1/64
Notes:
- Using a ULA on vmbr0 (fd00:1::/64) avoids overlapping with the public IPv6 block.
- Alternatively, you could bridge eno1 into vmbr0 so that containers get public IPv6 addresses directly—but that may complicate inbound filtering if you prefer to separate external/public and internal networks.
────────────────────────────── 3. Configuring the Container Network
When creating or editing your container (e.g., CTID 114), set its network configuration (via the Proxmox web UI or editing /etc/pve/lxc/114.conf
) as follows:
# IPv4
net0: name=eth0,bridge=vmbr0,ip=10.10.10.114/24,gw=10.10.10.1
# IPv6 using ULA
net0: ip6=fd00:1::114/64,gw6=fd00:1::1
This ensures the container receives its internal IPs while the host handles public access via NAT and port forwarding.
────────────────────────────── 4. Enabling IP Forwarding
On the Proxmox host, enable forwarding for both IPv4 and IPv6:
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf
sysctl -p
────────────────────────────── 5. Configuring NAT and Port Forwarding
You need to forward incoming web traffic (ports 80 and 443) from the public interface (eno1) to the backend container.
IPv4 Rules (using iptables):
# NAT for outgoing traffic from the 10.10.10.0/24 network
iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o eno1 -j MASQUERADE
# Forward IPv4 Port 80 (TCP)
iptables -t nat -A PREROUTING -i eno1 -p tcp --dport 80 -j DNAT --to-destination 10.10.10.114:80
iptables -A FORWARD -p tcp -d 10.10.10.114 --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Forward IPv4 Port 80 (UDP)
iptables -t nat -A PREROUTING -i eno1 -p udp --dport 80 -j DNAT --to-destination 10.10.10.114:80
iptables -A FORWARD -p udp -d 10.10.10.114 --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Forward IPv4 Port 443 (TCP)
iptables -t nat -A PREROUTING -i eno1 -p tcp --dport 443 -j DNAT --to-destination 10.10.10.114:443
iptables -A FORWARD -p tcp -d 10.10.10.114 --dport 443 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# Forward IPv4 Port 443 (UDP)
iptables -t nat -A PREROUTING -i eno1 -p udp --dport 443 -j DNAT --to-destination 10.10.10.114:443
iptables -A FORWARD -p udp -d 10.10.10.114 --dport 443 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
IPv6 Rules (using ip6tables). Since we’re using a ULA on the container side (fd00:1::114) and eno1 holds the public IPv6, add the following rules. Note the use of brackets around IPv6 addresses when appending ports:
# IPv6 NAT for outgoing traffic from the ULA range on vmbr0
ip6tables -t nat -A POSTROUTING -s fd00:1::/64 -o eno1 -j MASQUERADE
# IPv6 Forward Port 80 (TCP)
ip6tables -t nat -A PREROUTING -i eno1 -p tcp --dport 80 -j DNAT --to-destination [fd00:1::114]:80
ip6tables -A FORWARD -p tcp -d fd00:1::114 --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# IPv6 Forward Port 80 (UDP)
ip6tables -t nat -A PREROUTING -i eno1 -p udp --dport 80 -j DNAT --to-destination [fd00:1::114]:80
ip6tables -A FORWARD -p udp -d fd00:1::114 --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# IPv6 Forward Port 443 (TCP)
ip6tables -t nat -A PREROUTING -i eno1 -p tcp --dport 443 -j DNAT --to-destination [fd00:1::114]:443
ip6tables -A FORWARD -p tcp -d fd00:1::114 --dport 443 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# IPv6 Forward Port 443 (UDP)
ip6tables -t nat -A PREROUTING -i eno1 -p udp --dport 443 -j DNAT --to-destination [fd00:1::114]:443
ip6tables -A FORWARD -p udp -d fd00:1::114 --dport 443 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
Important:
- Adjust the ULA (fd00:1::/64) and container IPv6 (fd00:1::114) as needed.
- Use a persistence mechanism (such as iptables/ip6tables-persistent) to save these rules.
────────────────────────────── 6. Testing and Verification
IPv4:
- From an external source, try connecting to http://[PUBLIC_IPv4].
- Verify that traffic is correctly forwarded to the container’s web server (check logs on the container).
IPv6:
- Use tools like
ping6
andcurl -6
to test connectivity. - Ensure the DNAT rules are translating correctly by inspecting the ip6tables counters.
- Use tools like
General:
- Check that IP forwarding is enabled:
sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding
- Inspect current NAT rules:
iptables -t nat -L -n -v ip6tables -t nat -L -n -v
- Check that IP forwarding is enabled:
────────────────────────────── Conclusion
By configuring separate public and internal networks on your Proxmox host and applying NAT/port-forwarding rules for both IPv4 and IPv6, you enable your containerized web server to serve content externally without assigning it a directly routable public IP. This frontend/backend setup keeps your host’s public IP handling incoming traffic and safely directs it to the backend container, ensuring flexible, secure web service delivery.
