Двенадцать сборок

Защищённый сервер WireGuard с IPv6, который действительно маршрутизирует

Соберите endpoint WireGuard, который выдаёт клиентам приватный адрес v4 и действительно маршрутизируемый префикс IPv6, за политикой nftables, которая отбрасывает всё не запрошенное.

Что здесь собирается

Один инстанс с WireGuard, выдающий каждому клиенту приватный IPv4-адрес, маршрутизируемый IPv6-адрес из вашего собственного /48 и резолвер, который живёт внутри туннеля, так что DNS-запросы никогда не идут другим путём, чем остальной трафик. Межсетевой экран по умолчанию запрещает всё в обоих направлениях. Пересылка включена только для туннельного интерфейса и только исходящая.

Проверено на R-4 в AMS-01 с Debian 13. WireGuard работает с одним потоком и на стороне ядра, так что больше ядер вам ничего не даст, пока вы не гоните несколько гигабит через него. Гораздо важнее площадка: выбирайте ту, что ближе к вам, потому что каждая добавленная здесь миллисекунда добавляется к каждому пакету.

Перед началом

  • Развёрнутый инстанс и root по SSH.
  • Включённый аддон IPv6 /48 в панели. Включённого /64 хватит на одного клиента, но выдача подсетей каждому клиенту из одного /64 означает проксирование neighbor discovery, а это хобби, а не конфигурация.
  • Имя хоста, указывающее на инстанс. Всё ниже использует 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-пересылки заставляет ядро перестать принимать Router Advertisements, маршрут по умолчанию исчезает в течение десяти минут, и машина теряет связь по v6, оставаясь доступной по v4. Установка в два заставляет продолжать принимать объявления на маршрутизирующем хосте.

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

Pre-shared key в этой сборке не опционален. Он ничего не стоит, это одна строка в каждом конфиге, и это разница между туннелем, который просто безопасен сегодня, и тем, что останется безопасным против противника, записывающего трафик сейчас, чтобы расшифровать позже.

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 — это таблица маршрутизации, а не список разрешений. Дайте каждому пиру ровно те адреса, которыми он владеет, и не шире, иначе два клиента будут спорить за один и тот же маршрут, и проигравший просто перестанет получать пакеты.

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

Обратите внимание на то, чего нет: нет таблицы NAT для IPv6. Клиенты выходят наружу со своим адресом из вашего /48, что и есть причина брать /48 в первую очередь. Строка iifname "wg0" oifname "wg0" drop не даёт пирам достучаться друг до друга, что вам и нужно, если вы не строите mesh намеренно.

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 печатает предупреждение и молча оставляет ваш старый резолвер на месте. Это самая частая причина того, что туннель работает идеально, а каждый запрос утекает.

Проверка

Четыре проверки по порядку. Любая неудачная укажет, к какому шагу вернуться.

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

Отметка времени рукопожатия в пределах последних двух минут и ненулевые счётчики в обоих направлениях означают, что и криптография, и маршрутизация в порядке.

# 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

Третья команда доказывает, что туннельный резолвер отвечает. Если он не отвечает, значит, unbound запустился раньше, чем появился wg0; перезапустите его.

Последняя проверка — единственная, которая доказывает, что ваш трафик выходит туда, куда вы думаете, и ей нужна вторая машина. Подойдёт любой другой инстанс во флоте, в любом городе:

# 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 не делает.

Если что-то не так

СимптомПричинаИсправление
Рукопожатие удаётся, трафик не идётПересылка выключена или forward chain сбрасываетsysctl net.ipv4.ip_forward, затем перечитайте forward chain
Мелкие запросы в порядке, большие загрузки зависаютMTU и path discoveryСнизьте в обоих конфигах до MTU = 1380 и повторите
IPv6 отваливается через десять минут после загрузкиПересылка убила Router Advertisementsaccept_ra = 2 на внешнем интерфейсе
DNS резолвится вне туннеляКлиент проигнорировал DNS =Установите openresolv на клиенте
Всё пропало после перезагрузкиМодули не включеныsystemctl enable wg-quick@wg0 nftables unbound

Дальше разумные шаги — второй endpoint в другом регионе и мониторинг, который скажет вам, когда один из них перестанет отвечать. Оба описаны в руководствах; на странице сети объясняется, что край делает с вашим трафиком до того, как он дойдёт до вас.

Готовы, когда вы готовы

Выберите город. Выберите размер. Оплатите монетой.

Никаких форм о том, кто вы, никакого ожидания одобрения человеком, никаких звонков для проверки. Счёт оплачен — и учётные данные приходят на почту.