Шаг 10 · Сеть · 30 минут

Свой VPN на VPS: устанавливаем WireGuard

WireGuard превращает VPS в личную точку выхода в интернет и в способ безопасно достучаться до внутренних сервисов сервера без открытых наружу портов.

Как это работает — коротко

WireGuard проще, чем OpenVPN или IPsec, и в этом его сила. У каждой стороны — сервера и каждого клиента — есть пара ключей: приватный и публичный. Стороны обмениваются публичными ключами один раз, и после этого туннель поднимается без TCP-хендшейпов, сертификатов и центра сертификации.

После установки в системе появляется новый сетевой интерфейс, обычно wg0. Трафик, который попадает в него, шифруется и оборачивается в UDP-пакеты, а на другой стороне — расшифровывается и разворачивается обратно. С точки зрения приложений это выглядит как обычная сеть: свой диапазон IP-адресов, свои маршруты.

Устанавливаем WireGuard на сервере

В современных Ubuntu LTS WireGuard есть в стандартных репозиториях, отдельный PPA не нужен.

sudo apt update
sudo apt install -y wireguard

Пакет ставит саму реализацию и утилиты wg и wg-quick, которыми мы будем управлять туннелем.

Сервер должен не только принимать зашифрованный трафик, но и пересылать его дальше — в интернет или на другие внутренние сервисы. За это отвечает IP forwarding, по умолчанию он выключен. Включаем его на постоянной основе, добавив строку в /etc/sysctl.conf:

net.ipv4.ip_forward=1

Применяем изменение без перезагрузки:

sudo sysctl -p

Генерируем ключи

Ключевая пара нужна серверу и каждому клиенту отдельно — ключи никогда не переиспользуются. Команда wg genkey создаёт приватный ключ, wg pubkey из него выводит публичный.

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

umask 077 перед генерацией гарантирует, что файл с приватным ключом сразу создаётся без прав на чтение для остальных пользователей. Точно так же генерируем пару для каждого клиента, например для ноутбука и телефона отдельно:

wg genkey | tee laptop_private.key | wg pubkey > laptop_public.key
wg genkey | tee phone_private.key | wg pubkey > phone_public.key
Приватные ключи — это полный эквивалент пароля от туннеля. Никогда не кладите их в репозиторий, не отправляйте в чаты и не храните в общедоступных заметках: тот, у кого есть приватный ключ клиента, может подключиться к вашей сети от его имени.

Конфигурация сервера

Основной конфиг живёт в /etc/wireguard/wg0.conf. Секция [Interface] описывает сам сервер, а каждый [Peer] — одного клиента, которому разрешено подключаться.

sudo nano /etc/wireguard/wg0.conf
[Interface]
Address  =  10.10.0.1/24
ListenPort  =  51820
PrivateKey  =  <содержимое server_private.key>
PostUp  =  iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown  =  iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# laptop
PublicKey  =  <содержимое laptop_public.key>
AllowedIPs  =  10.10.0.2/32

[Peer]
# phone
PublicKey  =  <содержимое phone_public.key>
AllowedIPs  =  10.10.0.3/32

Address — это адрес самого интерфейса wg0 внутри туннельной подсети, а не публичный IP сервера. PostUp/PostDown добавляют и убирают правило NAT через iptables: без него пакеты из туннеля дойдут до сервера, но не смогут выйти дальше в интернет. Замените eth0 на имя вашего внешнего сетевого интерфейса — посмотреть его можно командой ip route.

В секциях [Peer] у сервера AllowedIPs означает не «куда клиенту можно ходить», а «какие адреса за этим конкретным пиром разрешено принимать» — обычно это его единственный туннельный IP с маской /32.

Конфигурация клиента

На стороне клиента — будь то ноутбук с Linux, macOS или приложение WireGuard на телефоне — конфиг зеркальный: он описывает себя в [Interface] и сервер в [Peer].

[Interface]
Address  =  10.10.0.2/24
PrivateKey  =  <содержимое laptop_private.key>
DNS  =  1.1.1.1

[Peer]
PublicKey  =  <содержимое server_public.key>
Endpoint  =  203.0.113.10:51820
AllowedIPs  =  0.0.0.0/0
PersistentKeepalive  =  25

Endpoint — публичный IP или домен вашего VPS с портом, на котором слушает WireGuard. AllowedIPs на клиенте определяет, какой трафик вообще пойдёт через туннель:

0.0.0.0/0 заворачивает в туннель весь трафик клиента — полноценный VPN, весь интернет идёт через VPS, и внешние сайты видят его IP вместо вашего. Если нужен только доступ к внутренним сервисам сервера, а обычный интернет пусть идёт напрямую, укажите вместо этого только туннельную подсеть, например 10.10.0.0/24 — это и есть split-tunnel. PersistentKeepalive полезен, если клиент сидит за NAT (почти всегда так и есть на телефоне или домашнем роутере): без него сервер может «потерять» клиента и перестать доставлять пакеты, пока клиент сам не пришлёт новый.

Автозапуск и firewall

Поднимаем интерфейс и включаем автозапуск при перезагрузке одной командой:

sudo systemctl enable --now wg-quick@wg0

Имя юнита wg-quick@wg0 берётся из имени файла конфигурации — wg0.conf. Проверить, что интерфейс поднялся:

sudo systemctl status wg-quick@wg0

WireGuard работает по UDP, и порт нужно открыть в файрволе. Если вы уже настроили ufw по гайду о SSH и файрволе, добавьте разрешение:

sudo ufw allow 51820/udp

Проверяем соединение

На сервере команда wg show выводит список пиров и время последнего рукопожатия — если оно есть и обновляется, туннель живой:

sudo wg show

На клиенте после подключения проверьте, что сервер отвечает внутри туннеля:

ping 10.10.0.1

И, если используется полный туннель (AllowedIPs = 0.0.0.0/0), убедитесь, что внешний мир видит IP сервера, а не ваш собственный:

curl ifconfig.me

Типовые ошибки

  • Забыли включить net.ipv4.ip_forward=1 и применить sysctl -p — туннель поднимается, пинг до сервера проходит, а дальше в интернет пакеты не идут.
  • Публичный ключ клиента в конфиге сервера не совпадает с тем, что реально сгенерирован на клиенте — рукопожатие в wg show никогда не появляется, соединение выглядит «мёртвым» без явной ошибки.
  • Порт 51820/udp открыт в ufw, но закрыт на уровне облачного провайдера — у многих VPS есть отдельная сетевая панель фильтрации трафика, и её тоже нужно проверить, а не только локальный файрвол.
  • Неверный AllowedIPs на клиенте: значение 0.0.0.0/0 без реально работающего NAT на сервере рвёт клиенту вообще весь доступ в интернет, включая обычные сайты.
  • Не совпадают маски подсети между Address на сервере и адресами пиров — из-за этого клиенты не видят друг друга, даже если каждый по отдельности достучался до сервера.

Что дальше

Туннель поднят — теперь имеет смысл спрятать за ним что-то, что не должно торчать наружу: настроим базу данных, доступ к которой будет только через этот VPN →