Contenuti

VPN server con wireguard

Wireguard è un tool per creare VPN, moderno, sicuro e performante. Vediamo come creare un server VPN a cui inoltrare tutto il traffico.

prerequisiti

Avremo bisogno di un server con caratteristiche minime:

  • 1 core
  • 1GB di RAM (funziona anche con meno, ma vediamo di essere ragionevoli)
  • 5GB di disco
  • banda!
  • linux con un kernel recente

In particolare bisogna prestare attenzione alla banda: se si ha la fortuna di avere una connessione ad internet veloce, diciamo >100mbit, dovremo assicurarci di avere almeno la stessa banda sul server.

Ad oggi, possiamo noleggiare un VPS con queste caratteristiche per meno di 5€/mese.

In questa guida, verranno considerati i seguenti sistemi operativi:

  • Debian 13 Trixie (come client o server)
  • Ubuntu Server 26.04 (come server)
  • Ubuntu 26.04 (come client)

definizioni

Useremo queste convenzioni:

  • Rete del tunnel: 192.168.199.1/24
  • IP del server: 192.168.199.1
  • IP dei client: da 192.168.199.2 in avanti
  • IP esterno del server: 11.22.33.44
  • interfaccia esterna del server: ens18

setup del server

Per semplicità, supponiamo di partire da un server nuovo, a cui abbiamo accesso come utente root.

Installiamo un po’ di pacchetti:

apt install wireguard iptables resolvconf qrencode unattended-upgrades unbound

Wireguard ha bisogno di una chiave pubblica e di una chiave privata per ogni membro della connessione, quindi creiamo una coppia di chiavi per il server:

wg genkey | tee /root/server.privkey
sL1UKqiqMraaQarCy7UIUpkQnpgzR6Gm+L1RCgp2TEM=

cat /root/server.privkey | wg pubkey | tee /root/server.pubkey
UgvmsCnMWWW9XAHNbc6+lkbCLSF5Mt3b85A4PrG4mRE=

Per semplificare la configurazione, useremo un tool di wireguard che si chiama wg-quick: questo ci permette di gestire la configurazione di ogni interfaccia di wireguard in un file; inoltre, si occuperà di gestire indirizzi IP e routing ad ogni attivazione/disattivazione dell’interfaccia. In questo file di configurazione verranno salvate le chiavi pubbliche e gli indirizzi IP di ogni altro membro della VPN. Cominciamo con il crere il file di configurazione (il nome del file DEVE essere [nome_interfaccia].conf) e popolarlo:

touch /etc/wireguard/wg0.conf

cat > /etc/wireguard/wg0.conf <<EOF
[Interface]
Address = 192.168.199.1/24
SaveConfig = true
ListenPort = 51194
PrivateKey = sL1UKqiqMraaQarCy7UIUpkQnpgzR6Gm+L1RCgp2TEM=
MTU = 1420
PostUp = iptables -A FORWARD -i wg0 -o ens18 -j ACCEPT
PostUp = iptables -A FORWARD -i ens18 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostUp = iptables -t mangle -A FORWARD -o wg0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PostDown = iptables -D FORWARD -i wg0 -o ens18 -j ACCEPT
PostDown = iptables -D FORWARD -i ens18 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -t mangle -D FORWARD -o wg0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
EOF

systemctl enable wg-quick@wg0

wg-quick up wg0

wg
interface: wg0
  public key: UgvmsCnMWWW9XAHNbc6+lkbCLSF5Mt3b85A4PrG4mRE=
  private key: (hidden)
  listening port: 51194

Mettiamo un secondo da parte il server e vediamo il client.

setup del client (linux)

Sul client dobbiamo replicare gli stessi comandi del server, con alcune piccole differenze: chiaramente la coppia di chiavi sarà differente, e non avremo un indirizzo IP ed una porta per la ricezione delle connessioni in quanto la connessione sarà solo in uscita. Tutta la parte di configurazione di iptables non ci serve.

Supponendo di utilizzare una Ubuntu 26.04:

sudo apt install wireguard resolvconf

wg genkey | tee ~/server.privkey
AGrgj2nh5T/3VMddrno/FIOgiotgKVQ9ydjw2AHzbno=

cat ~/server.privkey | wg pubkey | tee ~/server.pubkey
7c0uRl/F4jcpEPLOTA8zs0vcpQ3lTiljYbWb2QmJ11M=

sudo touch /etc/wireguard/wg0.conf

sudo tee /etc/wireguard/wg0.conf <<EOF
[Interface]
SaveConfig = true
PrivateKey = AGrgj2nh5T/3VMddrno/FIOgiotgKVQ9ydjw2AHzbno=
Address = 192.168.199.2/32
DNS = 192.168.199.1
MTU = 1420

[Peer]
PublicKey = phoJ2IBLJXEjaJJXzcEM6TGidh/rGxCdpXvKOP0HK0E=
Endpoint = 11.22.33.44:51194
AllowedIPs = 0.0.0.0/0
# AllowedIPs = 192.168.199.0/24
PersistentKeepalive = 30
EOF

sudo systemctl enable wg-quick@wg0

sudo wg-quick up wg0

Ricapitolando, il client ha impostato un indirizzo IP singolo (/32) ed un DNS. Nella sezione [Peer] indica il server al quale connettersi e su che porta (si può usare anche un FQDN), oltre alla chiave pubblica per certificarne l’identità e decrittare il traffico.

La riga AllowedIPs indica quali indirizzi IP vengono inoltrati sul tunnel, in questo caso tutti. Di conseguenza, quando la VPN sarà attiva, sarà impossibile vedere la rete locale (ed ogni altra rete non raggiungibile dal server VPN) e tutto il traffico passerà dalla VPN.

configurazione del client sul server

Il server deve essere istruito per accettare le connessioni dal client:

wg set wg0 peer 7c0uRl/F4jcpEPLOTA8zs0vcpQ3lTiljYbWb2QmJ11M= \
allowed-ips 192.168.199.2 persistent-keepalive 30

wg
interface: wg0
  public key: UgvmsCnMWWW9XAHNbc6+lkbCLSF5Mt3b85A4PrG4mRE=
  private key: (hidden)
  listening port: 51194
  fwmark: 0xca6c

peer: 7c0uRl/F4jcpEPLOTA8zs0vcpQ3lTiljYbWb2QmJ11M=
  endpoint: 3.4.5.6:51820
  allowed ips: 192.168.199.2/32
  latest handshake: 39 seconds ago
  transfer: 7.20 MiB received, 6.63 MiB sent
  persistent keepalive: every 30 seconds

wg-quick save wg0

L’ultimo comando serve per salvare immediatamente la configurazione nel file /etc/wireguard/wg0.conf.

Abbiamo ancora bisogno di un paio di ritocchi: masquerading e DNS.

Masquerading (e forwarding)

Il traffico che arriva dalla VPN wireguard, al momento, arriva sul server e viene scartato. Bisogna abilitare il forwarding:

# modifica live
sysctl -w net.ipv4.ip_forward=1

# modifica permanente
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/99-forwarding.conf

Le regole del firewall vengono create e rimosse quando l’interfaccia wg0 di wireguard sale o scende. Queste sono le regole:

iptables -A FORWARD -i ens18 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wg0 -o ens18 -j ACCEPT
iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
iptables -t mangle -A FORWARD -o wg0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Eccole spiegate:

  • il traffico da inoltrare, relativo a connessioni già attive, viene accettato ed inoltrato
  • il traffico da inoltrare, in arrivo dalla VPN viene accettato
  • il traffico in uscita sulla porta ens18 del server viene nattato (masquerading)
  • il traffico di risposta che va verso la VPN viene “clampato” (limita la dimensione dei pacchetti)

DNS

Il client utilizza il server DNS presente sul server, che quindi andiamo a configurare:

cat > /etc/unbound/unbound.conf.d/custom.conf <<EOF
interface: 0.0.0.0
access-control: 192.168.199.0/24 allow
access-control: 127.0.0.1/8 allow

forward-zone:
        name: "."
        forward-addr: 9.9.9.9
        forward-addr: 1.1.1.2
EOF

# riavvio unbound
systemctl restart unbound

Semplicemente abilitiamo il server DNS su TUTTE le interfacce, ma accettiamo le richieste solo dalla VPN e da localhost; ogni richiesta viene inoltrata ai DNS di quad9 e cloudflare.

TODO

  • filtraggio malware/pubblicità