From 3685affc4c8470db64e3255572ecf4ec999a5987 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 17 Jan 2026 00:05:46 +0200 Subject: Update content for html --- ...5-05-11-f3s-kubernetes-with-freebsd-part-5.html | 274 +++++++++++++++++++- ...5-07-14-f3s-kubernetes-with-freebsd-part-6.html | 1 + gemfeed/atom.xml | 279 ++++++++++++++++++++- 3 files changed, 550 insertions(+), 4 deletions(-) (limited to 'gemfeed') diff --git a/gemfeed/2025-05-11-f3s-kubernetes-with-freebsd-part-5.html b/gemfeed/2025-05-11-f3s-kubernetes-with-freebsd-part-5.html index 896d4e04..80a0173f 100644 --- a/gemfeed/2025-05-11-f3s-kubernetes-with-freebsd-part-5.html +++ b/gemfeed/2025-05-11-f3s-kubernetes-with-freebsd-part-5.html @@ -13,7 +13,7 @@

f3s: Kubernetes with FreeBSD - Part 5: WireGuard mesh network



-Published at 2025-05-11T11:35:57+03:00, last updated Sun 11 Jan 21:33:40 EET 2026
+Published at 2025-05-11T11:35:57+03:00, last updated Thu 15 Jan 19:30:46 EET 2026

This is the fifth blog post about my f3s series for my self-hosting demands in my home lab. f3s? The "f" stands for FreeBSD, and the "3s" stands for k3s, the Kubernetes distribution I will use on FreeBSD-based physical machines.

@@ -61,6 +61,18 @@
  • ⇢ ⇢ Installing the wg0.conf files
  • ⇢ ⇢ Re-generating mesh and installing the wg0.conf files again
  • ⇢ ⇢ Setting up roaming clients
  • +
  • Adding IPv6 support to the mesh
  • +
  • ⇢ ⇢ IPv6 addressing scheme
  • +
  • ⇢ ⇢ Updating the mesh generator for IPv6
  • +
  • ⇢ ⇢ IPv6 NAT on OpenBSD gateways
  • +
  • ⇢ ⇢ Manual OpenBSD interface configuration
  • +
  • ⇢ ⇢ Verifying dual-stack connectivity
  • +
  • ⇢ ⇢ Benefits of dual-stack
  • +
  • Manual gateway failover for roaming clients
  • +
  • ⇢ ⇢ Configuration files for pixel7pro (phone)
  • +
  • ⇢ ⇢ Configuration files for earth (laptop)
  • +
  • ⇢ ⇢ Using manual failover on Android
  • +
  • ⇢ ⇢ Using manual failover on Linux
  • Happy WireGuard-ing
  • Managing Roaming Client Tunnels
  • ⇢ ⇢ Starting and stopping on earth (Fedora laptop)
  • @@ -203,6 +215,17 @@ http://www.gnu.org/software/src-highlite --> 192.168.2.110 blowfish.wg0 blowfish.wg0.wan.buetow.org 192.168.2.111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org + +fd42:beef:cafe:2::130 f0.wg0 f0.wg0.wan.buetow.org +fd42:beef:cafe:2::131 f1.wg0 f1.wg0.wan.buetow.org +fd42:beef:cafe:2::132 f2.wg0 f2.wg0.wan.buetow.org + +fd42:beef:cafe:2::120 r0.wg0 r0.wg0.wan.buetow.org +fd42:beef:cafe:2::121 r1.wg0 r1.wg0.wan.buetow.org +fd42:beef:cafe:2::122 r2.wg0 r2.wg0.wan.buetow.org + +fd42:beef:cafe:2::110 blowfish.wg0 blowfish.wg0.wan.buetow.org +fd42:beef:cafe:2::111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org END
    @@ -256,6 +279,17 @@ http://www.gnu.org/software/src-highlite --> 192.168.2.110 blowfish.wg0 blowfish.wg0.wan.buetow.org 192.168.2.111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org + +fd42:beef:cafe:2::130 f0.wg0 f0.wg0.wan.buetow.org +fd42:beef:cafe:2::131 f1.wg0 f1.wg0.wan.buetow.org +fd42:beef:cafe:2::132 f2.wg0 f2.wg0.wan.buetow.org + +fd42:beef:cafe:2::120 r0.wg0 r0.wg0.wan.buetow.org +fd42:beef:cafe:2::121 r1.wg0 r1.wg0.wan.buetow.org +fd42:beef:cafe:2::122 r2.wg0 r2.wg0.wan.buetow.org + +fd42:beef:cafe:2::110 blowfish.wg0 blowfish.wg0.wan.buetow.org +fd42:beef:cafe:2::111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org END
    @@ -312,6 +346,19 @@ http://www.gnu.org/software/src-highlite --> 192.168.2.111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org 192.168.2.200 earth.wg0 earth.wg0.wan.buetow.org 192.168.2.201 pixel7pro.wg0 pixel7pro.wg0.wan.buetow.org + +fd42:beef:cafe:2::130 f0.wg0 f0.wg0.wan.buetow.org +fd42:beef:cafe:2::131 f1.wg0 f1.wg0.wan.buetow.org +fd42:beef:cafe:2::132 f2.wg0 f2.wg0.wan.buetow.org + +fd42:beef:cafe:2::120 r0.wg0 r0.wg0.wan.buetow.org +fd42:beef:cafe:2::121 r1.wg0 r1.wg0.wan.buetow.org +fd42:beef:cafe:2::122 r2.wg0 r2.wg0.wan.buetow.org + +fd42:beef:cafe:2::110 blowfish.wg0 blowfish.wg0.wan.buetow.org +fd42:beef:cafe:2::111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org +fd42:beef:cafe:2::200 earth.wg0 earth.wg0.wan.buetow.org +fd42:beef:cafe:2::201 pixel7pro.wg0 pixel7pro.wg0.wan.buetow.org END
    @@ -524,6 +571,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.130' + ipv6: 'fd42:beef:cafe:2::130' exclude_peers: - earth - pixel7pro @@ -543,6 +591,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.120' + ipv6: 'fd42:beef:cafe:2::120' exclude_peers: - earth - pixel7pro @@ -562,6 +611,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.110' + ipv6: 'fd42:beef:cafe:2::110' exclude_peers: - earth - pixel7pro @@ -579,6 +629,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.111' + ipv6: 'fd42:beef:cafe:2::111' exclude_peers: - earth - pixel7pro @@ -587,6 +638,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.200' + ipv6: 'fd42:beef:cafe:2::200' exclude_peers: - f0 - f1 @@ -600,6 +652,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.201' + ipv6: 'fd42:beef:cafe:2::201' exclude_peers: - f0 - f1 @@ -939,6 +992,225 @@ http://www.gnu.org/software/src-highlite -->
    The service is disabled from auto-start so the VPN is only active when manually started. This allows selective VPN usage based on need.

    +

    Adding IPv6 support to the mesh


    +
    +After setting up the IPv4-only mesh network, I decided to add dual-stack IPv6 support to enable more networking capabilities and prepare for the future. All 10 hosts (8 infrastructure + 2 roaming clients) now have both IPv4 and IPv6 addresses on their WireGuard interfaces.
    +
    +

    IPv6 addressing scheme


    +
    +We use ULA (Unique Local Address) private IPv6 space, analogous to RFC1918 private IPv4 addresses:
    +
    +
    +All hosts receive dual-stack addresses:
    +
    +
    +fd42:beef:cafe:2::110/64  - blowfish.wg0 (OpenBSD gateway)
    +fd42:beef:cafe:2::111/64  - fishfinger.wg0 (OpenBSD gateway)
    +fd42:beef:cafe:2::120/64  - r0.wg0 (Rocky Linux VM)
    +fd42:beef:cafe:2::121/64  - r1.wg0 (Rocky Linux VM)
    +fd42:beef:cafe:2::122/64  - r2.wg0 (Rocky Linux VM)
    +fd42:beef:cafe:2::130/64  - f0.wg0 (FreeBSD host)
    +fd42:beef:cafe:2::131/64  - f1.wg0 (FreeBSD host)
    +fd42:beef:cafe:2::132/64  - f2.wg0 (FreeBSD host)
    +fd42:beef:cafe:2::200/64  - earth.wg0 (roaming laptop)
    +fd42:beef:cafe:2::201/64  - pixel7pro.wg0 (roaming phone)
    +
    +
    +

    Updating the mesh generator for IPv6


    +
    +The mesh generator required two modifications to support dual-stack configurations:
    +
    +**1. Address generation (address method)**
    +
    +The generator now outputs multiple Address directives when IPv6 is present:
    +
    + +
    def address
    +  return '# No Address = ... for OpenBSD here' if hosts[myself]['os'] == 'OpenBSD'
    +
    +  ipv4 = hosts[myself]['wg0']['ip']
    +  ipv6 = hosts[myself]['wg0']['ipv6']
    +
    +  # WireGuard supports multiple Address directives for dual-stack
    +  if ipv6
    +    "Address = #{ipv4}\nAddress = #{ipv6}/64"
    +  else
    +    "Address = #{ipv4}"
    +  end
    +end
    +
    +
    +**2. AllowedIPs generation (peers method)**
    +
    +For mesh peers, both IPv4 and IPv6 addresses are included in AllowedIPs:
    +
    + +
    if is_roaming
    +  allowed_ips = '0.0.0.0/0, ::/0'
    +else
    +  # For mesh peers, allow both IPv4 and IPv6 if present
    +  ipv4 = data['wg0']['ip']
    +  ipv6 = data['wg0']['ipv6']
    +  allowed_ips = ipv6 ? "#{ipv4}/32, #{ipv6}/128" : "#{ipv4}/32"
    +end
    +
    +
    +Roaming clients keep AllowedIPs = 0.0.0.0/0, ::/0 to route all traffic (IPv4 and IPv6) through the VPN.
    +
    +

    IPv6 NAT on OpenBSD gateways


    +
    +To allow roaming clients to access the internet via IPv6, we added NAT66 rules to the OpenBSD gateways' pf.conf:
    +
    +
    +# NAT for WireGuard clients to access internet (IPv4)
    +match out on vio0 from 192.168.2.0/24 to any nat-to (vio0)
    +
    +# NAT66 for WireGuard clients to access internet (IPv6)
    +# Uses NPTv6 (Network Prefix Translation) to translate ULA to public IPv6
    +match out on vio0 inet6 from fd42:beef:cafe:2::/64 to any nat-to (vio0)
    +
    +# Allow all UDP traffic on WireGuard port (IPv4 and IPv6)
    +pass in inet proto udp from any to any port 56709
    +pass in inet6 proto udp from any to any port 56709
    +
    +
    +OpenBSD's PF firewall supports IPv6 NAT with the same syntax as IPv4, using NPTv6 (RFC 6296) to translate the ULA addresses to the gateway's public IPv6 address.
    +
    +

    Manual OpenBSD interface configuration


    +
    +Since OpenBSD doesn't use the Address directive in WireGuard configs, IPv6 must be manually configured on the wg0 interfaces. On blowfish:
    +
    + +
    rex@blowfish:~ $ doas vi /etc/hostname.wg0
    +
    +
    +Add the IPv6 address (note the order - IPv6 must be configured before up):
    +
    +
    +inet 192.168.2.110 255.255.255.0 NONE
    +inet6 fd42:beef:cafe:2::110 64
    +up
    +!/usr/local/bin/wg setconf wg0 /etc/wireguard/wg0.conf
    +
    +
    +**Important**: The IPv6 address must be specified before the up directive. This ensures the interface has both addresses configured before WireGuard peers are loaded.
    +
    +Apply the configuration:
    +
    + +
    rex@blowfish:~ $ doas sh /etc/netstart wg0
    +rex@blowfish:~ $ ifconfig wg0 | grep inet6
    +inet6 fd42:beef:cafe:2::110 prefixlen 64
    +
    +
    +Repeat for fishfinger with address fd42:beef:cafe:2::111.
    +
    +After reboot, the interface will automatically come up with both IPv4 and IPv6 addresses. WireGuard peers may take 30-60 seconds to establish handshakes after boot.
    +
    +

    Verifying dual-stack connectivity


    +
    +After regenerating and deploying the configurations, both IPv4 and IPv6 work across the mesh:
    +
    + +
    # From r0 (Rocky Linux VM)
    +root@r0:~ # ping -c 2 192.168.2.130  # IPv4 to f0
    +64 bytes from 192.168.2.130: icmp_seq=1 ttl=64 time=2.12 ms
    +64 bytes from 192.168.2.130: icmp_seq=2 ttl=64 time=0.681 ms
    +
    +root@r0:~ # ping6 -c 2 fd42:beef:cafe:2::130  # IPv6 to f0
    +64 bytes from fd42:beef:cafe:2::130: icmp_seq=1 ttl=64 time=2.16 ms
    +64 bytes from fd42:beef:cafe:2::130: icmp_seq=2 ttl=64 time=0.909 ms
    +
    +
    +The dual-stack configuration is backward compatible—hosts without the ipv6 field in the YAML configuration will continue to generate IPv4-only configs.
    +
    +

    Benefits of dual-stack


    +
    +Adding IPv6 to the mesh network provides:
    +
    +
    +

    Manual gateway failover for roaming clients


    +
    +WireGuard doesn't automatically failover between multiple peers with identical AllowedIPs routes. When both gateways (blowfish and fishfinger) are configured with AllowedIPs = 0.0.0.0/0, ::/0, WireGuard uses the first peer with a recent handshake. If that gateway goes down, traffic won't automatically switch to the backup.
    +
    +To enable manual failover, separate configuration files have been created for roaming clients (earth laptop and pixel7pro phone), each containing only a single gateway peer.
    +
    +

    Configuration files for pixel7pro (phone)


    +
    +Two separate configs in /home/paul/git/wireguardmeshgenerator/dist/pixel7pro/etc/wireguard/:
    +
    +
    +

    Configuration files for earth (laptop)


    +
    +Two separate configs in /home/paul/git/wireguardmeshgenerator/dist/earth/etc/wireguard/:
    +
    +
    +

    Using manual failover on Android


    +
    +On the pixel7pro phone, import both QR codes using the WireGuard app to create two separate tunnel profiles:
    +
    + +
    # Generate QR codes
    +qrencode -t ansiutf8 < dist/pixel7pro/etc/wireguard/wg0-blowfish.conf
    +qrencode -t ansiutf8 < dist/pixel7pro/etc/wireguard/wg0-fishfinger.conf
    +
    +
    +In the WireGuard app, you can then manually enable/disable each tunnel to select which gateway to use. Only enable one tunnel at a time.
    +
    +

    Using manual failover on Linux


    +
    +On the earth laptop, copy both configs and use systemd to switch between them:
    +
    + +
    # Install both configurations
    +sudo cp dist/earth/etc/wireguard/wg0-blowfish.conf /etc/wireguard/
    +sudo cp dist/earth/etc/wireguard/wg0-fishfinger.conf /etc/wireguard/
    +
    +# Start with blowfish gateway
    +sudo systemctl start wg-quick@wg0-blowfish.service
    +
    +# To switch to fishfinger gateway
    +sudo systemctl stop wg-quick@wg0-blowfish.service
    +sudo systemctl start wg-quick@wg0-fishfinger.service
    +
    +
    +This approach provides explicit control over which gateway handles roaming client traffic, useful when one gateway needs maintenance or experiences connectivity issues.
    +

    Happy WireGuard-ing



    All is set up now. E.g. on f0:
    diff --git a/gemfeed/2025-07-14-f3s-kubernetes-with-freebsd-part-6.html b/gemfeed/2025-07-14-f3s-kubernetes-with-freebsd-part-6.html index a9aaa5fb..fe828914 100644 --- a/gemfeed/2025-07-14-f3s-kubernetes-with-freebsd-part-6.html +++ b/gemfeed/2025-07-14-f3s-kubernetes-with-freebsd-part-6.html @@ -1008,6 +1008,7 @@ ifconfig_re0_alias0="inet vhid 1 advskew 100 pass testpass
     192.168.2.138 f3s-storage-ha f3s-storage-ha.wg0 f3s-storage-ha.wg0.wan.buetow.org
    +fd42:beef:cafe:2::138 f3s-storage-ha f3s-storage-ha.wg0 f3s-storage-ha.wg0.wan.buetow.org
     

    This allows clients to connect to f3s-storage-ha regardless of which physical server is currently the MASTER.
    diff --git a/gemfeed/atom.xml b/gemfeed/atom.xml index d24610e7..92baa74d 100644 --- a/gemfeed/atom.xml +++ b/gemfeed/atom.xml @@ -1,6 +1,6 @@ - 2026-01-11T22:40:26+02:00 + 2026-01-17T00:03:44+02:00 foo.zone feed To be in the .zone! @@ -7454,6 +7454,7 @@ ifconfig_re0_alias0="inet vhid 1 advskew 100 pass testpass
     192.168.2.138 f3s-storage-ha f3s-storage-ha.wg0 f3s-storage-ha.wg0.wan.buetow.org
    +fd42:beef:cafe:2::138 f3s-storage-ha f3s-storage-ha.wg0 f3s-storage-ha.wg0.wan.buetow.org
     

    This allows clients to connect to f3s-storage-ha regardless of which physical server is currently the MASTER.
    @@ -9566,7 +9567,7 @@ Jul 06 10:f3s: Kubernetes with FreeBSD - Part 5: WireGuard mesh network https://foo.zone/gemfeed/2025-05-11-f3s-kubernetes-with-freebsd-part-5.html - 2025-05-11T11:35:57+03:00, last updated Sun 11 Jan 21:33:40 EET 2026 + 2025-05-11T11:35:57+03:00, last updated Thu 15 Jan 19:30:46 EET 2026 Paul Buetow aka snonux paul@dev.buetow.org @@ -9576,7 +9577,7 @@ Jul 06 10:

    f3s: Kubernetes with FreeBSD - Part 5: WireGuard mesh network



    -Published at 2025-05-11T11:35:57+03:00, last updated Sun 11 Jan 21:33:40 EET 2026
    +Published at 2025-05-11T11:35:57+03:00, last updated Thu 15 Jan 19:30:46 EET 2026

    This is the fifth blog post about my f3s series for my self-hosting demands in my home lab. f3s? The "f" stands for FreeBSD, and the "3s" stands for k3s, the Kubernetes distribution I will use on FreeBSD-based physical machines.

    @@ -9624,6 +9625,18 @@ Jul 06 10:⇢ ⇢ Installing the wg0.conf files
  • ⇢ ⇢ Re-generating mesh and installing the wg0.conf files again
  • ⇢ ⇢ Setting up roaming clients
  • +
  • Adding IPv6 support to the mesh
  • +
  • ⇢ ⇢ IPv6 addressing scheme
  • +
  • ⇢ ⇢ Updating the mesh generator for IPv6
  • +
  • ⇢ ⇢ IPv6 NAT on OpenBSD gateways
  • +
  • ⇢ ⇢ Manual OpenBSD interface configuration
  • +
  • ⇢ ⇢ Verifying dual-stack connectivity
  • +
  • ⇢ ⇢ Benefits of dual-stack
  • +
  • Manual gateway failover for roaming clients
  • +
  • ⇢ ⇢ Configuration files for pixel7pro (phone)
  • +
  • ⇢ ⇢ Configuration files for earth (laptop)
  • +
  • ⇢ ⇢ Using manual failover on Android
  • +
  • ⇢ ⇢ Using manual failover on Linux
  • Happy WireGuard-ing
  • Managing Roaming Client Tunnels
  • ⇢ ⇢ Starting and stopping on earth (Fedora laptop)
  • @@ -9766,6 +9779,17 @@ http://www.gnu.org/software/src-highlite --> 192.168.2.110 blowfish.wg0 blowfish.wg0.wan.buetow.org 192.168.2.111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org + +fd42:beef:cafe:2::130 f0.wg0 f0.wg0.wan.buetow.org +fd42:beef:cafe:2::131 f1.wg0 f1.wg0.wan.buetow.org +fd42:beef:cafe:2::132 f2.wg0 f2.wg0.wan.buetow.org + +fd42:beef:cafe:2::120 r0.wg0 r0.wg0.wan.buetow.org +fd42:beef:cafe:2::121 r1.wg0 r1.wg0.wan.buetow.org +fd42:beef:cafe:2::122 r2.wg0 r2.wg0.wan.buetow.org + +fd42:beef:cafe:2::110 blowfish.wg0 blowfish.wg0.wan.buetow.org +fd42:beef:cafe:2::111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org END
    @@ -9819,6 +9843,17 @@ http://www.gnu.org/software/src-highlite --> 192.168.2.110 blowfish.wg0 blowfish.wg0.wan.buetow.org 192.168.2.111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org + +fd42:beef:cafe:2::130 f0.wg0 f0.wg0.wan.buetow.org +fd42:beef:cafe:2::131 f1.wg0 f1.wg0.wan.buetow.org +fd42:beef:cafe:2::132 f2.wg0 f2.wg0.wan.buetow.org + +fd42:beef:cafe:2::120 r0.wg0 r0.wg0.wan.buetow.org +fd42:beef:cafe:2::121 r1.wg0 r1.wg0.wan.buetow.org +fd42:beef:cafe:2::122 r2.wg0 r2.wg0.wan.buetow.org + +fd42:beef:cafe:2::110 blowfish.wg0 blowfish.wg0.wan.buetow.org +fd42:beef:cafe:2::111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org END
    @@ -9875,6 +9910,19 @@ http://www.gnu.org/software/src-highlite --> 192.168.2.111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org 192.168.2.200 earth.wg0 earth.wg0.wan.buetow.org 192.168.2.201 pixel7pro.wg0 pixel7pro.wg0.wan.buetow.org + +fd42:beef:cafe:2::130 f0.wg0 f0.wg0.wan.buetow.org +fd42:beef:cafe:2::131 f1.wg0 f1.wg0.wan.buetow.org +fd42:beef:cafe:2::132 f2.wg0 f2.wg0.wan.buetow.org + +fd42:beef:cafe:2::120 r0.wg0 r0.wg0.wan.buetow.org +fd42:beef:cafe:2::121 r1.wg0 r1.wg0.wan.buetow.org +fd42:beef:cafe:2::122 r2.wg0 r2.wg0.wan.buetow.org + +fd42:beef:cafe:2::110 blowfish.wg0 blowfish.wg0.wan.buetow.org +fd42:beef:cafe:2::111 fishfinger.wg0 fishfinger.wg0.wan.buetow.org +fd42:beef:cafe:2::200 earth.wg0 earth.wg0.wan.buetow.org +fd42:beef:cafe:2::201 pixel7pro.wg0 pixel7pro.wg0.wan.buetow.org END
    @@ -10087,6 +10135,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.130' + ipv6: 'fd42:beef:cafe:2::130' exclude_peers: - earth - pixel7pro @@ -10106,6 +10155,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.120' + ipv6: 'fd42:beef:cafe:2::120' exclude_peers: - earth - pixel7pro @@ -10125,6 +10175,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.110' + ipv6: 'fd42:beef:cafe:2::110' exclude_peers: - earth - pixel7pro @@ -10142,6 +10193,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.111' + ipv6: 'fd42:beef:cafe:2::111' exclude_peers: - earth - pixel7pro @@ -10150,6 +10202,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.200' + ipv6: 'fd42:beef:cafe:2::200' exclude_peers: - f0 - f1 @@ -10163,6 +10216,7 @@ hosts: wg0: domain: 'wg0.wan.buetow.org' ip: '192.168.2.201' + ipv6: 'fd42:beef:cafe:2::201' exclude_peers: - f0 - f1 @@ -10502,6 +10556,225 @@ http://www.gnu.org/software/src-highlite -->
    The service is disabled from auto-start so the VPN is only active when manually started. This allows selective VPN usage based on need.

    +

    Adding IPv6 support to the mesh


    +
    +After setting up the IPv4-only mesh network, I decided to add dual-stack IPv6 support to enable more networking capabilities and prepare for the future. All 10 hosts (8 infrastructure + 2 roaming clients) now have both IPv4 and IPv6 addresses on their WireGuard interfaces.
    +
    +

    IPv6 addressing scheme


    +
    +We use ULA (Unique Local Address) private IPv6 space, analogous to RFC1918 private IPv4 addresses:
    +
    +
      +
    • Prefix: fd42:beef:cafe::/48
    • +
    • Subnet: fd42:beef:cafe:2::/64 (wg0 interfaces)
    • +

    +All hosts receive dual-stack addresses:
    +
    +
    +fd42:beef:cafe:2::110/64  - blowfish.wg0 (OpenBSD gateway)
    +fd42:beef:cafe:2::111/64  - fishfinger.wg0 (OpenBSD gateway)
    +fd42:beef:cafe:2::120/64  - r0.wg0 (Rocky Linux VM)
    +fd42:beef:cafe:2::121/64  - r1.wg0 (Rocky Linux VM)
    +fd42:beef:cafe:2::122/64  - r2.wg0 (Rocky Linux VM)
    +fd42:beef:cafe:2::130/64  - f0.wg0 (FreeBSD host)
    +fd42:beef:cafe:2::131/64  - f1.wg0 (FreeBSD host)
    +fd42:beef:cafe:2::132/64  - f2.wg0 (FreeBSD host)
    +fd42:beef:cafe:2::200/64  - earth.wg0 (roaming laptop)
    +fd42:beef:cafe:2::201/64  - pixel7pro.wg0 (roaming phone)
    +
    +
    +

    Updating the mesh generator for IPv6


    +
    +The mesh generator required two modifications to support dual-stack configurations:
    +
    +**1. Address generation (address method)**
    +
    +The generator now outputs multiple Address directives when IPv6 is present:
    +
    + +
    def address
    +  return '# No Address = ... for OpenBSD here' if hosts[myself]['os'] == 'OpenBSD'
    +
    +  ipv4 = hosts[myself]['wg0']['ip']
    +  ipv6 = hosts[myself]['wg0']['ipv6']
    +
    +  # WireGuard supports multiple Address directives for dual-stack
    +  if ipv6
    +    "Address = #{ipv4}\nAddress = #{ipv6}/64"
    +  else
    +    "Address = #{ipv4}"
    +  end
    +end
    +
    +
    +**2. AllowedIPs generation (peers method)**
    +
    +For mesh peers, both IPv4 and IPv6 addresses are included in AllowedIPs:
    +
    + +
    if is_roaming
    +  allowed_ips = '0.0.0.0/0, ::/0'
    +else
    +  # For mesh peers, allow both IPv4 and IPv6 if present
    +  ipv4 = data['wg0']['ip']
    +  ipv6 = data['wg0']['ipv6']
    +  allowed_ips = ipv6 ? "#{ipv4}/32, #{ipv6}/128" : "#{ipv4}/32"
    +end
    +
    +
    +Roaming clients keep AllowedIPs = 0.0.0.0/0, ::/0 to route all traffic (IPv4 and IPv6) through the VPN.
    +
    +

    IPv6 NAT on OpenBSD gateways


    +
    +To allow roaming clients to access the internet via IPv6, we added NAT66 rules to the OpenBSD gateways' pf.conf:
    +
    +
    +# NAT for WireGuard clients to access internet (IPv4)
    +match out on vio0 from 192.168.2.0/24 to any nat-to (vio0)
    +
    +# NAT66 for WireGuard clients to access internet (IPv6)
    +# Uses NPTv6 (Network Prefix Translation) to translate ULA to public IPv6
    +match out on vio0 inet6 from fd42:beef:cafe:2::/64 to any nat-to (vio0)
    +
    +# Allow all UDP traffic on WireGuard port (IPv4 and IPv6)
    +pass in inet proto udp from any to any port 56709
    +pass in inet6 proto udp from any to any port 56709
    +
    +
    +OpenBSD's PF firewall supports IPv6 NAT with the same syntax as IPv4, using NPTv6 (RFC 6296) to translate the ULA addresses to the gateway's public IPv6 address.
    +
    +

    Manual OpenBSD interface configuration


    +
    +Since OpenBSD doesn't use the Address directive in WireGuard configs, IPv6 must be manually configured on the wg0 interfaces. On blowfish:
    +
    + +
    rex@blowfish:~ $ doas vi /etc/hostname.wg0
    +
    +
    +Add the IPv6 address (note the order - IPv6 must be configured before up):
    +
    +
    +inet 192.168.2.110 255.255.255.0 NONE
    +inet6 fd42:beef:cafe:2::110 64
    +up
    +!/usr/local/bin/wg setconf wg0 /etc/wireguard/wg0.conf
    +
    +
    +**Important**: The IPv6 address must be specified before the up directive. This ensures the interface has both addresses configured before WireGuard peers are loaded.
    +
    +Apply the configuration:
    +
    + +
    rex@blowfish:~ $ doas sh /etc/netstart wg0
    +rex@blowfish:~ $ ifconfig wg0 | grep inet6
    +inet6 fd42:beef:cafe:2::110 prefixlen 64
    +
    +
    +Repeat for fishfinger with address fd42:beef:cafe:2::111.
    +
    +After reboot, the interface will automatically come up with both IPv4 and IPv6 addresses. WireGuard peers may take 30-60 seconds to establish handshakes after boot.
    +
    +

    Verifying dual-stack connectivity


    +
    +After regenerating and deploying the configurations, both IPv4 and IPv6 work across the mesh:
    +
    + +
    # From r0 (Rocky Linux VM)
    +root@r0:~ # ping -c 2 192.168.2.130  # IPv4 to f0
    +64 bytes from 192.168.2.130: icmp_seq=1 ttl=64 time=2.12 ms
    +64 bytes from 192.168.2.130: icmp_seq=2 ttl=64 time=0.681 ms
    +
    +root@r0:~ # ping6 -c 2 fd42:beef:cafe:2::130  # IPv6 to f0
    +64 bytes from fd42:beef:cafe:2::130: icmp_seq=1 ttl=64 time=2.16 ms
    +64 bytes from fd42:beef:cafe:2::130: icmp_seq=2 ttl=64 time=0.909 ms
    +
    +
    +The dual-stack configuration is backward compatible—hosts without the ipv6 field in the YAML configuration will continue to generate IPv4-only configs.
    +
    +

    Benefits of dual-stack


    +
    +Adding IPv6 to the mesh network provides:
    +
    +
      +
    • **Future-proofing**: Ready for IPv6-only services and networks
    • +
    • **Compatibility**: Dual-stack maintains full IPv4 compatibility
    • +
    • **Learning**: Hands-on experience with IPv6 networking
    • +
    • **Flexibility**: Roaming clients can access both IPv4 and IPv6 internet resources
    • +

    +

    Manual gateway failover for roaming clients


    +
    +WireGuard doesn't automatically failover between multiple peers with identical AllowedIPs routes. When both gateways (blowfish and fishfinger) are configured with AllowedIPs = 0.0.0.0/0, ::/0, WireGuard uses the first peer with a recent handshake. If that gateway goes down, traffic won't automatically switch to the backup.
    +
    +To enable manual failover, separate configuration files have been created for roaming clients (earth laptop and pixel7pro phone), each containing only a single gateway peer.
    +
    +

    Configuration files for pixel7pro (phone)


    +
    +Two separate configs in /home/paul/git/wireguardmeshgenerator/dist/pixel7pro/etc/wireguard/:
    +
    +
      +
    • **wg0-blowfish.conf** - Routes all traffic through blowfish gateway (23.88.35.144)
    • +
    • **wg0-fishfinger.conf** - Routes all traffic through fishfinger gateway (46.23.94.99)
    • +

    +

    Configuration files for earth (laptop)


    +
    +Two separate configs in /home/paul/git/wireguardmeshgenerator/dist/earth/etc/wireguard/:
    +
    +
      +
    • **wg0-blowfish.conf** - Routes all traffic through blowfish gateway
    • +
    • **wg0-fishfinger.conf** - Routes all traffic through fishfinger gateway
    • +

    +

    Using manual failover on Android


    +
    +On the pixel7pro phone, import both QR codes using the WireGuard app to create two separate tunnel profiles:
    +
    + +
    # Generate QR codes
    +qrencode -t ansiutf8 < dist/pixel7pro/etc/wireguard/wg0-blowfish.conf
    +qrencode -t ansiutf8 < dist/pixel7pro/etc/wireguard/wg0-fishfinger.conf
    +
    +
    +In the WireGuard app, you can then manually enable/disable each tunnel to select which gateway to use. Only enable one tunnel at a time.
    +
    +

    Using manual failover on Linux


    +
    +On the earth laptop, copy both configs and use systemd to switch between them:
    +
    + +
    # Install both configurations
    +sudo cp dist/earth/etc/wireguard/wg0-blowfish.conf /etc/wireguard/
    +sudo cp dist/earth/etc/wireguard/wg0-fishfinger.conf /etc/wireguard/
    +
    +# Start with blowfish gateway
    +sudo systemctl start wg-quick@wg0-blowfish.service
    +
    +# To switch to fishfinger gateway
    +sudo systemctl stop wg-quick@wg0-blowfish.service
    +sudo systemctl start wg-quick@wg0-fishfinger.service
    +
    +
    +This approach provides explicit control over which gateway handles roaming client traffic, useful when one gateway needs maintenance or experiences connectivity issues.
    +

    Happy WireGuard-ing



    All is set up now. E.g. on f0:
    -- cgit v1.2.3