Dodici build

Server WireGuard indurito con IPv6 che instrada davvero

Costruisci un endpoint WireGuard che assegna ai client un indirizzo privato v4 e un prefisso IPv6 realmente instradato, dietro una policy nftables che scarta tutto ciò che non è richiesto.

Cosa si costruisce

Un'istanza che esegue WireGuard, che assegna a ogni client un indirizzo IPv4 privato, un indirizzo IPv6 instradato dal proprio /48, e un resolver che vive dentro il tunnel, così le query DNS non prendono mai un percorso diverso dal resto del traffico. Il firewall è default-drop in entrambe le direzioni. Il forwarding è abilitato solo per l'interfaccia del tunnel, e solo in uscita.

Testato su un R-4 in AMS-01 con Debian 13. WireGuard è single-flow e lato kernel, quindi più core non comprano nulla finché non spingi diversi gigabit al secondo. Ciò che conta molto di più è il sito: scegli quello più vicino a dove ti trovi davvero, perché ogni millisecondo che aggiungi qui lo aggiungi a ogni pacchetto.

Prima di iniziare

  • Un'istanza attiva e root via SSH.
  • Il componente aggiuntivo IPv6 /48 abilitato nel pannello. Il /64 incluso funziona per un singolo client, ma subnet per client da un singolo /64 significa fare proxy del neighbour discovery, e quello è un hobby piuttosto che una configurazione.
  • Un hostname che punta all'istanza. Tutto ciò che segue usa vpn.example.com.
  • Ogni indirizzo 2001:db8: qui è spazio di documentazione. Sostituisci il prefisso con quello mostrato nella pagina dell'istanza.

1. Pacchetti e impostazioni del kernel

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

L'ultimo comando stampa il nome dell'interfaccia verso l'esterno. Sulle nostre immagini KVM è ens3; se il tuo è diverso, sostituiscilo ovunque sotto. Ora il 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

La riga accept_ra = 2 è quella che la gente dimentica. Attivare il forwarding IPv6 fa smettere al kernel di accettare i router advertisement, la rotta predefinita sparisce entro dieci minuti, e la macchina diventa irraggiungibile su v6 mentre risponde ancora su v4. Impostarla a due mantiene l'accettazione degli advertisement su un host che fa forwarding.

2. Chiavi

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

La chiave pre-condivisa non è opzionale in questa build. Non costa nulla, è una riga in ogni configurazione, ed è la differenza tra un tunnel che è semplicemente sicuro oggi e uno che rimane sicuro contro un avversario che registra il traffico ora per decrittarlo dopo.

3. L'interfaccia del server

Scrivi /etc/wireguard/wg0.conf, incollando i contenuti delle chiavi dove indicato:

[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

Lato server AllowedIPs è una tabella di routing, non un elenco di permessi. Dai a ogni peer esattamente gli indirizzi che possiede e niente di più ampio, o due client litigheranno per la stessa rotta e il perdente smetterà semplicemente di ricevere pacchetti.

chmod 600 /etc/wireguard/wg0.conf

4. Un resolver dentro il tunnel

Puntare i client a un resolver pubblico vanifica gran parte del senso. Unbound è già installato; dagli /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 non si avvierà prima che il tunnel esista, perché quegli indirizzi non sono ancora attivi. Sequenzialo correttamente piuttosto che combatterlo:

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

5. Il firewall

Sostituisci /etc/nftables.conf completamente:

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
  }
}

Nota ciò che è assente: non c'è tabella NAT per IPv6. I client escono con il loro indirizzo dal tuo /48, che è l'intera ragione per cui prendi il /48 in primo luogo. La riga iifname "wg0" oifname "wg0" drop impedisce ai peer di raggiungersi a vicenda, cosa che vuoi a meno che tu non stia deliberatamente costruendo una mesh.

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

6. Avvio

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

7. Il client

[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

Per un telefono, trasformalo in un codice QR sul server e fotografa il terminale:

qrencode -t ansiutf8 < /root/laptop.conf

Su un client Debian o Ubuntu la riga DNS = richiede openresolv installato, altrimenti wg-quick stampa un avviso e silenziosamente lascia il vecchio resolver in posizione. Questa è la causa più comune di un tunnel che funziona perfettamente e perde ogni lookup.

Verifica

Quattro controlli, in ordine. Qualsiasi cosa fallisca ti dice a quale passo tornare.

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

Un timestamp di handshake entro gli ultimi due minuti e contatori non zero in entrambe le direzioni significano che la crittografia e il routing sono entrambi a posto.

# 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

Il terzo comando prova che il resolver del tunnel sta rispondendo. Se va in timeout, Unbound è partito prima che wg0 esistesse; riavvialo.

L'ultimo controllo è l'unico che prova che il tuo traffico esce dove pensi, e richiede una seconda macchina. Qualsiasi altra istanza nella flotta va bene, in qualsiasi città:

# 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/

Il listener stampa l'indirizzo sorgente di ogni connessione. Il tuo tentativo v4 dovrebbe arrivare dal server WireGuard, perché è stato mascherato. Il tentativo v6 dovrebbe arrivare dall'indirizzo di tunnel del client dentro il tuo /48, intatto, che è ciò che instradato significa e proxato no.

Quando va storto

SintomoCausaFix
Handshake riesce, nessun traffico passaForwarding spento, o la catena forward scartasysctl net.ipv4.ip_forward, poi rileggi la catena forward
Richieste piccole ok, download grandi si bloccanoMTU e path discoveryAbbassa entrambe le config a MTU = 1380 e riprova
IPv6 muore circa dieci minuti dopo il bootForwarding ha ucciso i router advertisementaccept_ra = 2 sull'interfaccia verso l'esterno
DNS risolve fuori dal tunnelClient ha ignorato DNS =Installa openresolv sul client
Tutto sparito dopo un riavvioUnit mai abilitatesystemctl enable wg-quick@wg0 nftables unbound

Da qui, i prossimi passi sensati sono un secondo endpoint in un'altra regione e uno stack di monitoraggio che ti dica quando uno di loro smette di rispondere. Entrambi sono trattati altrove in le guide; la pagina di rete spiega cosa fa l'edge con il tuo traffico prima che ti raggiunga.

Pronto quando lo sei

Scegli una città. Scegli una dimensione. Paga in criptovaluta.

Nessun modulo su chi sei, nessuna attesa per l'approvazione di una persona, nessuna chiamata per verificare nulla. La fattura viene saldata e le credenziali arrivano nella tua casella di posta.