Configuring Bridged LXC Containers with Dedicated Public Static IPs: A Complete Guide for Ubuntu Hosts


3 views

When working with LXC containers on Ubuntu hosts, many administrators need to assign dedicated public IPs to containers while maintaining proper network isolation. The common bridge networking approach often leads to routing conflicts where:

# Common symptoms include:
- Host responding to container IPs
- Extremely slow container boot times
- "Redirect Host" errors in ping/traceroute
- Duplicate IP assignments in lxc-ls output

First, let's examine the correct host bridge setup in /etc/network/interfaces:

auto br0
iface br0 inet static
    address HOST_PUBLIC_IP/24
    gateway HOST_GATEWAY
    bridge_ports eth0
    bridge_stp off
    bridge_fd 0
    bridge_maxwait 0

For each container, remove any IP configuration from the LXC config and instead handle it in the container's interfaces file:

# /var/lib/lxc/CONTAINER_NAME/config
lxc.network.type = veth
lxc.network.link = br0
lxc.network.hwaddr = 00:16:3e:XX:XX:XX
lxc.network.flags = up

Inside the container (/etc/network/interfaces), use this precise configuration:

auto eth0
iface eth0 inet static
    address CONTAINER_PUBLIC_IP/24
    gateway HOST_GATEWAY
    dns-nameservers 8.8.8.8 8.8.4.4
    post-up ip route add HOST_GATEWAY dev eth0
    post-up ip route add default via HOST_GATEWAY

These sysctl settings are essential for proper routing:

# /etc/sysctl.conf
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-arptables=0

If you encounter the "Redirect Host" error, check these solutions:

# Verify ARP filtering is disabled
echo 0 > /proc/sys/net/ipv4/conf/all/arp_filter
echo 0 > /proc/sys/net/ipv4/conf/br0/arp_filter

# Ensure no duplicate IP assignments
ip addr show | grep "YOUR_PUBLIC_IP"

Here's a real-world configuration that works reliably:

# Host bridge config
auto br0
iface br0 inet static
    address 203.0.113.45/24
    gateway 203.0.113.1
    bridge_ports eth0
    bridge_stp off

# Container config (LXC)
lxc.network.type = veth
lxc.network.link = br0
lxc.network.hwaddr = 00:16:3e:a1:b2:c3

# Container interfaces
auto eth0
iface eth0 inet static
    address 203.0.113.46/24
    gateway 203.0.113.1
    post-up ip route add 203.0.113.1 dev eth0
    post-up ip route add default via 203.0.113.1

When working with LXC containers that require direct public internet access, bridging is often the preferred approach. The typical setup involves:

# Host /etc/network/interfaces
auto br0
iface br0 inet static
    bridge_ports eth0
    bridge_fd 0
    address HOST_PUBLIC_IP
    netmask 255.255.255.0
    gateway PUBLIC_GATEWAY
    dns-nameservers 8.8.8.8

The key to making this work lies in proper container configuration. Here's what your LXC config should contain:

# /var/lib/lxc/CONTAINER_NAME/config
lxc.network.type = veth
lxc.network.link = br0
lxc.network.flags = up
lxc.network.hwaddr = RANDOM_MAC_ADDRESS

The most frequent issues I've encountered (and their solutions):

# Problem: IP conflict between host and container
# Solution: Remove IP aliases from host
sudo ip addr del PUBLIC_IP/32 dev eth0

# Problem: Routing loops
# Solution: Ensure proper ARP filtering
echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
echo 1 > /proc/sys/net/ipv4/conf/br0/arp_filter

Here's a working example of the container's /etc/network/interfaces:

auto eth0
iface eth0 inet static
    address CONTAINER_PUBLIC_IP
    netmask 255.255.255.255
    pointopoint GATEWAY_IP
    post-up route add GATEWAY_IP dev eth0
    post-up route add default gw GATEWAY_IP
    dns-nameservers 8.8.8.8

To verify your setup is working correctly:

# From host:
ping CONTAINER_IP
lxc-attach -n CONTAINER_NAME -- ping 8.8.8.8

# Check routes:
ip route show
bridge link show

For more complex scenarios, consider these additional settings:

# Prevent NAT issues
echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables

# Improve performance
echo 0 > /proc/sys/net/bridge/bridge-nf-call-arptables