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 linkL'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 --systemLa 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.pskLa 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/128Lato 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.conf4. 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: yesUnbound 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 -206. Avvio
systemctl enable --now wg-quick@wg0
systemctl restart unbound
wg show wg07. 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 = 25Per un telefono, trasformalo in un codice QR sul server e fotografa il terminale:
qrencode -t ansiutf8 < /root/laptop.confSu 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 transferUn 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 +shortIl 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
| Sintomo | Causa | Fix |
|---|---|---|
| Handshake riesce, nessun traffico passa | Forwarding spento, o la catena forward scarta | sysctl net.ipv4.ip_forward, poi rileggi la catena forward |
| Richieste piccole ok, download grandi si bloccano | MTU e path discovery | Abbassa entrambe le config a MTU = 1380 e riprova |
| IPv6 muore circa dieci minuti dopo il boot | Forwarding ha ucciso i router advertisement | accept_ra = 2 sull'interfaccia verso l'esterno |
| DNS risolve fuori dal tunnel | Client ha ignorato DNS = | Installa openresolv sul client |
| Tutto sparito dopo un riavvio | Unit mai abilitate | systemctl 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.