Привет, товарищ!

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

Я пробовал разные варианты, но пришел к выводу, что лучше всего ставить WireGuard нативно прямо на хост-систему Ubuntu. Вариант с Docker тоже возможен, но он добавляет лишнюю сложность с пробросом портов и правами доступа. Нативная установка работает быстрее, управляется через стандартный systemd и проще интегрируется с фаерволом.

Начнем с установки. Это нужно сделать на всех машинах, которые будут участвовать в сети. В терминале выполняем обновление пакетов и установку утилит:

1
2
sudo apt update
sudo apt install wireguard wireguard-tools -y

После установки проверим, что модуль ядра загружен командой wg. Если увидели справку или пустой список интерфейсов, значит все прошло успешно.

1
wg

Следующий шаг - генерация ключей. Это нужно делать локально на каждом сервере. Приватный ключ никогда не должен покидать машину, а публичный мы будем передавать партнерам по сети.

1
2
3
cd /etc/wireguard
umask 077
wg genkey | tee privatekey | wg pubkey > publickey

Сохраните содержимое файлов privatekey и publickey в надежное место. Для примера в статье я буду использовать заглушки вида PRIVATE_KEY_HERE и PUBLIC_KEY_HERE.

Теперь создадим конфигурацию. Допустим, мы выделили под нашу сеть подсеть 10.8.0.0/24. Серверу с белым IP адресом назначим 10.8.0.1, а клиентам адреса вроде 10.8.0.2 и 10.8.0.3.

На сервере с белым IP создаем файл /etc/wireguard/wg0.conf. В секции Interface указываем его приватный ключ и слушаемый порт. В секции Peer добавляем публичные ключи клиентов.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[Interface]
PrivateKey = SERVER_PRIVATE_KEY_HERE
Address = 10.8.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT

[Peer]
PublicKey = CLIENT1_PUBLIC_KEY_HERE
AllowedIPs = 10.8.0.2/32

[Peer]
PublicKey = CLIENT2_PUBLIC_KEY_HERE
AllowedIPs = 10.8.0.3/32

Обратите внимание на строки PostUp и PostDown. Они нужны для того, чтобы при подъеме интерфейса автоматически применялись правила фаервола, разрешающие пересылку пакетов.

На клиенте, который находится за NAT (например, домашний сервер), конфигурация будет проще. Ему нужно знать публичный ключ сервера и его белый IP адрес.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[Interface]
PrivateKey = CLIENT1_PRIVATE_KEY_HERE
Address = 10.8.0.2/24
DNS = 1.1.1.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY_HERE
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25

Параметр PersistentKeepalive важен для клиентов за натом. Он отправляет служебные пакеты каждые 25 секунд, чтобы роутер не забывал об открытом соединении.

Прежде чем запускать туннель, нужно подготовить сеть. На сервере обязательно включаем пересылку пакетов (IP Forwarding), иначе трафик не будет ходить между интерфейсами.

1
2
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Также нужно настроить фаервол. Если у вас активен UFW, откройте порт UDP 51820 и разрешите маршрутизацию для интерфейса wg0.

1
2
3
4
sudo ufw allow 51820/udp
sudo ufw route allow in on wg0 out on wg0
sudo ufw route allow in on wg0 out on eth0
sudo ufw route allow in on eth0 out on wg0

В командах выше замените eth0 на имя вашего основного сетевого интерфейса.

Теперь самый важный момент, на котором я лично споткнулся. После любого изменения файла конфигурации wg0.conf необходимо перезапускать сервис интерфейса. Правила PostUp выполняются только в момент создания интерфейса. Если вы просто отредактировали файл и забыли перезапустить службу, новые правила фаервола не применятся, и соединения не будет.

Правильный порядок действий после правки конфига выглядит так:

1
2
sudo wg-quick down wg0
sudo wg-quick up wg0

Или через системную службу:

1
sudo systemctl restart wg-quick@wg0

Не пренебрегайте этим шагом. Именно отсутствие перезагрузки часто приводит к тому, что интерфейс поднят, ключи верны, но пакеты теряются по пути.

Чтобы сеть поднималась автоматически после перезагрузки сервера, включите службу в автозагрузку:

1
sudo systemctl enable wg-quick@wg0

Для диагностики состояния туннеля используйте команду wg show. Запустите ее в режиме мониторинга, чтобы видеть изменения в реальном времени:

1
watch -n 1 wg show

Смотрите на поле latest handshake. Если время там постоянно обновляется (например, 5 seconds ago, 10 seconds ago), значит соединение активно и пакеты ходят. Если время застыло или указано none, значит пакеты не доходят. Проверьте фаерволы и убедитесь, что порт открыт у провайдера VPS.

Также проверяйте счетчики трафика transfer. Если при пинге счетчик received растет, значит пакеты доходят до интерфейса WireGuard. Если пинга нет, но трафик есть, проблема скорее всего в маршрутизации внутри системы или блокировке ICMP фаерволом.

В итоге вы получите безопасную сеть, где серверы видят друг друга по внутренним IP адресам. Сервисы вроде баз данных можно слушать только на интерфейсе туннеля, и они будут недоступны из внешнего интернета.

Удачи в построении вашей лаборатории!