SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-28

Як налаштувати WireGuard VPN на власному VPS

Налаштуйте WireGuard на Linux VPS: ключі, wg0.conf, IP forwarding, NAT, AllowedIPs і DNS. Розберіть помилки handshake та сумісність Linux 5.6+.

Що ви налаштовуєте

WireGuard VPN на власному сервері — це приблизно 40 рядків конфігурації: одна пара ключів, один файл інтерфейсу, один параметр sysctl, одне правило NAT і один отвір у firewall. Встановлення просте, тому більша частина цього посібника присвячена типовим проблемам, правам доступу до ключів, AllowedIPs, маршрутизації та DNS.

WireGuard — це тунель Layer 3 у ядрі Linux. Він входить до mainline починаючи з Linux 5.6, тому Ubuntu 24.04 і Debian 13 постачають його без зовнішнього модуля. Немає узгодження шифрів, центру сертифікації чи кроку з іменем користувача та паролем: peer — це відкритий ключ і IP-адреси, які цей ключ може використовувати. Пакет із невірною перевіркою MAC відкидається без відповіді, тому порт не відповідає на сканування. Недолік полягає в тому, що сервера автентифікації немає, тому для відкликання доступу потрібно видалити peer на сервері.

Спочатку перевірте віртуалізацію

WireGuard потребує ядра, до якого можна завантажити модуль. На KVM VPS він працює одразу після встановлення. У контейнерній віртуалізації зі спільним ядром хоста, наприклад OpenVZ або LXC, перша команда завершується помилкою RTNETLINK answers: Operation not supported. У такому разі використовуйте резервну реалізацію wireguard-go у userspace. Спочатку перевірте середовище командою sudo modprobe wireguard && echo ok.

Генеруйте ключі без їх розкриття

Файл /etc/wireguard/server.key, доступний для читання всім користувачам, фактично означає відсутність VPN. Поширений рядок umask 077 && wg genkey | sudo tee ... ненадійний, оскільки sudo застосовує власну umask до файлу, який створює tee. Явно задайте режим доступу.

sudo apt update && sudo apt install -y wireguard nftables
sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/server.key'
sudo sh -c 'wg pubkey < /etc/wireguard/server.key > /etc/wireguard/server.pub'
sudo chmod 600 /etc/wireguard/server.key

Згенеруйте пару ключів клієнта так само. wg genpsk додає необов’язковий попередньо узгоджений ключ: по одному рядку в кожній конфігурації.

Інтерфейс сервера: /etc/wireguard/wg0.conf

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of /etc/wireguard/server.key>

[Peer]
PublicKey = <laptop public key>
PresharedKey = <psk, optional>
AllowedIPs = 10.8.0.2/32

chmod 600 it; попередження під час запуску про те, що файл доступний усім користувачам, означає, що цей крок пропущено. Address — це адреса сервера всередині тунелю з маскою всієї підмережі VPN. Виберіть діапазон, який не використовують у мережах, до яких ви підключаєтеся. 192.168.1.0/24 конфліктує з половиною домашніх маршрутизаторів, за якими працюють ваші клієнти, і тоді тунель непомітно програє локальному маршруту.

AllowedIPs піра на стороні сервера — це /32, єдина адреса тунелю, що належить цьому клієнту. Якщо призначити двом пірам однакову дозволену IP-адресу, вона перейде до піра, налаштованого останнім, а перший перестане отримувати трафік без будь-яких повідомлень про помилку. Залиште SaveConfig не заданим, інакше wg-quick down перезапише цей файл із поточного стану.

Перетворіть сервер на маршрутизатор

Linux-сервер відкидає пакети, адресовані не йому. Пересилання пакетів і source NAT за замовчуванням вимкнені.

printf 'net.ipv4.ip_forward = 1\nnet.ipv6.conf.all.forwarding = 1\n' \
  | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
sysctl net.ipv4.ip_forward

Просте sysctl -w працює до наступного перезавантаження, після якого непомітно припиняє працювати. Для NAT потрібен egress-інтерфейс — мережевий інтерфейс, через який сервер виходить в інтернет, а не wg0. Не вгадуйте eth0. Визначте його за допомогою ip route show default, оскільки сучасні образи використовують такі імена, як enp1s0 або ens3.

Firewall: the port, and the forward path

One nftables file covers filter and NAT. Write /etc/nftables.conf, it flushes the existing ruleset, so skip this on a box already managed by ufw or Docker.

#!/usr/sbin/nft -f
flush ruleset

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    ct state established,related accept
    iif lo accept
    tcp dport 22 accept
    udp dport 51820 accept
  }
  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state established,related accept
    iifname "wg0" oifname "enp1s0" accept
  }
}

table ip nat {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    ip saddr 10.8.0.0/24 oifname "enp1s0" masquerade
  }
}

Apply it with sudo systemctl enable --now nftables, keeping a second SSH session open: policy drop plus a typo in the SSH rule locks you out of your own server. Note what the forward chain does not allow, wg0 to wg0. Peers reach the internet, not each other; add iifname "wg0" oifname "wg0" accept for a peer-to-peer VPN. The same chain governs what a peer may touch on the server itself, which matters when the box doubles as a remote development box running Claude Code in tmux and you would rather not expose that side of it publicly.

On a ufw box: ufw allow 51820/udp, DEFAULT_FORWARD_POLICY="ACCEPT" in /etc/default/ufw, and a *nat POSTROUTING MASQUERADE rule at the top of /etc/ufw/before.rules.

Запустіть це через systemd

sudo systemctl enable --now wg-quick@wg0
sudo wg show

wg-quick створює інтерфейс, додає адреси та встановлює маршрути, визначені на основі AllowedIPs. enable --now — це важлива частина: вручну запущений wg-quick up wg0 зникне після наступного перезавантаження, а оновлення ядра передбачають перезавантаження. Якщо unit не запускається після одного з таких перезавантажень, це залишатиметься непомітним, доки хтось не спробує підключитися. Тому OnFailure= drop-in для wg-quick@wg0 із надсиланням сповіщень на власний сервер ntfy — найдешевший спосіб отримати повідомлення на телефон, а не від користувача, якого заблоковано поза системою.

Конфігурація клієнта та параметр, який усі налаштовують неправильно

[Interface]
PrivateKey = <laptop private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1

[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

AllowedIPs одночасно виконує два різні завдання. Змішування цих завдань є основною причиною більшості непорозумінь із WireGuard.

Для вихідного трафіку це таблиця маршрутизації. Пакет, адреса призначення якого відповідає AllowedIPs певного peer, шифрується та надсилається цьому peer. 0.0.0.0/0, ::/0 спрямовує через тунель увесь трафік: це full tunnel, де сервер є маршрутом за замовчуванням. Split tunnel містить вужчий список: AllowedIPs = 10.8.0.0/24, 10.20.0.0/16 передає через VPN-трафік і одну приватну мережу за сервером, а весь інший трафік використовує локальний маршрут. Саме цей вужчий список дає змогу повністю не виставляти сервіси в публічний інтернет: приватний екземпляр Nextcloud на VPS, прив’язаний до адреси тунелю, або віртуальні машини лабораторії з вкладеною віртуалізацією, що працюють на тому самому сервері, залишаються доступними для peer і невидимими для всіх інших.

Для вхідного трафіку це список керування доступом. Розшифрований пакет від peer, адреса джерела якого відсутня в AllowedIPs цього peer, відкидається. Тому на сервері для ноутбука вказано 10.8.0.2/32: запис 0.0.0.0/0 дозволив би цьому клієнту підміняти будь-яку адресу в тунелі.

PersistentKeepalive потрібен для клієнтів за NAT, коли маршрутизатор підтримує UDP-відповідність відкритою лише під час передавання пакетів. Після завершення її строку сервер більше не може зв’язатися з клієнтом. PersistentKeepalive = 25 підтримує відповідність відкритою. Установлюйте його на клієнті, а не на сервері з публічною IP-адресою.

DNS і витік, якого ніхто не помічає

Із AllowedIPs = 0.0.0.0/0 і без рядка DNS = клієнт продовжує використовувати DNS-резолвер, отриманий від локальної мережі, — маршрутизатор у кафе за адресою 192.168.1.1. Цей маршрут специфічніший за маршрут за замовчуванням, тому DNS-запити виходять через локальне з’єднання у відкритому вигляді, тоді як увесь інший трафік проходить через тунель. Трафік захищений від перегляду; список доменних імен — ні.

Є два коректні варіанти. Вкажіть у DNS публічний резолвер (DNS = 9.9.9.9), і запити проходитимуть через тунель та виходитимуть із вашого сервера, хоча цей резолвер усе одно їх бачитиме. Або запустіть unbound чи dnsmasq, прив’язаний до 10.8.0.1, задайте DNS = 10.8.0.1 і додайте udp dport 53 iifname "wg0" accept до вхідного ланцюжка, встановіть цей рядок і не налаштовуйте резолвер — тоді нічого не резолвитиметься.

На клієнтах Linux wg-quick застосовується до DNS через resolvconf; якщо його немає, ви отримаєте resolvconf: command not found. Встановіть openresolv або задайте PostUp = resolvectl dns %i 10.8.0.1 на клієнті з systemd-resolved.

Додавання та видалення peer без розриву тунелю

Перезапуск інтерфейсу для додавання користувача відключає всіх активних користувачів. Додайте блок [Peer] до wg0.conf, а потім перезавантажте набір peer без перезапуску інтерфейсу.

sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'

wg-quick strip виводить конфігурацію без ключів, які використовує лише wg-quick (Address, DNS, PostUp), а syncconf застосовує зміни без розриву активних сесій. Оновлюються лише peer: для зміненого Address все одно потрібен повний down/up. Відкличте доступ за допомогою sudo wg set wg0 peer <public key> remove, а потім видаліть блок із файлу, інакше він знову з’явиться під час наступного перезавантаження.

Режими відмови та повідомлення, які ви побачите

Handshake не завершується. wg show показує peer без latest handshake, а клієнт записує в журнал:

Handshake for peer 1 (10.0.0.10:51820) did not complete after 5 seconds, retrying (try 2)

Пакети не надходять або не приймаються. Перевірте по черзі: чи відкритий UDP 51820 у firewall VPS і в мережевому firewall вашого провайдера — у більшості панелей це окремий параметр; чи правильні адреса та порт Endpoint; чи правильно вказані ключі. У блоці [Peer] клієнта має бути публічний ключ сервера, і навпаки. Якщо вставити приватний ключ або власний публічний ключ клієнта, виникне саме цей симптом. sudo tcpdump -ni any udp port 51820 на сервері показує, чи надходять пакети взагалі. Модуль ядра за замовчуванням нічого не записує в журнал; повідомлення WireGuard з’являються в dmesg лише після ввімкнення dynamic debug (echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control). Якщо dynamic debug увімкнено, невідповідність ключів відображається як відкидання через недійсний MAC.

Handshake працює, але інтернету немає. ping 10.8.0.1 завершується успішно, але ping 1.1.1.1 завершується тайм-аутом: не налаштовано forwarding або NAT. Перевірте, чи sysctl net.ipv4.ip_forward має значення 1, а потім спостерігайте за лічильниками, поки клієнт виконує ping, за допомогою sudo nft list ruleset або sudo iptables -t nat -L POSTROUTING -n -v. Нульова кількість пакетів у правилі masquerade означає, що в ньому неправильно вказано назву вихідного інтерфейсу. Якщо лічильник зростає, але відповіді не надходять, проблема, ймовірно, у політиці forward chain.

Інтернет працює, але імена не визначаються. ping 1.1.1.1 завершується успішно, а curl https://example.com повертає Could not resolve host. Відсутній рядок DNS або в ньому вказано resolver, недоступний зсередини тунелю.

Деякі HTTPS-сайти зависають. SSH і ping працюють, але великі сторінки завантажуються не повністю. Причина — path MTU: тунель додає службові дані, і деякий проміжний канал відкидає завеликі пакети, не повертаючи повідомлення ICMP. Зменште MTU у клієнтському [Interface], спробуйте 1420, потім 1380, а далі 1280. Якщо зменшення MTU усуває зависання, але пропускна здатність усе ще недостатня, не підбирайте значення навмання. Виконайте пошук фактичного path MTU методом бісекції та обмеження TCP MSS. Це також допоможе виключити причини, не пов’язані з тунелем.

Інтерфейс не запускається. Address already in use означає, що інший процес використовує UDP 51820. Cannot find device wg0 після невдалого up зазвичай означає, що конфігурацію відхилено. Перегляньте journalctl -u wg-quick@wg0 -n 50.

Перенесення зі Streisand або OpenVPN

Streisand більше не підтримується, а його репозиторій архівовано. Запуск VPN на занедбаній системі автоматизації створює довготривалу проблему безпеки. Оновлення на місці немає, а PKI OpenVPN не конвертується: у WireGuard немає сертифікатів, CA та строку дії, тому для кожного клієнта потрібно створити нову пару ключів.

Виконуйте міграцію паралельно. WireGuard на UDP 51820 може працювати поруч з OpenVPN на 1194 на тому самому сервері. Розгорніть wg0, переносьте клієнтів по одному, а потім зупиніть старий сервіс. Модель OpenVPN із іменами користувачів, паролями та відкликанням доступу не переноситься. Якщо потрібні облікові записи або журнал аудиту, додайте відповідний рівень над WireGuard.

Резервні копії, оновлення та фактори, що створюють навантаження в масштабі

/etc/wireguard є сервером. Створіть його резервну копію (sudo tar czf wg-backup.tgz -C /etc wireguard, режим 600, зберігайте за межами цього сервера), і ви зможете відновити його на новому VPS за кілька хвилин. Якщо втратити приватний ключ сервера, конфігурацію кожного клієнта доведеться створити заново, оскільки клієнти фіксують публічний ключ сервера. Оновлення — це звичайний apt upgrade і перезавантаження для оновлень ядра, а wg-quick@wg0 самостійно відновлює роботу, якщо його було ввімкнено.

Стан кожного вузла невеликий, а криптографічні операції виконуються в ядрі. Тому обмеженням буде пропускна здатність CPU і мережі вашого VPS, а не параметри цього конфігураційного файлу. Вимірюйте її за допомогою iperf3 через тунель, а не покладайтеся на опубліковані показники. У масштабі найбільше навантаження створюють операційні процеси. Кожному вузлу потрібна унікальна IP-адреса тунелю. Ручне редагування шістдесяти блоків [Peer] призводить до появи дублікатів AllowedIPs: генеруйте конфігурації скриптом. Один сервер — це один UDP endpoint і одна точка відмови, а WireGuard не має кластеризації. Резервування означає використання другого сервера з власними ключами. Ротація ключів залишається ручною, тому зафіксуйте, хто зберігає кожен ключ і як його відкликати. Коли такий облік перестає вміщатися в текстовому файлі, зазвичай використовують control plane поверх того самого kernel data plane. Self-hosted сервер NetBird бере на себе розподіл адрес, поширення даних про вузли та setup keys, які інакше довелося б налаштовувати вручну. Якщо самостійне розгортання цього control plane додає ще один зайвий сервер, Tailscale може розмістити його замість вас, а його безкоштовний план охоплює шість користувачів із необмеженою кількістю пристроїв. Для більшості особистих інфраструктур цього достатньо, тому платити за нього не доводиться. Після цього оплата залежить від кількості людей, а не машин, тому фактична вартість для домогосподарства або невеликої команди визначається кількістю користувачів із обліковими записами, а не кількістю вузлів, які довелося б вручну додавати до wg0.conf. У такій схемі облік split-tunnel AllowedIPs замінюється на оголошення приватних діапазонів через subnet router. Їх оголошують один раз з одного VPS і централізовано підтверджують, замість того щоб вставляти їх у файл конфігурації кожного клієнта. Чи варто переходити на таку схему, залежить від того, до яких ресурсів фактично може отримати доступ hosted control plane. Він ніколи не зберігає ключі, якими шифрується ваш трафік, але визначає, які вузли дізнаються один про одного.

Для всього цього потрібні Linux-сервер, яким ви керуєте, публічна IP-адреса, ядро, до якого можна завантажити модуль, і firewall, яким ви повністю керуєте.

FAQ

Чому рукостискання WireGuard ніколи не завершується?

wg show, у якому немає latest handshake, означає, що пакети не надходять або не приймаються. Перевірте UDP 51820 у firewall VPS і в окремому мережевому firewall вашого провайдера. Перевірте хост і порт у Endpoint. Потім переконайтеся, що ключі не переплутані: блок [Peer] на клієнті має містити public key сервера. sudo tcpdump -ni any udp port 51820 на сервері показує, чи надходять пакети взагалі. dmesg повідомляє лише про помилки рукостискання WireGuard після ввімкнення динамічного debug (echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control). Після цього невідповідність ключів відображається як відкидання через недійсний MAC.

Тунель підключається, але доступу до інтернету немає. Чого бракує?

Якщо ping 10.8.0.1 працює, а ping 1.1.1.1 завершується тайм-аутом, проблема пов’язана з forwarding або NAT. Переконайтеся, що sysctl net.ipv4.ip_forward має значення 1 і це значення задано в /etc/sysctl.d/, а не лише через sysctl -w, який зникає після перезавантаження. Потім перевірте, чи правило masquerade використовує фактичний вихідний інтерфейс із ip route show default, enp1s0 або, рідше, ens3 і eth0.

Чи потрібен рядок DNS = у конфігурації клієнта?

Якщо використовується full tunnel і рядок DNS = відсутній, клієнт продовжує використовувати resolver, отриманий від локальної мережі. Ці запити передаються у відкритому вигляді через локальний канал, тоді як решта трафіку проходить через тунель. Вкажіть у DNS публічний resolver або запустіть unbound/dnsmasq, прив’язаний до 10.8.0.1, і відкрийте udp dport 53 iifname "wg0" у input chain.

Що саме контролює AllowedIPs?

Він виконує дві функції. Для вихідного трафіку це таблиця маршрутизації: трафік, що відповідає AllowedIPs peer, шифрується та надсилається цьому peer. Для вхідного трафіку це список контролю доступу: розшифрований пакет, джерело якого не входить до AllowedIPs цього peer, відкидається. Тому на стороні сервера для кожного клієнта вказують /32, тоді як на стороні клієнта можна вказати 0.0.0.0/0.

Чи працюватиме WireGuard на будь-якому VPS?

На KVM VPS WireGuard працює з модулем ядра без додаткового налаштування. У контейнерній віртуалізації зі спільним ядром хоста, наприклад OpenVZ або LXC, modprobe wireguard завершується помилкою Operation not supported. У такому разі використовуйте користувацьку реалізацію wireguard-go. Перед будь-якими іншими діями виконайте sudo modprobe wireguard && echo ok.