Whilst it is possible to use manual iptables rules to forward ports from outside to containers. It works, but not well, because it is impossible to connect from container to outside IP or connect from the host itself to outside IP’s ports (like my own DNS server).
Here are the steps to forward port from outside to container properly using LXD’s proxy
device in NAT mode (which automates the iptables rules required):
First, enable br_netfilter
kernel module. This step is optional, but without it your container will not be able to connect to the proxy’s external address and have connections forwarded back to it. However caution should be taken with this step on systems running existing instances and a firewall as enabling br_netfilter
will cause all bridge traffic to flow through the firewall, and may cause some traffic to be unexpectedly blocked if an existing firewall rule matches bridge traffic that wasn’t previously filtered.
In Debian 10 you can do this:
modprobe br_netfilter
echo br_netfilter > /etc/modules-load.d/lxd.conf
Second, set a static IP address on your container’s NIC. Look up your current dynamic address:
lxc list | grep testcontainer
| testcontainer | RUNNING | 172.16.172.113 (eth0) | fd42:dad8:c4ad:e744:216:3eff:fecf:5770 (eth0) | CONTAINER | 0 |
And set that address as static IP:
Note: That when setting a static IPv6 address you will need to ensure that the parent managed network has ipv6.dhcp.stateful
enabled, otherwise setting a static IPv6 address will fail.
lxc stop testcontainer
lxc config device override testcontainer eth0 ipv4.address=172.16.172.113 ipv6.address=fd42:dad8:c4ad:e744:216:3eff:fecf:5770
lxc start testcontainer
Third, add proxy device to your container, one per port:
lxc config device add testcontainer proxyv4 proxy nat=true listen=tcp:a.b.c.d:7777 connect=tcp:0.0.0.0:7777
Device proxyv4 added to testcontainer
lxc config device add testcontainer proxyv6 proxy nat=true listen=tcp:[2001:db8::1]:7777 connect=tcp:[::]:7777
Device proxyv6 added to testcontainer
Here a.b.c.d
and 2001:db8::1
is your external IP address and proxyvX
is just a string identifier, so error messages about missing device are kinda misleading, it’s not a real network interface.
Now you can telnet to your external IP anywhere; inside the container, inside the host or outside, all iptables rules are created automatically.
To remove that port forward use remove command:
lxc config device remove testcontainer proxyv4
Device proxyv4 removed from testcontainer
lxc config device remove testcontainer proxyv6
Device proxyv6 removed from testcontainer
For more information, see the proxy
device documentation: https://linuxcontainers.org/lxd/docs/master/instances#type-proxy