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

Дисклеймер, граждане. Не проходите мимо.

Данная статья носит исключительно образовательный и исследовательский характер. Автор рассматривает WireGuard как инструмент построения защищённых каналов связи для корпоративной инфраструктуры, удалённой работы и защиты персональных данных в небезопасных сетях.

Развёртывание личного VPN-сервера, описанное ниже, предназначено для законных целей: объединение офисов, защита трафика в публичном Wi-Fi, доступ к домашним устройствам. Автор не призывает к использованию технологии для получения доступа к информации, распространение которой ограничено на территории Российской Федерации, и напоминает, что ответственность за использование VPN лежит на конечном пользователе в соответствии с действующим законодательством.

WireGuard - протокол защищенного туннелирования, реализованный как виртуальный сетевой интерфейс в ядре Linux. Отмечу отдельно, что в ядре Linux 5.6+ версии, поскольку официально он добавлен только в 2020 году. В версиях до 5.6 его придётся компилировать отдельно самостоятельно. Для своих практических целей, рассматриваю Debian 12 с ядром 6.1LTS, где также добавлены оптимизации WireGuard (GSO — Generic Segmentation Offload, GRO — Generic Receive Offload). Поскольку материал имеет практическую направленность, то сразу о том, что я использовал при подготовке этой статьи: VPS 1CPU 3,3 ГГц, 1ГБ RAM, ПЗУ 15 ГБ NVMe с системой Debian 12.

Стоит отметить, что даже такая скромная начинка VPS позволяет развернуть достойную по количеству и качеству сеть. В этом скрывается первый жирный плюс WireGuard. В отличие от OpenVPN и IPSec, WireGuard не является отдельным приложением, поэтому потребление ресурсов более чем очень скромное. Система рассчитана на хорошее масштабирование. Каждый отдельный клиент - пир не займет более нескольких килобайт памяти. Примерно 1,5–1,9 КБ на одного подключенного пира для версий ядра 2021 года и новее. Процесс подключения и удержания связи выглядит, как HANDSHAKE, и далее каждые 2-3 минуты ротация сессионных ключей (если идёт трафик), в отсутствии трафика ничего не происходит.

Статистика нагрузки на сервер с WireGuard в течении суток при 8 -12 активных пользователях (устройств). Оперативную память, в основном, ест система и Docker-контейнер
Статистика нагрузки на сервер с WireGuard в течении суток при 8 -12 активных пользователях (устройств). Оперативную память, в основном, ест система и Docker-контейнер

Предлагаю вам, дорогие читатели, изучить материал патча: Linux-Kernel Archive: [PATCH 5.10 660/663] wireguard: queueing: get rid of per-peer ring buffers, где Джейсон Доненфельд сам описывает плюсы и минусы перехода от рингбуфферов к очередям на основе списков. Основная идея - сократить выделение памяти. Короткая цитата:

Джейсон А. Доненфельд <Jason@xxxxxxxxx>  Пн 01 мар 2021

Наличие двух буферов кольца на одного пиринга означает, что каждый узел приводит к двум огромным распределениям колец. На восьмиядерной x86_64-машине этот коммит сокращает выделение на одного пиринга с 18 688 байт до 1 856 байт, что составляет сокращение на 90%. Девяносто процентов! При некоторых развертываниях на одной машине , приближающейся к 500 000 пиров, речь идёт о сокращении с 7 гигабайт памяти до 700 мегабайт.

Что с безопасностью?

Самая существенная часть. WireGuard позиционируется, в первую очередь, как криптопротокол. Это своего рода Кондом для посещений Интернета. VPN-туннель — лишь следствие того, как работает шифрование.

Вопрос традиционно вызывает споры между приверженцами OpenVPN, WireGuard. Везде, как водится, есть свои сильные и слабые стороны.

К преимуществам, к примеру, OpenVPN часто относят гибкость в выборе алгоритмов шифрования, но и это же является его недостатком. Сразу встаёт вопрос: каким должен быть стек? AES-256 или 128? или CHACHA? Да, для грамотной и корректной настройки нужны специалисты высокого класса. И для своих задач OpenVPN бывает действительно незаменим.

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

Какое шифрование используется?

Это самому можно увидеть после установки WireGuard:

apt install wireguard -y 
modprobe wireguard && lsmod | grep wireguard

libchacha20poly1305
curve25519_x86_64
libcurve25519_generic

Для "рукопожатия" сервер использует общий секрет, вычисленный на основе приватных и публичных ключей.
Приватный и публичный ключи составляют криптографическую пару: публичный ключ математически выводится из приватного. Обратное вычисление невозможно, и в этом основа безопасности:

wg genkey | tee server_private.key | wg pubkey > server_public.key

ChaCha20 шифрует трафик сеансовыми ключами, которые вывела хэш-функция BLAKE2s из общего секрета. Пакеты трафика аутентифицируются Poly1305.

Ещё одна известная фича WireGuard — «стелс-режим».

Помимо того, что у протокола нет обязательной привязки к конкретным портам (51820 используется традиционно), найдя порт, не получится понять, что там. Как это работает?

При сканировании NMAP посылает тестовый пакет данных на порт, ожидая ответа. WireGuard, будучи криптопротоколом, пытается расшифровать этот пакет известными ему приватными ключами. Poly1305 проверяет аутентичность подписи — и поскольку данные мусорные, а подпись не соответствует содержимому, пакет молча отбрасывается без какого-либо ответа. NMAP фиксирует open|filtered. Что внутри — не ясно.

Разумеется, не всё так однобоко и великолепно, и не для всех сценариев WireGuard является рекомендуемым инструментом туннелирования. Предлагаю к прочтению перевод статьи с IPFire Майкла Тремера (он является явным сторонником IPsec) от 2020 года, размещенный на Хабре: Почему не стоит пользоваться WireGuard / Хабр от Data_center_MIRAN. Это иной взгляд на вопрос. Очень познавательно.

Действительно, WireGuard лишен многих полезных опций, которые кажутся базовыми при работе с туннелированием. На фоне IPsec и OpenVPN он выглядит словно авто в минимальной комплектации, где нет даже магнитолы. Протокол построен поверх UDP, и это одна из самых заметных проблем. Если в сети, где вы планируете работать, установлена блокировка UDP-трафика, то без костылей не обойтись (например, udp2raw, чтобы «завернуть» UDP-пакеты WireGuard в TCP-соединение), которые, впрочем, тоже могут не дать результата. РКН периодически уверенно кладёт WireGuard из-за невозможности маскировать UDP-трафик под HTTPS. Таким образом выходит, что основная "фишка" в легковесности протокола и быстрорукопожатности становится же ахиллесовой пятой.

Нет ни одного технического решения (думаю, это касается не только туннелирования), которое удовлетворило все запросы и всех запросчиков. Для повседневного использования, при всех присущих минусах и плюсах, я для себя выбрал WireGuard, как легкий и быстрый способ получить дополнительную безопасность. Более того, нет никакой необходимости арендовать сервер за рубежом (иностранный, разумеется, дороже (около 2500р/мес у меня). Для дополнительно шифрования трафика прекрасно подойдёт и отечественный.

Пора переходить к практической части.

Как развернуть эту конфетку?

На весь процесс, вместе с Docker и прочим, уйдёт не более часа при аккуратном выполнении.

Ниже собраны все команды и содержание конфигураций, чтобы их удобно было копировать. После них будут предоставлены необходимые инструкции.

Итак, мы арендовали серверное пространство. Открываем консоль и строчка за строчкой выполняем команды из списка. Одна команда (строчка) за один раз. Если надо с чем-то согласиться - со всем соглашаемся. Linux ерунды не предложит.

apt update && apt upgrade -y

apt install wireguard -y

modprobe wireguard && lsmod | grep wireguard

umask 077
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key

cat /etc/wireguard/server_private.key
cat /etc/wireguard/server_public.key

mkdir -p /etc/wireguard/clients
umask 077
wg genkey | tee /etc/wireguard/clients/peer_private.key | wg pubkey > /etc/wireguard/clients/peer_public.key

cat /etc/wireguard/clients/peer_private.key
cat /etc/wireguard/clients/peer_public.key

nano /etc/wireguard/wg0.conf

chmod 600 /etc/wireguard/wg0.conf

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p

ip route get 1.1.1.1 | awk '{print $5; exit}'

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

apt install iptables-persistent -y

iptables -I INPUT -p udp --dport 51820 -j ACCEPT

netfilter-persistent save

nano /etc/wireguard/clients/peer.conf

cat /etc/wireguard/clients/peer.conf

Содержимое файла конфигурации wg0.conf:
После команды из 20й строчки списка выше откроется редактор, куда надо вставить эти данные (скопировать туда ключи, полученные во время генераций после команды из строки 8):

[Interface]
Address = 10.0.0.1/24
ListenPort = 51820 (можно любой, по вкусу, кроме зарезервированных)
PrivateKey = (приватный ключ Сервера)

[Peer]
PublicKey = (публичный ключ КЛИЕНТА)
AllowedIPs = 10.0.0.2/32

Содержимое peer.conf:
Аналогично wg0.conf после команды из 37й строчки (nano /etc/wireguard/clients/peer.conf)

[Interface]
Address = 10.0.0.2/32
PrivateKey = (здесь приватный ключ КЛИЕНТА)
DNS = 1.1.1.1

[Peer]
PublicKey = (здесь должен быть публичный ключ СЕРВЕРА)
Endpoint = (здесь должен быть ваш публичный IP)
AllowedIPs = 0.0.0.0/0

В примере DNS = 1.1.1.1 - Cloudflare. Можете для себя выбрать другой, например, Google 8.8.8.8 - тоже шустрый, однако Cloudflare не хранит логи, в отличии от Google, или AdGuard - 94.140.14.14, 94.140.15.15, который хорош для блокировки рекламы. Можете прописать даже два или более через запятую: DNS = 1.1.1.1, 8.8.8.8, 94.140.15.15. В сущности, DNS можно не указывать вовсе, тогда будет использоваться системный, но лучше так не делать.

Если вы дошли до этого места и правильно выполнили все команды в консоли, то поздравляю. Вы настроили WireGuard!

wg-quick up wg0 - запускаем интерфейс

wg show - проверяем. Если всё ОК, то мы увидим следующий вывод:

latest handshake: 5 seconds ago
transfer: 1.2 MiB received, 800 KiB sent

Всё работает!

systemctl enable wg-quick@wg0 - добавляем WireGuard в автозапуск на сервере, чтобы вручную не запускать при каждой перезагрузке VPS

На этом можно было бы остановиться. Но есть ещё одна маленькая деталь, которую хочется добавить, чтобы опыт взаимодействия с WireGuard был действительно приятным. Добавим веб-интерфейс для заведения новых пиров на сервер.

Сначала остановим сервер: wg-quick down wg0
Далее устанавливаем и проверяем Docker:

apt install docker.io docker-compose -y
systemctl enable --now docker
docker --version

docker run -d \
  --name=wg-easy \
  -e WG_HOST= ДОБАВЬТЕ СВОЙ ПУБЛИЧНЫЙ IP \
  -e PASSWORD= ПРИДУМАЙТЕ СВОЙ ПАРОЛЬ! \
  -e WG_DEFAULT_DNS=1.1.1.1 \
  -v ~/.wg-easy:/etc/wireguard \
  -p 51820:51820/udp \ 
  -p 51821:51821/tcp \
  --cap-add=NET_ADMIN \
  --cap-add=SYS_MODULE \
  --sysctl="net.ipv4.conf.all.src_valid_mark=1" \
  --sysctl="net.ipv4.ip_forward=1" \
  --restart unless-stopped \
  weejewel/wg-easy 

Обратите внимание, что конфиги Docker копируются скопом. Нужно добавить свой пароль, свой порт-UDP, если при настройке WireGuard вы установили не 51820

Далее открываем порт в фаерволе:

iptables -I INPUT -p tcp --dport 51821 -j ACCEPT
netfilter-persistent save

Всё! На этом точно всё. Проверяем. Заходим к себе в панель по адресу:
ваш_публичный_ip:tcp_порт_из_кофнигов_docker
(например: 145.145.145.145:51821),
вводим пароль из конфигов Docker и радуемся сами, а также радуем близких своим собственным VPN. За чудесный веб-интерфейс благодарим weejewel (Emile Nijssen)

Всем спасибо за внимание! С уважением @noise_floor .