Почему WireGuard, а не OpenVPN
WireGuard был представлен в 2016 году и с версии ядра Linux 5.6 (март 2020) встроен прямо в ядро. Вот почему он лучше:
| Параметр | WireGuard | OpenVPN |
|---|---|---|
| Строк кода | ~4 000 | ~70 000 |
| Скорость | Близко к скорости канала | 200–500 Мбит/с типично |
| Криптография | ChaCha20-Poly1305, Curve25519, BLAKE2s | AES-256-GCM, RSA, гибко |
| Протокол | UDP только | UDP / TCP |
| Смена сети (WiFi→LTE) | Без разрыва | Переподключение |
| Сложность настройки | Простая | Средняя |
| Встроен в ядро Linux | С 5.6 (2020) | Нет (userspace) |
Меньше кода = меньше уязвимостей. Работа в ядре Linux = максимальная скорость без userspace-накладных расходов.
Шаг 1: Установка WireGuard на сервер
Подключитесь к серверу по SSH и выполните:
apt update
apt install -y wireguard curl qrencodeНа Ubuntu 22.04 WireGuard уже есть в стандартных репозиториях, а модуль встроен в ядро (5.15). qrencode понадобится позже для QR-кода мобильным клиентам.
На AlmaLinux 9 / Rocky Linux 9 / RHEL 9 модуль ядра нужно ставить отдельно из репозитория ELRepo:
dnf install -y epel-release
dnf install -y https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm
dnf install -y kmod-wireguard wireguard-tools qrencode
modprobe wireguardНа AlmaLinux 10 / Rocky 10 модуль уже в ядре 6.x — достаточно dnf install -y wireguard-tools qrencode.
Шаг 2: Генерация ключей
WireGuard использует пары ключей (приватный + публичный). Генерируем для сервера:
cd /etc/wireguard
umask 077 # новые файлы создаются с правами 600 — приватные ключи сразу защищены
wg genkey | tee server.key | wg pubkey > server.pub
wg genkey | tee client1.key | wg pubkey > client1.pubumask 077 действует в рамках текущей сессии bash и гарантирует, что приватные ключи не попадут к другим пользователям даже на мгновение. Если вы вернётесь к серверу позже в новой SSH-сессии и будете снова генерировать ключи — повторите umask 077 заново.
Сохраните значения ключей — они понадобятся в конфигах:
cat server.key # приватный ключ сервера — только в [Interface] на сервере (wg0.conf)
cat server.pub # публичный ключ сервера — в [Peer] секции конфига клиента
cat client1.key # приватный ключ клиента — только в [Interface] конфига клиента
cat client1.pub # публичный ключ клиента — в [Peer] секции wg0.conf на сервереserver.key, client1.key) нельзя передавать никому. Публичные ключи (*.pub) — безопасны для передачи.Шаг 3: Конфигурация сервера
Создаём файл /etc/wireguard/wg0.conf. Команда ниже подставит ключи и имя интерфейса автоматически — никаких ручных правок:
Сначала определяем имя внешнего сетевого интерфейса (обычно eth0, ens3, enp0s3) — через него клиенты будут выходить в интернет:
# Извлекаем имя интерфейса из default-маршрута
IFACE=$(ip route show default | grep -oP 'dev \K\S+' | head -1)
echo "Внешний интерфейс: $IFACE"
# Если вывод пустой — посмотрите вручную и задайте сами:
# ip -br link # покажет все интерфейсы (eth0, ens3, enp0s3 и т.д.)
# IFACE=eth0 # подставьте нужное имяСледующий блок (cat > /etc/wireguard/wg0.conf) выполняйте в той же SSH-сессии — переменная $IFACE живёт только в текущем shell. Если разорвали соединение — пересоздайте её командой выше.
SERVER_PRIVATE=$(cat /etc/wireguard/server.key)
CLIENT1_PUBLIC=$(cat /etc/wireguard/client1.pub)
if [ -z "$IFACE" ]; then
echo "ОШИБКА: IFACE пустой — задайте IFACE=eth0 и повторите этот блок"
else
umask 077 # файл конфига сразу создаётся с правами 600 — приватный ключ защищён
cat > /etc/wireguard/wg0.conf << EOF
[Interface]
PrivateKey = $SERVER_PRIVATE
Address = 10.0.0.1/24
ListenPort = 51820
# NAT и форвардинг — каждая команда отдельной строкой для наглядности
PostUp = iptables -I FORWARD -i wg0 -j ACCEPT
PostUp = iptables -I FORWARD -o wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o $IFACE -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o $IFACE -j MASQUERADE
[Peer]
# Клиент 1
PublicKey = $CLIENT1_PUBLIC
AllowedIPs = 10.0.0.2/32
EOF
chmod 600 /etc/wireguard/wg0.conf
echo "Конфиг создан: /etc/wireguard/wg0.conf"
fi- •
Address = 10.0.0.1/24— IP сервера в VPN-сети (подсеть 10.0.0.0/24) - •
ListenPort = 51820— UDP-порт WireGuard (можно изменить) - •
-I FORWARD— вставляем правила в начало цепочки, чтобы они сработали раньше правил UFW - •
POSTROUTING MASQUERADE— NAT: клиенты выходят в интернет через IP сервера - •
AllowedIPs = 10.0.0.2/32— IP первого клиента в VPN-сети
$IFACE подставляется в файл на момент создания. Если после обновления ядра интерфейс переименуется (например, eth0 → ens3), откройте wg0.conf и обновите имя в строках PostUp/PostDown вручную.Проверьте, что конфиг создан корректно:
cat /etc/wireguard/wg0.confШаг 4: IP-форвардинг и NAT
Без IP-форвардинга сервер не будет перенаправлять трафик клиентов в интернет. Это самая частая причина «VPN подключён, но интернета нет».
cat > /etc/sysctl.d/99-wireguard.conf << EOF
net.ipv4.ip_forward = 1
EOF
sysctl --systemПроверяем, что применилось:
sysctl net.ipv4.ip_forward
# Должно вернуть: net.ipv4.ip_forward = 1Правила iptables (PostUp/PostDown) прописаны в wg0.conf и применятся автоматически при старте и остановке интерфейса — дополнительных команд iptables вводить не нужно.
[Interface] (например, fd42:42::1/64), симметричные правила ip6tables в PostUp/PostDown, net.ipv6.conf.all.forwarding = 1 в sysctl.Шаг 5: Запуск и автозапуск
Сначала открываем порт в файрволле, затем запускаем WireGuard. Проверьте, активен ли UFW:
ufw status
# Если "inactive" — UFW выключен, переходите к следующему шагу
# Если "active" — открываем порт:
ufw allow 51820/udpiptables -A INPUT -p udp --dport 51820 -j ACCEPT
# Чтобы правило пережило reboot (флаг noninteractive отключает интерактивный вопрос):
DEBIAN_FRONTEND=noninteractive apt install -y iptables-persistent
netfilter-persistent savesystemctl enable --now wg-quick@wg0Проверяем статус:
systemctl status wg-quick@wg0
# Должно быть: active (exited) — это нормально для WireGuard
# wg-quick запускает интерфейс и завершается; сам интерфейс живёт в ядре
wg show
# Покажет: интерфейс wg0, публичный ключ сервера, порт 51820, список пировШаг 6: Настройка клиента
Генерируем конфиг клиента прямо на сервере — ключи и IP подставляются автоматически:
CLIENT1_PRIVATE=$(cat /etc/wireguard/client1.key)
SERVER_PUBLIC=$(cat /etc/wireguard/server.pub)
# Определяем публичный IP сервера с резервными источниками
SERVER_IP=$(curl -fsS -4 --max-time 5 https://api.ipify.org \
|| curl -fsS -4 --max-time 5 https://ifconfig.me/ip \
|| curl -fsS -4 --max-time 5 https://ipinfo.io/ip)
echo "Публичный IP сервера: $SERVER_IP"
if [ -z "$SERVER_IP" ]; then
echo "ОШИБКА: не удалось определить IP — задайте вручную: SERVER_IP=1.2.3.4"
else
umask 077 # конфиг клиента создаётся с правами 600 — приватный ключ защищён
cat > /etc/wireguard/wg-client1.conf << EOF
[Interface]
PrivateKey = $CLIENT1_PRIVATE
Address = 10.0.0.2/32
DNS = 1.1.1.1
[Peer]
PublicKey = $SERVER_PUBLIC
Endpoint = $SERVER_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF
chmod 600 /etc/wireguard/wg-client1.conf
echo "Конфиг клиента создан: /etc/wireguard/wg-client1.conf"
fi- •
Address = 10.0.0.2/32— IP клиента в VPN (только его адрес, /32) - •
AllowedIPs = 0.0.0.0/0— весь IPv4-трафик идёт через VPN - •
PersistentKeepalive = 25— keepalive каждые 25 сек, поддерживает соединение за NAT - •
DNS = 1.1.1.1— DNS-запросы через VPN на сервер Cloudflare
Android и iOS
Установите приложение WireGuard из App Store / Google Play. Генерируем QR-код прямо в терминале сервера (qrencode поставили на шаге 1):
qrencode -t ansiutf8 < /etc/wireguard/wg-client1.confВ приложении нажмите «+» → «Create from QR code» и наведите камеру на терминал (на iOS приложение попросит разрешить доступ к камере). На светлом фоне терминала QR читается хуже — переключите тему терминала на тёмную либо используйте qrencode -t ansi256utf8.
Windows и macOS
Скачайте файл конфига с сервера на локальный компьютер. На большинстве облачных образов Ubuntu SSH под root отключён — сперва скопируйте конфиг в домашнюю папку sudo-пользователя (замените USER на имя вашего пользователя):
cp /etc/wireguard/wg-client1.conf /home/USER/
chown USER:USER /home/USER/wg-client1.confscp USER@ВАШ_IP_СЕРВЕРА:/home/USER/wg-client1.conf ./wg-client1.confЕсли на вашем сервере root-SSH разрешён, можно скачать напрямую одной командой: scp root@ВАШ_IP_СЕРВЕРА:/etc/wireguard/wg-client1.conf ./wg-client1.conf.
Дальше — установка и импорт конфига в приложение:
- • Windows: скачайте приложение с wireguard.com/install. Нажмите стрелку рядом с «Add Tunnel» → «Import tunnel(s) from file» (или
Ctrl+O) и выберитеwg-client1.conf. - • macOS: установите приложение из Mac App Store (на wireguard.com/install кнопка macOS ведёт туда же). В приложении нажмите «+» → «Import Tunnel(s) from File…» (или
⌘+O) и выберитеwg-client1.conf.
Выберите туннель в списке слева и нажмите Activate — статус сменится на Active.
Linux (клиент)
На Ubuntu/Debian есть тонкий момент: строка DNS = 1.1.1.1 требует утилиты resolvconf, иначе wg-quick up завершится ошибкой resolvconf: command not found. При этом на Ubuntu 22.04 по умолчанию DNS уже обслуживает systemd-resolved, и установка конфликтующегоopenresolv может вызвать «signature mismatch». Чище всего — использовать PostUp/PostDown на resolvectl, который уже есть в системе:
apt update
apt install -y wireguard
# Скачиваем конфиг с сервера (если root-SSH закрыт — см. заметку выше про scp через sudo-пользователя)
scp root@ВАШ_IP_СЕРВЕРА:/etc/wireguard/wg-client1.conf /etc/wireguard/wg0.conf
chmod 600 /etc/wireguard/wg0.confШаг 2 — отредактируйте /etc/wireguard/wg0.conf через nano /etc/wireguard/wg0.conf: удалите строку DNS = 1.1.1.1 и сразу под строкой [Interface] добавьте:
PostUp = resolvectl dns %i 1.1.1.1; resolvectl domain %i ~.
PostDown = resolvectl revert %i%i — плейсхолдер wg-quick: он сам подставит имя интерфейса (wg0). Сохраните файл (Ctrl+O, Enter, Ctrl+X) и запускайте:
systemctl enable --now wg-quick@wg0
# Временно остановить / снова запустить:
# systemctl stop wg-quick@wg0
# systemctl start wg-quick@wg0
# Убрать из автозапуска:
# systemctl disable wg-quick@wg0Вариант «оставить DNS = 1.1.1.1 и поставить openresolv/resolvconf» не рекомендую: оба пакета перехватят /etc/resolv.conf у systemd-resolved и часто приводят к проблемам при обновлении. Путь через resolvectl выше — чище.
Шаг 7: Проверка подключения
После подключения клиента проверьте на сервере:
wg show
# Сразу после запуска: интерфейс wg0, список peer-ов без handshake
# После первого подключения клиента появится:
# latest handshake: X seconds ago
# transfer: N KiB received, N KiB sentНа стороне клиента убедитесь, что IP сменился:
curl -s https://ifconfig.me/ip
# Должен вернуть IP вашего VPS, а не домашний IPПроверьте доступность внутреннего адреса сервера:
ping 10.0.0.1
# Ответы подтверждают, что туннель работает.
# Если ping не идёт, но curl ifconfig.me уже показал IP VPS — значит туннель
# работает, а ICMP просто фильтруется (некритично).Добавление новых клиентов
Каждый новый пользователь — новая пара ключей и новый IP в VPN-сети:
cd /etc/wireguard
umask 077
wg genkey | tee client2.key | wg pubkey > client2.pub
# Добавляем нового пира в конфиг сервера
CLIENT2_PUBLIC=$(cat client2.pub)
echo "
[Peer]
# Клиент 2
PublicKey = $CLIENT2_PUBLIC
AllowedIPs = 10.0.0.3/32" >> /etc/wireguard/wg0.confПрименяем без перезапуска сервиса (активные клиенты не отключатся):
wg-quick strip wg0 | wg syncconf wg0 /dev/stdin
# syncconf перечитывает только секции [Peer] (ключи, AllowedIPs, Endpoint).
# Если меняли [Interface] — Address, DNS, PostUp, PostDown — нужен полный
# перезапуск (прервёт активные сессии на ~2 секунды):
# systemctl restart wg-quick@wg0Генерируем конфиг для клиента 2 (аналогично первому, только другой IP и ключ):
CLIENT2_PRIVATE=$(cat /etc/wireguard/client2.key)
SERVER_PUBLIC=$(cat /etc/wireguard/server.pub)
SERVER_IP=$(curl -fsS -4 --max-time 5 https://api.ipify.org \
|| curl -fsS -4 --max-time 5 https://ifconfig.me/ip \
|| curl -fsS -4 --max-time 5 https://ipinfo.io/ip)
echo "Публичный IP сервера: $SERVER_IP"
if [ -z "$SERVER_IP" ]; then
echo "ОШИБКА: не удалось определить IP — задайте вручную: SERVER_IP=1.2.3.4"
else
umask 077
cat > /etc/wireguard/wg-client2.conf << EOF
[Interface]
PrivateKey = $CLIENT2_PRIVATE
Address = 10.0.0.3/32
DNS = 1.1.1.1
[Peer]
PublicKey = $SERVER_PUBLIC
Endpoint = $SERVER_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF
chmod 600 /etc/wireguard/wg-client2.conf
echo "Конфиг клиента 2 создан: /etc/wireguard/wg-client2.conf"
fiТипичные проблемы и решения
✗VPN подключён, но интернета нет
Решение: Четыре вещи: (1) sysctl net.ipv4.ip_forward — должно быть 1; (2) iptables -t nat -L POSTROUTING -n -v — должно быть правило MASQUERADE; (3) iptables -L FORWARD -n -v — должны быть правила ACCEPT для wg0; (4) в клиентском конфиге AllowedIPs = 0.0.0.0/0 (весь трафик через VPN). Если правил iptables нет — перезапустите: systemctl restart wg-quick@wg0.
✗Клиент не может подключиться (таймаут)
Решение: На сервере: systemctl status wg-quick@wg0 — сервис должен быть active (exited). Затем: ss -ulnp | grep 51820 — порт слушается (PID будет пустой, это нормально: WireGuard работает в ядре и не создаёт userspace-сокет). Проверка через wg show wg0 надёжнее. Имейте в виду: nmap -sU -p 51820 почти всегда вернёт open|filtered — WireGuard намеренно игнорирует «пробы», чтобы не палить порт. Проверяйте файрволл в панели управления VPS-провайдера — он может блокировать UDP независимо от UFW.
✗wg-quick up падает с resolvconf: command not found
Решение: На Linux-клиенте строка DNS = в конфиге обрабатывается через resolvconf, а wireguard-tools его не тянет как зависимость. Рекомендуемый путь: убрать строку DNS = и задать DNS через PostUp = resolvectl dns %i 1.1.1.1; resolvectl domain %i ~. и PostDown = resolvectl revert %i — это работает на Ubuntu 22.04 «из коробки», без установки дополнительных пакетов. На RHEL/AlmaLinux 9, если systemd-resolved ещё не активен: dnf install -y systemd-resolved && systemctl enable --now systemd-resolved.
✗DNS не работает через VPN
Решение: Проверьте, что DNS прописан в клиентском конфиге: либо через строку DNS = 1.1.1.1 (при наличии resolvconf), либо через PostUp = resolvectl dns %i 1.1.1.1; resolvectl domain %i ~. (%i — плейсхолдер wg-quick, он сам подставляет имя интерфейса). Проверка на клиенте после подключения: resolvectl status wg0 — поле DNS Servers должно показать 1.1.1.1.
✗Docker на сервере ломает FORWARD-цепочку
Решение: Если после установки Docker исчез интернет у VPN-клиентов — Docker переписал политику FORWARD. Разрешите трафик из wg0 явно: iptables -I DOCKER-USER -i wg0 -j ACCEPT. Либо перезапустите wg-quick@wg0 — правила PostUp встанут заново.
✗UFW активен, но форвардинг не работает
Решение: Проверьте /etc/default/ufw — параметр DEFAULT_FORWARD_POLICY должен быть ACCEPT (по умолчанию DROP). Исправьте и выполните ufw reload. Также в /etc/ufw/sysctl.conf строка net/ipv4/ip_forward=1 должна быть раскомментирована — иначе при reboot UFW откатит ваш sysctl.
✗WireGuard не запускается: «Cannot find device wg0»
Решение: Модуль ядра недоступен: WireGuard встроен в Linux с 5.6. Ubuntu 22.04 (ядро 5.15) — OK. Если это AlmaLinux 9 / Rocky 9 — установите kmod-wireguard из ELRepo (см. шаг 1) и выполните modprobe wireguard. Проверить загруженность модуля: lsmod | grep wireguard.