Benutzer-Werkzeuge

Webseiten-Werkzeuge


public:wg-fallback-v6-v4

Reverse WireGuard Endpoint Fallback (extended version)

This article only makes sense if you refer to the initial one first (incase you havn't, here the link)

Problem

Many public networks (hotel WiFi, train WiFi, public hotspots, etc.) are IPv4-only or apply strict filtering policies for UDP traffic.

If a WireGuard endpoint is reachable only via IPv6, clients in such networks cannot establish the tunnel.

Goal of this design:

  • Prefer IPv6 connectivity
  • Provide automatic IPv4 fallback
  • Use only one public endpoint hostname
  • Keep the actual WireGuard service running on a single host

Architecture

The actual WireGuard service runs on a dedicated host (called wg-end).

The firewall only provides an IPv4 port forward.

Internet Client
      │
      │ IPv6 available
      ▼
   wg-end (WireGuard endpoint)

or

Internet Client
      │
      │ IPv4 only
      ▼
Firewall (DNAT)
      │
      ▼
   wg-end (WireGuard endpoint)

DNS Design

A single endpoint hostname is used that resolves differently depending on the IP protocol.

firewall.random.tld
    A     → firewall IPv4
    AAAA  → wg-end IPv6

wg-end.random.tld
    AAAA  → wg-end IPv6

Resulting connection paths:

Client network Connection path
IPv6 available direct connection to wg-end
IPv4 only firewall → DNAT → wg-end

WireGuard client configuration:

Endpoint = firewall.random.tld:51820

Firewall

IPv4 forwarding:

WAN UDP 51820 → DNAT → wg-end:51820

IPv6 handling:

No NAT is required. Only a firewall rule permitting access to the endpoint host.

allow udp any → wg-end.random.tld port 51820

DynDNS Concept

The IPv6 DynDNS updater writes two AAAA records simultaneously.

wg-end.random.tld     AAAA → wg-end IPv6
firewall.random.tld   AAAA → wg-end IPv6

IPv4 DynDNS remains unchanged:

firewall.random.tld   A → firewall IPv4

This automatically makes firewall.random.tld (FAKE) dual-stack.

DynDNS Script

/usr/local/sbin/ovh-dyndns-v6.sh

#!/usr/bin/env bash
set -euo pipefail
 
CONF=/etc/ovh-dyndns-v6.conf
source "$CONF"
 
GUA="$(/usr/local/sbin/fetch-gua.sh)"
 
[ -n "$GUA" ] || {
    logger -t ovh-dyndns-v6 "ERROR: no GUA"
    exit 2
}
 
export OVH_ENDPOINT OVH_APP_KEY OVH_APP_SECRET OVH_CONSUMER_KEY
export OVH_ZONE TTL
export GUA
 
TARGETS=("${RECORD_FQDNS[@]}")
 
for fqdn in "${TARGETS[@]}"; do
    export RECORD_FQDN="$fqdn"
 
    OUT="$(
        /opt/ovh-dyndns-v6/venv/bin/python \
        /opt/ovh-dyndns-v6/update_aaaa.py
    )"
 
    logger -t ovh-dyndns-v6 "$OUT fqdn=$fqdn"
    echo "$OUT fqdn=$fqdn"
done

DynDNS Configuration

/etc/ovh-dyndns-v6.conf

OVH_ENDPOINT="ovh-eu"
 
OVH_APP_KEY="secret"
OVH_APP_SECRET="secret"
OVH_CONSUMER_KEY="secret"
 
OVH_ZONE="random.tld"
 
TTL=300
 
RECORD_FQDNS=(
  "wg-end.random.tld"
  "firewall.random.tld"
)
 
IFACE="ens18"

systemd Service

/etc/systemd/system/ovh-dyndns-v6.service

[Unit]
Description=Update OVH IPv6 DynDNS

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/ovh-dyndns-v6.sh

systemd Timer

/etc/systemd/system/ovh-dyndns-v6.timer

[Unit]
Description=Run OVH IPv6 DynDNS updater every 5 minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
AccuracySec=30s
Persistent=true

[Install]
WantedBy=timers.target

Enable the timer:

systemctl daemon-reload
systemctl enable --now ovh-dyndns-v6.timer

DNS Verification

dig +short A firewall.random.tld
dig +short AAAA firewall.random.tld
dig +short AAAA wg-end.random.tld

Expected result:

firewall.random.tld   A     → firewall IPv4
firewall.random.tld   AAAA  → wg-end IPv6
wg-end.random.tld     AAAA  → wg-end IPv6

WireGuard Verification

wg show

IPv6 transport:

endpoint: [2003:xxxx:...]:51820

IPv4 fallback:

endpoint: 203.x.x.x:51820

Result

This architecture provides:

  • IPv6-first WireGuard connectivity
  • automatic IPv4 fallback
  • a single public endpoint hostname
  • no additional peers
  • no DNS workarounds

The actual WireGuard endpoint always remains wg-end, independent of the transport protocol.

Appendix

Why CNAME is not used

For anyone familiar with DNS, this is self-explanatory:

A DNS name may only have one CNAME record, and that record replaces all other record types.

Therefore it is not possible to combine:

  • IPv4 from one host
  • IPv6 from another host

using CNAME records.

The correct approach is simply to publish A and AAAA records directly on the endpoint hostname.

Why this does not create asymmetric routing

Both connection paths ultimately terminate on the same WireGuard endpoint host.

IPv6 path:

Client → wg-end

IPv4 path:

Client → firewall → DNAT → wg-end

Since the WireGuard service always runs on the same machine and uses the same peer identity, the tunnel state remains consistent.

Why a single hostname is preferred

Using one endpoint hostname keeps client configuration simple:

Endpoint = firewall.random.tld:51820

Transport selection happens automatically:

  • IPv6 preferred when available
  • IPv4 fallback when required

This makes the setup particularly robust in mobile or restricted networks.


Static IP Alternative

In environments where a static public dual-stack address is available on the firewall, this setup can be simplified.

Example:

vpn.random.tld
    A     → firewall IPv4
    AAAA  → firewall IPv6

The firewall would then forward both IPv4 and IPv6 traffic to the WireGuard host.

However, in practice this is rarely feasible in residential deployments.

Reasons include:

  • Most consumer internet connections use dynamic IPv4 addresses
  • IPv6 is often delivered via dynamic prefix delegation
  • Static dual-stack assignments are usually business-grade offerings

Very few home users are willing to pay for static addressing just to operate a personal VPN endpoint.

Therefore a DynDNS-based design is typically required.

Why IPv6 DynDNS is still uncommon

While DynDNS services are widely available for IPv4, support for automatic IPv6 updates is still inconsistent.

Typical problems include:

  • Many DynDNS clients only update A records
  • IPv6 prefix changes require AAAA record updates
  • Consumer routers often lack proper IPv6 DynDNS support
  • Even commercial DynDNS providers frequently focus on IPv4 use cases

Because of this, IPv6 DynDNS solutions are often implemented using custom scripts or API integrations.

The approach described in this document assumes a DynDNS workflow capable of updating multiple AAAA records simultaneously.

Design Summary

This architecture solves three practical problems simultaneously:

  • dynamic IPv4 addresses
  • dynamic IPv6 prefixes
  • IPv4-only client networks

The result is a single stable WireGuard endpoint hostname that works reliably across both IPv4 and IPv6 networks.

public/wg-fallback-v6-v4.txt · Zuletzt geändert: von gerson

Seiten-Werkzeuge