IPv6 with a Freebox Pop and OPNSense
Sun 30 November 2025 — download

Because the Freebox Pop is an underpowered piece of crap quite weak when it comes to NAT'ing anything above 100Mbps, I decided to get a proper machine and slap OPNSense on it: I'm paying for the whole fiber, I'm going to use the whole fiber.

IPv4 was trivial: Firewall -> NAT -> Port Forward, and you're done. It took me 5 minutes. IPv6 very much not so, partly because I don't have a clue about IPv6 (and let's be honest, network in general), partly because it's an almost 30 years old pile of designed-by-committee RFC.

Amyway, the Freebox Pop is giving me seven /64 prefixes that I can freely delegate, so for simplicity's sake and because I'm a lazy punk, I:

  1. waste use one for the network between the Freebox and the WAN interface of OPNSense.
  2. use a second one for the LAN

It looks like this:

+──────────+
│ Internet │
+──────────+
     │
     ▼
┌─────────┐
│ Freebox │
└─────────┘
     │      prefix A
     ▼
┌──────────┐
│ OPNSense │
└──────────┘
     │      prefix B
     ▼
  +─────+
  │ LAN │
  +─────+

Apparently, it's possible to not waste a prefix for the network between the Freebox and the router, but in the spirit of modern times, I'm comfortable wasting a significant amount of resources because I couldn't be bothered.

Freebox side

  1. Open http://mafreebox.freebox.fr in your browser
  2. Paramètres de la Freebox -> Réseau Local: Mode Réseau -> Bridge
  3. Open http://mafreebox.freebox.fr in your browser
  4. Paramètres de la Freebox -> Connexion Internet: Configuration IPv6
    1. Note the Local link address
    2. Note the first and second delegate prefixes, eg. 2a01:xxx:xxx:xxx1:: and 2a01:xxx:xxx:xxx2::.
    3. Disable the IPv6 firewall, since it's dropping ~everything and can't be configured besides on/off.

OPNSense side

  1. Open the admin interface
  2. Firewall -> Settings -> Advanced -> Allow IPv6
  3. Interfaces -> Overview -> WAN should contain an IPv6 starting with fe80:: note it down. It's the Local link address of the WAN interface.
  4. System -> Gateway -> Add:
    1. Name: FreeboxIPv6Gateway
    2. IP Address: IPv6 address of the Freebox in the first delegate prefix, 2a01:xxx:xxx:xxx1::1 in our case
    3. Upstream gateway: tick the box
    4. Monitor IP: tick the box, if only to be warned/have logs if when things go South

Back to the Freebox side

  1. Open http://mafreebox.freebox.fr/ in your browser
  2. Paramètres de la Freebox -> Connexion Internet: Configuration IPv6 -> Délégation de prefixe: add the Local link address of the WAN interface into the Next Hop field for the first and second prefixes.

Back to the OPNSense side

  1. Interfaces -> WAN:
    1. Generic configuration -> IPv6 Configuration Type, set it to Static IPv6
    2. Static IPv6 configuration -> IPv6 address, set it to any IPv6 address present in the first delegated prefix but the one ending in :1 since it's already used by the Freebox. I put 2a01:xxx:xxx:xxx1::2.
    3. IPv6 Upstream Gateway: put the gateway we created, FreeboxIPv6Gateway.
  2. Interfaces -> LAN:
    1. Generic configuration -> IPv6 Configuration Type, set it to Static IPv6
    2. Static IPv6 configuration -> IPv6 address, set it to any IPv6 address present in the second delegated prefix but the one ending in :1 since it's already used by the Freebox. I put 2a01:xxx:xxx:xxx2::2.

And now comes the salt: in IPv4, one would normally use DHCP to assign IP addresses. In IPv6, one can use DHCPv6 or SLAAC+RDNSS!

Anyway, I'm going with SLAAC only and hoping for the best.

  1. Services -> Router advertisements -> WAN
    1. Router Advertisements -> Router Only, since I use a fixed IPv6 for the WAN interface of the router, and don't provide network access to anything else on this segment.
    2. Advertise Default Gateway, tick the box.
  2. Services -> Router advertisements -> LAN
    1. Router Advertisements -> Stateless, and pray
    2. Advertise Default Gateway, tick the box.
    3. Adversitse Routes, put the second prefix.

Another (mild) wave of saltiness: you need to punch holes into your firewall to allow incoming traffic for ICMPv6, otherwise things might just break. Fear not, there is a whole RFC about what should normally not be dropped, what will be dropped anyway, what a policy should be defined for, and what should be dropped unless a good case can be made, both for Transit Traffic and Local Configuration Traffic. At this point I just wanted things to work, so I courageously just gave up and trusted OPNSense "Automatically generated rules" to take care of this for me.

Oh, and if you have things like Jellyfin, set the firewall to "conservative", otherwise it'll randomly drop your websocket connections, and you'll waste a whole afternoon debugging it.