Свой VPN на VPS: устанавливаем WireGuard
WireGuard превращает VPS в личную точку выхода в интернет и в способ безопасно достучаться до внутренних сервисов сервера без открытых наружу портов.
Как это работает — коротко
WireGuard проще, чем OpenVPN или IPsec, и в этом его сила. У каждой стороны — сервера и каждого клиента — есть пара ключей: приватный и публичный. Стороны обмениваются публичными ключами один раз, и после этого туннель поднимается без TCP-хендшейпов, сертификатов и центра сертификации.
После установки в системе появляется новый сетевой интерфейс, обычно wg0. Трафик, который попадает в него, шифруется и оборачивается в UDP-пакеты, а на другой стороне — расшифровывается и разворачивается обратно. С точки зрения приложений это выглядит как обычная сеть: свой диапазон IP-адресов, свои маршруты.
Устанавливаем WireGuard на сервере
В современных Ubuntu LTS WireGuard есть в стандартных репозиториях, отдельный PPA не нужен.
sudo apt install -y wireguard
Пакет ставит саму реализацию и утилиты wg и wg-quick, которыми мы будем управлять туннелем.
Сервер должен не только принимать зашифрованный трафик, но и пересылать его дальше — в интернет или на другие внутренние сервисы. За это отвечает IP forwarding, по умолчанию он выключен. Включаем его на постоянной основе, добавив строку в /etc/sysctl.conf:
Применяем изменение без перезагрузки:
Генерируем ключи
Ключевая пара нужна серверу и каждому клиенту отдельно — ключи никогда не переиспользуются. Команда wg genkey создаёт приватный ключ, wg pubkey из него выводит публичный.
wg genkey | tee server_private.key | wg pubkey > server_public.key
umask 077 перед генерацией гарантирует, что файл с приватным ключом сразу создаётся без прав на чтение для остальных пользователей. Точно так же генерируем пару для каждого клиента, например для ноутбука и телефона отдельно:
wg genkey | tee phone_private.key | wg pubkey > phone_public.key
Конфигурация сервера
Основной конфиг живёт в /etc/wireguard/wg0.conf. Секция [Interface] описывает сам сервер, а каждый [Peer] — одного клиента, которому разрешено подключаться.
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].
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
Поднимаем интерфейс и включаем автозапуск при перезагрузке одной командой:
Имя юнита wg-quick@wg0 берётся из имени файла конфигурации — wg0.conf. Проверить, что интерфейс поднялся:
WireGuard работает по UDP, и порт нужно открыть в файрволе. Если вы уже настроили ufw по гайду о SSH и файрволе, добавьте разрешение:
Проверяем соединение
На сервере команда wg show выводит список пиров и время последнего рукопожатия — если оно есть и обновляется, туннель живой:
На клиенте после подключения проверьте, что сервер отвечает внутри туннеля:
И, если используется полный туннель (AllowedIPs = 0.0.0.0/0), убедитесь, что внешний мир видит IP сервера, а не ваш собственный:
Типовые ошибки
- Забыли включить
net.ipv4.ip_forward=1и применитьsysctl -p— туннель поднимается, пинг до сервера проходит, а дальше в интернет пакеты не идут. - Публичный ключ клиента в конфиге сервера не совпадает с тем, что реально сгенерирован на клиенте — рукопожатие в
wg showникогда не появляется, соединение выглядит «мёртвым» без явной ошибки. - Порт 51820/udp открыт в ufw, но закрыт на уровне облачного провайдера — у многих VPS есть отдельная сетевая панель фильтрации трафика, и её тоже нужно проверить, а не только локальный файрвол.
- Неверный
AllowedIPsна клиенте: значение0.0.0.0/0без реально работающего NAT на сервере рвёт клиенту вообще весь доступ в интернет, включая обычные сайты. - Не совпадают маски подсети между
Addressна сервере и адресами пиров — из-за этого клиенты не видят друг друга, даже если каждый по отдельности достучался до сервера.
Что дальше
Туннель поднят — теперь имеет смысл спрятать за ним что-то, что не должно торчать наружу: настроим базу данных, доступ к которой будет только через этот VPN →