marfillaster · notes

Build log · MikroTik RB5009 · Route64, no VPS

Routed IPv6 for a segmented IPv4-only LAN behind CGNAT

Free routed /56 over Route64's WireGuard tunnel — a native global /64 per VLAN, no VPS, with a fast fail-to-IPv4 on outage.

Overview

The Route64 path in the MikroTik RB5009 home-network series: recover real, routable IPv6 over a CGNAT'd line using the free Route64 broker's WireGuard tunnel and a routed /56. Nothing recurring, no endpoint to operate. The sibling — a self-operated VPS routing a /48 — is its own post: Routed IPv6 over CGNAT via a VPS. Read the index's path-choice matrix first if you have not decided between them.

This post assumes you already have a working, segmented IPv4 LAN behind carrier-grade NAT — VLANs, inter-VLAN firewall, DHCP — from the VLAN companion post.

Route64 hands out a routed /56 over WireGuard. Because the transport is plain outbound UDP, it traverses residential CGNAT — verified on a live Converge line, not inferred. A /56 is 256 /64s: enough to give every VLAN its own native global prefix straight from the delegation, with no helper daemon and no second prefix for clients to choose between. The single trade-off is designed-for: Route64 is the only IPv6 uplink, so when it is down the LAN fails fast and cleanly back to IPv4 rather than blackholing.

Every numbered section is paste-ready against a RouterOS v7 box that already has the VLAN segmentation from the companion post. The italic notes are the rationale — the trade-off being made and why.

1. Topology and what you need first

                     Internet (IPv4 + IPv6)
                            │
              ┌─────────────┴─────────────┐
              │   Route64 PoP (WireGuard) │
              │   routes a /56 to you     │
              └─────────────┬─────────────┘
                            │ WireGuard / outbound UDP
                            │ (only IPv6 transits the tunnel)
              ┌─────────────┴─────────────┐
              │   Residential fiber+CGNAT │
              │   (IPv4 outbound only)    │
              └─────────────┬─────────────┘
                            │
                ┌───────────┴───────────┐
                │     home router       │
                │  wg-route64  ::2/64   │  ← tunnel link
                │  bridge   <56>:1::1   │  ← LAN  GUA + ULA
                │  vlan-iot <56>:10::1  │  ← IoT  GUA + ULA
                │  vlan-gst <56>:20::1  │  ← Guest GUA + ULA
                └───────────────────────┘

This post starts where the segmentation post ends. You should already have: the bridge/vlan-iot/vlan-guest interfaces, the IPv4 inter-VLAN firewall, per-VLAN DHCPv4, and a working DoH resolver advertised on a ULA. If you do not, build the VLAN companion post and the DNS companion post first; only the IPv6 layer differs here.

2. Conventions and placeholders

Substitute every <PLACEHOLDER> before pasting. Comments are single tokens so the netwatch scripts need no nested quotes.

PlaceholderMeaning
<R64_PRIVKEY>Client (home router) WireGuard private key from the Route64 tunnel page.
<R64_SRV_PUBKEY>Route64 server public key.
<R64_POP_IP>Route64 PoP endpoint IPv4.
<R64_POP_PORT>Route64 PoP endpoint UDP port (also the local listen-port).
<R64_LINK>Tunnel-link /64 prefix. Client is <R64_LINK>::2, gateway <R64_LINK>::1.
<R64_56>Routed /56 written without its trailing subnet byte, e.g. 2001:db8:abcd:c0.
<ULA_PREFIX>Your locally-generated ULA, e.g. fd96:7d0b:7dc2. Same one the DNS section uses.
<R64_TUNNEL_ID>Numeric Route64 tunnel ID (DynDNS hostname).
<R64_USER> / <R64_APIKEY>Route64 account user and API key for the DynDNS endpoint.

<R64_56> is the one to read carefully. Route64 delegates a /56 such as 2001:db8:abcd:c000::/56; the usable LAN /64s are 2001:db8:abcd:c001::/642001:db8:abcd:c0ff::/64. Write <R64_56> as the part before the subnet byte (2001:db8:abcd:c0) so <R64_56>01::1 expands to 2001:db8:abcd:c001::1. This guide uses 01/10/20 to echo the VLAN numbering.

3. Route64 dashboard

Create a tunnel of type WireGuard and note: the PoP endpoint:port, the server public key, the client private key, the tunnel-link /64 (the point-to-point pair, client ::2, gateway ::1), the routed /56 delegated for LAN use — a different prefix from the link /64 — the numeric tunnel ID, and an API key for the DynDNS endpoint. The portal asks for a public IPv4; behind CGNAT that value is not used (see the design note above).

4. WireGuard client

The home router always initiates; ::/0 in allowed-address lets the peer carry any IPv6 (the path is a routing decision, not set here). The tunnel-link address is advertise=no — it is point-to-point, no SLAAC.

bash

bash

/interface/wireguard add name=wg-route64 mtu=1420 \
    listen-port=<R64_POP_PORT> private-key="<R64_PRIVKEY>"
/interface/wireguard/peers add interface=wg-route64 \
    public-key="<R64_SRV_PUBKEY>" \
    endpoint-address=<R64_POP_IP> endpoint-port=<R64_POP_PORT> \
    allowed-address=::/0 persistent-keepalive=15s
/ipv6/address add address=<R64_LINK>::2/64 interface=wg-route64 advertise=no

There is no second IPv6 path, so the Route64 default is just the default.

bash

bash

/ipv6/route add dst-address=::/0 gateway=<R64_LINK>::1%wg-route64 \
    distance=1 comment=r64def

6. Fast fail-to-IPv4

netwatch probes Cloudflare's IPv6 anycast on TCP 443 — reachable only through the Route64 default. On failure it sets ra-lifetime=0 on every GUA-bearing VLAN. A Router Lifetime of zero tells hosts "I am not a default router": they purge the IPv6 default and Happy Eyeballs to IPv4 within seconds. On recovery it restores ra-lifetime=30m. The default route stays installed throughout — only the Router Lifetime toggles.

bash

bash

/tool/netwatch add name=r64health type=tcp-conn \
    host=2606:4700:4700::1111 port=443 \
    interval=5s timeout=2s comment=r64health \
    up-script="/ipv6/nd set [find interface=bridge] ra-lifetime=30m; /ipv6/nd set [find interface=vlan-iot] ra-lifetime=30m; /ipv6/nd set [find interface=vlan-guest] ra-lifetime=30m; :log info route64-up" \
    down-script="/ipv6/nd set [find interface=bridge] ra-lifetime=0s; /ipv6/nd set [find interface=vlan-iot] ra-lifetime=0s; /ipv6/nd set [find interface=vlan-guest] ra-lifetime=0s; :log info route64-down-failedtoIPv4"

The set [find interface=...] lines are no-ops until the per-VLAN ND entries exist; they start working as soon as the Per-VLAN IPv6 post is applied (substitution: <GUA_LAN>=<R64_56>01, <GUA_IOT>=<R64_56>10, <GUA_GUEST>=<R64_56>20).

After the index §5 ULA-only update strips Guest's GUA, the vlan-guest line above becomes a no-op (the VLAN has no global default to withdraw); leave it in for symmetry or drop it.

7. DynDNS hygiene (optional)

Not required — the tunnel survives a wrong pin on both established and cold handshakes. Kept only to keep the portal accurate, on a 15-minute scheduler (Route64 rate-limits endpoint changes to one per 10 min; nochg is unmetered, so 15 min never trips it). start-time=startup corrects a stale pin after a reboot.

bash

bash

/system/script add name=route64-ddns source=":do { :local r [/tool fetch url=\"https://manager.route64.org/nic/update?hostname=<R64_TUNNEL_ID>\" user=\"<R64_USER>\" password=\"<R64_APIKEY>\" mode=https output=user as-value]; :log info (\"route64-ddns: \" . (\$r->\"data\")); } on-error={ :log warning \"route64-ddns: fetch error\"; }"
/system/scheduler add name=route64-ddns start-time=startup interval=15m \
    on-event="/system/script/run route64-ddns"

8. Tunnel-side verification

The checks below prove the WireGuard tunnel, the default route, and the netwatch are correct. LAN-side checks (client GUA, ping6 from a VLAN, anti-spoof drop counter) live in the Per-VLAN IPv6 post; the one-glance path-agnostic check is the screenshot at the index §7.

bash

bash

# Tunnel handshake is recent and bytes are moving
/interface/wireguard/peers print where interface=wg-route64

# Egress from the router itself — proves native routing through the tunnel
/ping 2606:4700:4700::1111 count=4

# Single default, via Route64
/ipv6/route print where dst-address=::/0

# netwatch health + the fail/recover log trail
/tool/netwatch print where comment=r64health
/log/print where message~"route64-(up|down)"

Pulling the WireGuard peer's endpoint (or briefly disabling wg-route64) should produce a route64-down-failedtoIPv4 log line within ~8 s. The full ≈40 s client-side failover lands once per-VLAN IPv6 is in place — see that post's verification block.

9. Caveats

  • Single uplink. A Route64 outage is a full IPv6 outage; the network fails fast to IPv4 by design.
  • Inbound reachability is best-effort. Inbound v6 to the GUA does work — verified end-to-end on this build — and Route64's ToS does not forbid running listeners. What it does not promise is service levels (§10): the path runs through a broker PoP, so reachability is only as good as the broker's. Fine for personal-grade services; for anything you would page on, put a self-operated relay in front.
  • Throughput cap. Route64's ToS §14 documents "up to 200M throughput often more," extendable via donations. Fine for general home egress; sized below modern fiber peak.
  • No filesharing. Route64's ToS §6 explicitly forbids "bittorent or similar" filesharing over the tunnel. Run those over native IPv4.
  • ULA addressing survives an outage; routed IPv6 does not. Hosts keep their <ULA_PREFIX> addresses and same-VLAN/​on-link IPv6 (including the ULA DNS resolver) through a Route64 outage.
  • /56, not /48. 256 /64s — ample for a home's VLANs. A /48's 65k only matters if you sub-delegate at scale, which a home LAN does not.
  • Free broker. No SLA (ToS §10), no portal 2FA at time of writing, and use is governed by Route64's terms of service. Acceptable for a home LAN's egress IPv6; weigh it for anything you care about.

If you'd rather run this path alongside the VPS path under one announceable /48 with BGP best-path failover, see Multi-homing IPv6 over CGNAT on RouterOS — the series finale. It replaces the WAN-side plumbing of this post with a self-contained multi-homed build (own ASN, announceable /48 as hard prerequisites); Route64 keeps its single-uplink role here and becomes the backup BGP session there.

References

Share

Comments

View or add comments