12のビルド

実際にルーティングされるIPv6を備えた堅牢なWireGuardサーバー

クライアントにプライベートv4アドレスと実際にルーティングされるIPv6プレフィックスを提供し、要求されないものをすべてドロップするnftablesポリシーの背後にあるWireGuardエンドポイントを構築する。

これで作られるもの

WireGuardを実行する1つのインスタンス。各クライアントにプライベートIPv4アドレス、独自の/48からルーティングされたIPv6アドレス、そしてトンネル内に存在するリゾルバを割り当てます。DNSクエリが他のトラフィックとは異なる経路を取ることがないようにです。ファイアウォールは双方向でデフォルトドロップです。転送はトンネルインターフェースに対してのみ有効で、かつアウトバウンドのみです。

AMS-01のR-4でDebian 13でテスト済み。WireGuardはシングルフローでカーネルサイドなので、複数ギガビットを押し出すまでは、コアを増やしても意味がありません。もっと重要なのはサイトです。実際にいる場所に最も近いものを選んでください。ここで追加するミリ秒は、すべてのパケットに追加されるからです。

始める前に

  • デプロイ済みのインスタンスとSSHでのrootアクセス。
  • パネルでIPv6 /48アドオンを有効にしていること。付属の/64は単一クライアントで動作しますが、単一の/64からクライアントごとのサブネットを出すには近隣探索のプロキシが必要で、それは設定ではなく趣味です。
  • インスタンスを指すホスト名。以下ではすべてvpn.example.comを使用します。
  • ここにあるすべての2001:db8:アドレスはドキュメント用スペースです。プレフィックスをインスタンスページに表示されているものに置き換えてください。

1. パッケージとカーネル設定

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

その最後のコマンドは、外向きインターフェース名を表示します。当社のKVMイメージではens3です。異なる場合は、以下すべてで置き換えてください。次にカーネル:

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

accept_ra = 2の行は忘れがちです。IPv6転送を有効にすると、カーネルはルーター広告の受け入れを停止し、デフォルトルートは10分以内に消え、マシンはv4で応答しながらv6で暗闇になります。2に設定すると、転送ホストで広告の受け入れを維持します。

2. 鍵

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

事前共有鍵はこの構成ではオプションではありません。コストはゼロで、各設定で1行です。今日単に安全なトンネルと、現在トラフィックを記録して後で解読する敵に対しても安全であり続けるトンネルの違いです。

3. サーバーインターフェース

/etc/wireguard/wg0.confを書き、マークされた場所に鍵の内容を貼り付けます:

[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

サーバー側ではAllowedIPsはルーティングテーブルであり、許可リストではありません。各ピアに、それが所有するアドレスだけを正確に与え、それ以上広くしないでください。そうしないと、2つのクライアントが同じルートを争い、負けた方は単にパケットを受信しなくなります。

chmod 600 /etc/wireguard/wg0.conf

4. トンネル内のリゾルバ

クライアントをパブリックリゾルバに向けると、意味がかなり失われます。Unboundはすでにインストールされています。/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はトンネルが存在する前に起動に失敗します。これらのアドレスがまだ上がっていないためです。うまく順序付けて対抗するのではなく、適切にシーケンスします:

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

5. ファイアウォール

/etc/nftables.conf全体を置き換えます:

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

何が欠けているかに注意してください:IPv6用のNATテーブルはありません。クライアントは/48から自分のアドレスでegressします。これがそもそも/48を取得する理由のすべてです。iifname "wg0" oifname "wg0" dropの行はピア同士の到達を防ぎます。これは、意図的にメッシュを構築しているのでない限り望ましいです。

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

6. 起動

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

7. クライアント

[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

電話の場合は、サーバー上でQRコードに変換してターミナルを撮影します:

qrencode -t ansiutf8 < /root/laptop.conf

DebianまたはUbuntuクライアントでは、DNS =の行にopenresolvのインストールが必要です。そうしないとwg-quickは警告を出力し、古いリゾルバを静かに残します。これは、完全に機能し、すべてのルックアップをリークするトンネルの最も一般的な原因です。

検証

4つのチェックを順に行います。失敗したものは、どのステップに戻るべきかを示します。

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

過去2分以内のハンドシェイクタイムスタンプと、双方向の非ゼロカウンタは、暗号化とルーティングの両方が正常であることを意味します。

# 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

3番目のコマンドは、トンネルリゾルバが応答していることを証明します。タイムアウトした場合は、wg0が存在する前にunboundが起動しました。再起動してください。

最後のチェックは、トラフィックが意図した場所から出ることを証明する唯一のチェックであり、2台目のマシンが必要です。フリート内の他のインスタンスならどこでも、どの都市でも構いません:

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

リスナーは各接続の送信元アドレスを出力します。v4の試行は、マスカレードされたためWireGuardサーバーから到着するはずです。v6の試行は、クライアント自身のトンネルアドレスから/48内で、変更されずに到着するはずです。これが「routed」の意味であり、「proxied」ではないのです。

問題が発生した場合

症状原因修正
ハンドシェイク成功、データが通らない転送オフ、またはフォワードチェーンがドロップsysctl net.ipv4.ip_forward、次にフォワードチェーンを再読
小さなリクエストはok、大きなダウンロードがハングMTUとパス探索両方の設定をMTU = 1380に下げて再試行
起動後約10分でIPv6が死ぬ転送がルーター広告を殺した外向きインターフェースでaccept_ra = 2
DNSがトンネル外で解決クライアントがDNS =を無視クライアントにopenresolvをインストール
再起動後にすべて消えるユニットが有効になっていないsystemctl enable wg-quick@wg0 nftables unbound

ここから先の賢明な次のステップは、別のリージョンに2番目のエンドポイントを置き、それらのいずれかが応答を停止したときに通知する監視スタックを構築することです。両方ともガイドの他の場所でカバーされています。ネットワークページは、エッジがトラフィックを処理する方法を説明しています。

準備はできている

都市を選べ。サイズを選べ。コインで支払え。

あなたが誰かに関するフォームも、承認する人間を待つ必要も、確認のための電話もありません。請求が完了すれば、認証情報があなたの受信トレイに届きます。