Twaalf builds

Een geharde WireGuard-server met IPv6 die daadwerkelijk routeert

Bouw een WireGuard-endpoint dat clients een privé-v4-adres en een echt gerouteerd IPv6-prefix geeft, achter een nftables-beleid dat alles zonder toestemming blokkeert.

Wat dit bouwt

Eén instantie die WireGuard draait, elke cliënt een privé IPv4-adres geeft, een gerouteerd IPv6-adres uit je eigen /48, en een resolver die in de tunnel leeft zodat DNS-query's nooit een andere route nemen dan de rest van het verkeer. De firewall is standaard-drop in beide richtingen. Doorsturen is alleen ingeschakeld voor de tunnelinterface, en alleen uitgaand.

Getest op een R-4 in AMS-01 met Debian 13. WireGuard is single-flow en kernel-side, dus meer cores leveren niets op totdat je meerdere gigabits per seconde duwt. Wat veel meer uitmaakt is de locatie: kies de locatie die het dichtst bij je eigenlijke positie ligt, want elke milliseconde die je hier toevoegt, voeg je toe aan elk pakket.

Voordat je begint

  • Een geïmplementeerde instantie en root via SSH.
  • De add-on IPv6 /48 ingeschakeld in het paneel. De bijgeleverde /64 werkt voor een enkele cliënt, maar per-cliënt-subnetten uit een enkele /64 betekent neighbour discovery proxven, en dat is een hobby in plaats van een configuratie.
  • Een hostnaam die naar de instantie wijst. Hieronder wordt overal vpn.example.com gebruikt.
  • Elk 2001:db8:-adres hier is documentatieruimte. Vervang het prefix door dat op je instantiepagina wordt getoond.

1. Pakketten en kernelinstellingen

apt update && apt full-upgrade -y
apt install -y wireguard-tools nftables unbound qrencode
ip -br link

Dat laatste commando print de naam van je naar buiten gerichte interface. Op onze KVM-images is dat ens3; als de jouwe verschilt, vervang het dan hieronder overal. Nu de kernel:

cat > /etc/sysctl.d/99-wireguard.conf <<EOF
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.ens3.accept_ra = 2
net.ipv4.conf.all.rp_filter = 1
EOF
sysctl --system

De accept_ra = 2-regel is degene die men vergeet. Het inschakelen van IPv6-doorsturen zorgt ervoor dat de kernel stopt met het accepteren van routeradvertenties, de standaardroute verdwijnt binnen tien minuten en de machine wordt donker via v6 terwijl hij nog via v4 antwoordt. Door het op twee te zetten, blijf je advertenties accepteren op een doorsturende host.

2. Sleutels

install -d -m 700 /etc/wireguard
umask 077
wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub
wg genkey | tee /etc/wireguard/laptop.key | wg pubkey > /etc/wireguard/laptop.pub
wg genpsk > /etc/wireguard/laptop.psk

De pre-shared key is niet optioneel in deze build. Het kost niets, het is één regel in elke config, en het is het verschil tussen een tunnel die vandaag slechts veilig is en een die veilig blijft tegen een aanvaller die nu verkeer opneemt om later te decoderen.

3. De serverinterface

Schrijf /etc/wireguard/wg0.conf en plak de sleutelinhoud waar gemarkeerd:

[Interface]
Address = 10.7.0.1/24, 2001:db8:1a2b:7::1/64
ListenPort = 51820
PrivateKey = <contents of /etc/wireguard/server.key>
MTU = 1420

[Peer]
# laptop
PublicKey = <contents of /etc/wireguard/laptop.pub>
PresharedKey = <contents of /etc/wireguard/laptop.psk>
AllowedIPs = 10.7.0.2/32, 2001:db8:1a2b:7::2/128

Aan de serverkant is AllowedIPs een routingtabel, geen machtigingslijst. Geef elke peer precies de adressen die hij bezit en niets breder, anders vechten twee cliënten om dezelfde route en stopt de verliezer eenvoudigweg met het ontvangen van pakketten.

chmod 600 /etc/wireguard/wg0.conf

4. Een resolver in de tunnel

Cliënten naar een publieke resolver verwijzen, maakt een groot deel van het doel ongedaan. Unbound is al geïnstalleerd; geef het /etc/unbound/unbound.conf.d/tunnel.conf:

server:
  interface: 10.7.0.1
  interface: 2001:db8:1a2b:7::1
  access-control: 10.7.0.0/24 allow
  access-control: 2001:db8:1a2b:7::/64 allow
  do-ip6: yes
  prefetch: yes
  hide-identity: yes
  hide-version: yes
  qname-minimisation: yes

Unbound zal niet starten voordat de tunnel bestaat, omdat die adressen nog niet actief zijn. Sequenceer het goed in plaats van ertegen te vechten:

systemctl edit unbound
[Unit]
[email protected]
[email protected]

5. De firewall

Vervang /etc/nftables.conf volledig:

flush ruleset

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    ct state established,related accept
    ct state invalid drop
    iif lo accept
    ip protocol icmp accept
    ip6 nexthdr icmpv6 accept
    tcp dport 22 accept
    udp dport 51820 accept
    iifname "wg0" udp dport 53 accept
    iifname "wg0" tcp dport 53 accept
  }
  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state established,related accept
    iifname "wg0" oifname "ens3" accept
    iifname "wg0" oifname "wg0" drop
  }
  chain output {
    type filter hook output priority filter; policy accept;
  }
}

table ip nat {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    ip saddr 10.7.0.0/24 oifname "ens3" masquerade
  }
}

Let op wat ontbreekt: er is geen NAT-tabel voor IPv6. Cliënten gaan uit met hun eigen adres uit je /48, wat de hele reden is om de /48 in de eerste plaats te nemen. De iifname "wg0" oifname "wg0" drop-regel stopt peers die elkaar bereiken, wat je wilt tenzij je bewust een mesh bouwt.

systemctl enable --now nftables
nft list ruleset | head -20

6. Start het

systemctl enable --now wg-quick@wg0
systemctl restart unbound
wg show wg0

7. De cliënt

[Interface]
PrivateKey = <contents of /etc/wireguard/laptop.key>
Address = 10.7.0.2/24, 2001:db8:1a2b:7::2/64
DNS = 10.7.0.1
MTU = 1420

[Peer]
PublicKey = <contents of /etc/wireguard/server.pub>
PresharedKey = <contents of /etc/wireguard/laptop.psk>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

Voor een telefoon, zet dat om in een QR-code op de server en fotografeer de terminal:

qrencode -t ansiutf8 < /root/laptop.conf

Op een Debian- of Ubuntu-cliënt heeft de DNS =-regel openresolv geïnstalleerd nodig, anders print wg-quick een waarschuwing en laat stilletjes je oude resolver op zijn plaats. Dat is de meest voorkomende oorzaak van een tunnel die perfect werkt en elke lookup lekt.

Verifieer het

Vier controles, in volgorde. Alles wat faalt, vertelt je naar welke stap je terug moet.

# on the server, after connecting the client
wg show wg0 latest-handshakes
wg show wg0 transfer

Een handshake-timestamp binnen de laatste twee minuten en niet-null tellers in beide richtingen betekenen dat zowel de cryptografie als de routing in orde zijn.

# on the client
ping -c3 10.7.0.1
ping -c3 2001:db8:1a2b:7::1
dig @10.7.0.1 paragonvps.com AAAA +short

Het derde commando bewijst dat de tunnelresolver antwoordt. Als het een time-out geeft, is unbound gestart voordat wg0 bestond; herstart het. De laatste controle is de enige die bewijst dat je verkeer vertrekt waar je denkt dat het vertrekt, en die heeft een tweede machine nodig. Elke andere instantie in de vloot volstaat, in elke stad:

# on the second instance
nc -lv 9101

# on the client, tunnel up
curl -m5 -4 http://second.example.com:9101/
curl -m5 -6 http://second.example.com:9101/

De luisteraar print het bronadres van elke verbinding. Je v4-poging moet aankomen vanaf de WireGuard-server, omdat die gemaskeerd is. De v6-poging moet aankomen vanaf het eigen tunneladres van de cliënt binnen je /48, onveranderd, wat gerouteerd betekent en geproxied niet.

Wanneer het misgaat

SymptoomOorzaakFix
Handshake slaagt, geen verkeer passeertDoorsturen uit, of de forward-chain laat vallensysctl net.ipv4.ip_forward en lees dan de forward-chain opnieuw
Kleine verzoeken prima, grote downloads hangenMTU en padontdekkingZet beide configs op MTU = 1380 en probeer opnieuw
IPv6 sterft ongeveer tien minuten na opstartenDoorsturen doodde routeradvertentiesaccept_ra = 2 op de naar buiten gerichte interface
DNS lost buiten de tunnel opCliënt negeerde DNS =Installeer openresolv op de cliënt
Alles weg na een herstartEenheden nooit ingeschakeldsystemctl enable wg-quick@wg0 nftables unbound

Vanaf hier zijn de logische volgende stappen een tweede endpoint in een andere regio en een monitoring-stack die je vertelt wanneer een ervan stopt met antwoorden. Beide worden elders behandeld in de gidsen; de netwerkpagina legt uit wat de edge met je verkeer doet voordat het je bereikt.

Klaar wanneer jij dat bent

Kies een stad. Kies een formaat. Betaal in munt.

Geen formulieren over wie je bent, geen wachten op een mens die je goedkeurt, geen telefoontje om iets te verifiëren. De factuur wordt betaald en de inloggegevens belanden in je inbox.