Public IPv6 on Containers

I have been attempting to use IPv6 as much as possible lately. I have a /48 with delegation enabled from my router. The problem I am having is figuring out how to use a delegated range with LXD containers. Everything I have read suggests you have to manually enter a /64 in to use.
Is there any way to use dhclient to grab the delegated range to use with lxdbr0 to configure the IPs on the containers?
If not, does anyone have a good guide for configuring an IPv6 /64 on lxdbr0. The guides I have attempted to follow didn’t work for me.

Yes, it is possible to use dhclient to obtain an IPv6 prefix delegation (PD) from your router and then use that PD to configure the IPv6 addresses of your LXD containers. Here are the basic steps:

  1. Configure dhclient to request a prefix delegation by adding the following lines to /etc/dhcp/dhclient.conf:
interface "eth0" {
  send dhcp6.request_prefix;
}

(This assumes that your WAN interface is eth0. Adjust the interface name as appropriate for your setup.)

  1. Restart the networking service to apply the changes:
sudo systemctl restart networking
  1. Once dhclient has obtained a prefix delegation, you can use the pd-address parameter when creating a new LXD network bridge to assign a part of the delegated range to the bridge:
lxc network create mynet \
  ipv6.address=2001:db8:1234::1/64 \
  ipv6.nat=false \
  ipv6.dhcp=true \
  ipv6.dhcp.stateful=false \
  ipv6.dhcp.range=2001:db8:1234::100,2001:db8:1234::200 \
  ipv6.routes=2001:db8:1234::/48

lxd init --auto \
  --network-address=2001:db8:1234::1/64

This example creates a new LXD network bridge called “mynet” and assigns the IPv6 address 2001:db8:1234::1/64 to it. It also configures a DHCP range of 2001:db8:1234::100 to 2001:db8:1234::200. The pd-address parameter is not used here, as the delegated prefix is automatically assigned to the network (@tomp I’m actually not 100% sure about that, what do you think ?).

  1. Finally, you can configure the IPv6 addresses of your LXD containers by assigning them addresses from the delegated prefix using the lxc network attach command:
lxc network attach mynet <container-name> eth0 eth0
lxc config device set <container-name> eth0 ipv6.address=2001:db8:1234::2/64

This example attaches the container to the “mynet” network and assigns it the IPv6 address 2001:db8:1234::2/64 on its eth0 interface.

I hope this helps! Let me know if you have any further questions or concerns.

1 Like

I personally would be wary of using an externally acquired temporary IPv6 allocation and then statically configuring it into lxdbr0. As something will presumably have to maintain that lease externally and if it ever goes away or changes to a different subnet then your lxdbr0 network will end up having incorrect addresses.

It would be better in my view to ask your ISP to A) route a specific /64 to your endpoint or B) route the entire allocation to your endpoint (this is what my ISP does, so I get the whole /48 routed directly to my router without having to use DHCP, I am then free to route it internally to my LXD server as needed).

1 Like

@ciphermenial have you checked whether your /48 allocation is already routed to your router without using PD? Or are you confident that you’ll always get the same allocation if using PD?

1 Like

Yes. I am already using it and the ISP has confirmed it is fixed to my connection and won’t change.

OK so in that case you can use just the /64 you’ve been assigned in lxdbr0 directly.

1 Like

@gabrielmougard what was your thinking around this in the suggestion, it seems unnecessary to me?

1 Like

This bit too.

1 Like

One thing you will want to set is lxc network set lxdbr0 ipv6.nat=false

1 Like

Can you show the output of ip a and ip -6 r on the LXD host after?

1 Like

@tomp I wanted to show an example of a network creation that was taking a range of /64 addresses and a set of addresses to the bridge (using ipv6.routes) that correspond to the /48 addresses. My understanding of ipv6 is probably not accurate though.

Regarding the lxd init --auto ... bit, isn’t it how we can initiate LXD with an pre-existing managed network ?

1 Like

Hrm, no I don’t think this is quite what the OP is requesting.

My understanding is that the OP wants to use a /64 from their /48 allocation with lxdbr0.

Now, if the /48 (or the /64 in question) is not statically routed to the LXD host, then there will need to be a manual use of IPv6 PD to get the /64 subnet routed to the host.

Once thats done, they can setup the lxdbr0 as follows:

I’m assuming that they’ve already initialised their LXD and that lxdbr0 is currently using an automatically generated ULA IPv6 /64 subnet with NAT enabled.

lxc network set lxdbr0 \
    ipv6.address=<first IP in delegated subnet>/64 \
    ipv6.nat=false

This will then instruct LXD to take ownership of that IPv6 subnet and configure the host to route packets arriving at the external interface into the managed lxdbr0 bridge.

We don’t necessarily need stateful DHCPv6 or DHCPv6 ranges, because by default LXD will use SLAAC and router advertisements to allow automatic configuration of the instances.

By disabling NAT though, it allows the instances to be directly reachable on the internet, and won’t be hidden behind the host’s IP.

2 Likes

The lxd init command is for initializing LXD on first start, it does the equivalent of lxc network create (amongst other things), so there’s no point in do lxd init again after you’ve added a managed network via lxc network create.

If you want the new network to be used by default for instances, either modify lxdbr0 which is already part of the default profile or do lxc profile set default eth0 network=<new network>.

1 Like

I am using a MikroTik router for my setup. The router is receiving the /48 from my ISP and creating a /64 pool for SLAAC to my LAN. The IP addressing I am attempting to use is as follows.

2001:1111:1111::/48
2001:1111:1111::/64 for SLAAC on LAN
2001:1111:1111:1::/64 to be used on the lxdbr0

I have run lxc network set lxdbr0 ipv6.address=2001:1111:1111:1::1/64 ipv6.nat=false and that assigns an IPv6 in that range to each of the containers. However I am still unable to get IPv6 connectivity working past the LXD host. I am guessing the problem is with routing.

Update: Ignore that. I did need to add a route on my router to pass it to the host IP.

1 Like

This is exactly how it should work. NAT is not security. I only allow inbound on 443 to my reverse proxy, which means only exposing a single container through the firewall.

Yes its not enabled by default for security, but rather for convenience so that instances connected to default lxdbr0 bridge can get egress connectivity without having to configure their upstream router.

1 Like

I see.

I have written up what I have done with this. The router side is with Mikrotik, but I think it could be useful for others trying to make this work.

https://ciphermenial.github.io/posts/public-ipv6-lxd/

1 Like