Як розгорнути self-hosted NetBird VPN на VPS
Налаштуйте mesh VPN NetBird на одному VPS: DNS і TLS, закріплений quickstart script, setup keys для peer-ів без нагляду та порівняння з Headscale.
Що дає self-hosting VPN-сервера NetBird
Self-hosting VPN-сервера NetBird розміщує control plane на VPS, яким ви керуєте. Це частина системи, яка зберігає список peer-ів, визначає, яка машина може підключатися до якої, і допомагає двом peer-ам знаходити один одного за NAT (network address translation). Самі тунелі й далі працюють через WireGuard і шифруються безпосередньо між вашими машинами. Змінюється те, що жодна зовнішня компанія не зберігає список ваших пристроїв і не керує процесом входу. Важливо чітко розуміти, що саме це дає: hosted control plane також не має ключів, які шифрують ваш трафік, а що насправді може зробити coordination server у разі компрометації — це вужчий перелік, ніж зазвичай припускають до ознайомлення з ним.
NetBird поєднує дві знайомі вам концепції. Це mesh overlay, тому peer-и підключаються один до одного, а не передають увесь трафік через один gateway. Водночас NetBird можна повністю розгорнути власними силами, тому він конкурує з Headscale — self-hosted control server для Tailscale. Якщо ви раніше використовували лише тунель через один gateway, спочатку прочитайте про різницю між звичайним WireGuard і mesh overlay, оскільки саме ця модель допоможе зрозуміти решту цього матеріалу.
Якщо насправді вам потрібен один сервер, через який виходитиме весь ваш трафік, mesh використовує складнішу інфраструктуру, ніж потрібно для цього завдання. Звичайний WireGuard VPN на одному VPS або exit node у Tailscale забезпечує це з набагато меншою кількістю компонентів. Якщо ж потрібно підключитися до однієї приватної мережі, а не об’єднати машини між собою, Tailscale subnet router на VPS оголосить цей діапазон у вашому наявному tailnet без використання наведеного нижче стека.
Що фактично запускає цей стек
Структура нещодавно змінилася, і в більшості старих інструкцій описано попередню версію. Станом на August 2026 року, у release v0.76.2, quickstart script за замовчуванням записує Compose file із трьома services.
netbird-serverмістить management API, signal service, relay з вбудованим STUN listener і вбудований identity provider. У старих release це були окремі containers, а identity provider був окремою інсталяцією Zitadel, яку потрібно було спочатку підготувати.dashboard— це admin web console.traefikзавершує TLS (transport layer security) і під час першого запуску запитує сертифікат у Let's Encrypt.
Є ще два services. Вони залишаються вимкненими, якщо під час prompt не відповісти yes. NetBird Proxy service публікує внутрішні services на публічних hostnames. CrowdSec фільтрує зловмисний network traffic. Для побудови робочої mesh network не потрібен жоден із них. На невеликому сервері обидва додатково споживають пам’ять.
Якщо ви переходите з wg-easy в одному Docker container, кількість компонентів зростає. Натомість ви отримуєте access policies і облікові записи окремих користувачів, а peers підключаються безпосередньо один до одного, а не через один gateway.
Що потрібно підготувати
Публічне доменне ім’я є обов’язковим. Dashboard, API і relay працюють через HTTPS на порту 443, а Traefik отримує сертифікат від Let's Encrypt за допомогою HTTP challenge. Для цього потрібне ім’я, яке з публічного інтернету резолвиться на цей VPS. У цій схемі сама IP-адреса не підійде.
Створіть один A-запис, netbird.example.com, що вказує на публічну IPv4-адресу VPS, і дочекайтеся його оновлення, перш ніж щось запускати.
dig +short netbird.example.comКоманда має вивести адресу вашого сервера. Якщо запустити інсталятор до завершення поширення DNS-запису, запит сертифіката завершиться помилкою під час першого запуску. Повторні невдалі перевірки можуть призвести до обмежень Let's Encrypt за частотою запитів, і тоді доведеться чекати годину перед новою спробою.
З інтернету мають бути доступні три порти: TCP 80 для перевірки сертифіката та перенаправлення на HTTPS, TCP 443 для dashboard, API, signal і relay-трафіку, а також UDP 3478 для STUN.
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 3478/udp
sudo ufw reload
sudo ufw statusТакож відкрийте їх у мережевому firewall вашого провайдера. У більшості панелей VPS це окремий елемент керування. Саме через нього сервер може відмовляти в підключеннях, навіть якщо його власний ufw status налаштований правильно.
STUN (session traversal utilities for NAT) дає змогу peer визначити публічні адресу й порт, призначені його NAT, щоб два peer могли спробувати встановити прямий тунель. Якщо заблокувати UDP 3478, peer усе одно підключаться через relay на TCP 443, тому явної помилки не буде. Натомість на кожному peer ви отримаєте Connection type: Relayed, а весь трафік проходитиме через VPS, а не безпосередньо між peer.
На рівні програмного забезпечення потрібні Docker із плагіном Compose v2, а також jq і curl. Скрипт перевіряє всі ці компоненти й зупиняється, якщо будь-якого з них немає. Якщо Docker щойно встановлено на цьому сервері, спочатку налаштуйте робочий Docker Compose на VPS.
Порти, якщо не використовувати вбудований reverse proxy
Робота без Traefik означає, що окремі сервіси будуть доступні безпосередньо, а список портів стане довшим:
- TCP 80, перенаправлення HTTP
- TCP 443, HTTPS
- TCP 33073, керування через gRPC
- TCP 10000, signal через gRPC
- TCP 33080, relay через WebSocket або QUIC
- UDP 3478, STUN
Обирайте цей варіант лише тоді, коли сервер уже завершує TLS для іншого сервісу. В іншому разі вбудований Traefik означає менше правил і менше помилок.
Встановіть сервер NetBird за допомогою quickstart-скрипту
У документації наведено однорядкову команду, яка передає останній release безпосередньо в shell:
curl -fsSL https://github.com/netbirdio/netbird/releases/latest/download/getting-started.sh | bashЗамість цього зафіксуйте версію. latest змінюється, тому та сама команда, виконана з інтервалом у два тижні, створює дві різні інсталяції. На диску також не залишається інформації про те, яка версія записала конфігурацію. Завантажте позначений release, прочитайте його, а потім запустіть.
mkdir -p ~/netbird
cd ~/netbird
curl -fsSL -o getting-started.sh \
https://github.com/netbirdio/netbird/releases/download/v0.76.2/getting-started.sh
less getting-started.sh
bash getting-started.shСпочатку скрипт запитує домен:
Enter the domain you want to use for NetBird (e.g. netbird.my-domain.com):Потім він запитує, як оброблятиметься TLS:
Which reverse proxy will you use?
[0] Traefik (recommended - automatic TLS, included in Docker Compose)
[1] Existing Traefik (labels for external Traefik instance)
[2] Nginx (generates config template)
[3] Nginx Proxy Manager (generates config + instructions)
[4] External Caddy (generates Caddyfile snippet)
[5] Other/Manual (displays setup documentation)
Enter choice [0-5] (default: 0):Виберіть [0]. Варіанти 2–5 записують фрагмент конфігурації та залишають налаштування з’єднання на ваш розсуд. Це правильно для сервера, на якому вже працює проксі, але неправильно для нового сервера. Після вибору варіанта 0 скрипт запитає адресу електронної пошти для Let's Encrypt. Вона використовується для сповіщень про завершення строку дії сертифіката.
Під час першої інсталяції відмовтеся від сервісу NetBird Proxy. Для нього потрібні ще 2 DNS-записи: proxy.netbird.example.com і wildcard-запис *.proxy.netbird.example.com. Для звичайної mesh-мережі цей сервіс не потрібен. Також відмовтеся від CrowdSec. Обидва компоненти можна додати пізніше.
Скрипт записує файли в поточний каталог: docker-compose.yml, config.yaml з правами 600, dashboard.env і traefik-dynamic.yaml, якщо ви вибрали вбудований Traefik. Вважайте цей каталог даними стану, які потрібно зберігати, оскільки config.yaml містить ключ шифрування даних у сховищі. Повторна інсталяція не виправить втрату цього ключа.
docker compose ps
docker compose logs -f netbird-serverКожен сервіс має читати running, а журнал сервера має перейти у стабільний стан, без циклічних перезапусків. Окремо перевірте сертифікат:
docker compose logs traefik | grep -i acmeACME (automatic certificate management environment) — це протокол, який Traefik використовує для отримання сертифіката. Помилки на цьому етапі майже завжди спричинені DNS або закритим портом 80.
Створення першого облікового запису адміністратора
Відкрийте https://netbird.example.com. У новій інсталяції відкриється сторінка налаштування, а не форма входу. Введіть адресу електронної пошти, ім’я та пароль, а потім натисніть Create Account. Цей обліковий запис стане першим адміністратором, після чого сторінка перенаправить вас до форми входу.
Цей обліковий запис зберігається у власному сховищі користувачів NetBird, яке працює на основі постачальника ідентифікації, вбудованого в контейнер netbird-server. Зовнішні компоненти не використовуються. Це головна відмінність від self-hosted NetBird річної давності: тоді працездатна інсталяція вимагала спочатку розгорнути Zitadel або Keycloak і скопіювати чотири значення OIDC (OpenID Connect) у setup.env, інакше система взагалі не запускалася.
Якщо замість сторінки налаштування браузер показує попередження про сертифікат, сертифікат не було випущено. Виправте це, перш ніж продовжувати, оскільки dashboard звертається до API через те саме ім’я хоста й за некоректного сертифіката працює непередбачувано.
Приєднання першого peer
Встановіть клієнт на будь-якій Linux-машині, зокрема на самому VPS, якщо хочете додати його до mesh:
curl -fsSL https://pkgs.netbird.io/install.sh | shУ Debian і Ubuntu цей скрипт налаштовує репозиторій пакетів NetBird, а потім встановлює клієнт через apt. У результаті пакетом у будь-якому разі керує пакетний менеджер. Якщо ви не хочете передавати скрипт через pipe до shell, спочатку збережіть його за допомогою curl -fsSL -o install.sh https://pkgs.netbird.io/install.sh і прочитайте перед виконанням sh install.sh. У будь-якому разі перевірте, що саме встановилося:
apt-cache policy netbirdnetbird — це клієнт командного рядка та daemon. netbird-ui — це desktop tray app, яка не потрібна на headless-сервері.
Тепер підключіть клієнт до свого сервера:
sudo netbird up --management-url https://netbird.example.comЯкщо не вказати --management-url, клієнт зареєструється в hosted-сервісі NetBird, оскільки це значення за замовчуванням, вбудоване в клієнт. Команда все одно завершиться успішно, машина все одно отримає адресу, а self-hosted dashboard залишиться порожнім. Майже всі хоча б одного разу стикаються з цією проблемою.
Команда виведе URL, який потрібно відкрити в браузері, щоб завершити вхід. Після цього:
netbird status
ip addr show wt0З netbird status потрібно прочитати чотири рядки: Management: Connected, Signal: Connected, рядок Relays: з інформацією про кожен доступний relay і NetBird IP: в overlay-діапазоні. wt0 — це інтерфейс WireGuard, який створює NetBird. Він має використовувати ту саму адресу.
Додавання другої машини без участі користувача за допомогою setup key
Вхід через браузер не працює для машини без браузера та користувача перед нею. Setup key — це токен попередньої автентифікації, який реєструє машину без інтерактивного кроку. Створіть його в dashboard у розділі Setup Keys.
Є два типи ключів. Одноразовий ключ автентифікує рівно одну машину, після чого його буде використано. Повторно використовуваний ключ реєструє багато машин, за потреби з обмеженням їхньої кількості. Для обох типів можна вказати строк дії. Обидва також можуть автоматично додати новий peer до групи, тому правила доступу цієї групи застосовуються одразу після появи машини.
sudo netbird up --setup-key <SETUP-KEY> \
--management-url https://netbird.example.com \
--hostname build-runner-01--hostname задає ім’я, яке відображається в dashboard. Якщо його не вказати, peer отримає ім’я, під яким машина ідентифікує себе. Список записів, названих ubuntu, не допомагає в керуванні машинами.
Для контейнерів і короткоживучих build agents під час створення ключа позначте його як ephemeral. Peers, зареєстровані за допомогою ephemeral key, автоматично видаляються після перебування в offline-стані понад 10 minutes. Це не дає неактивним записам накопичуватися у списку peers.
Перед використанням setup keys врахуйте важливе обмеження: завершення строку дії або видалення ключа зупиняє нові реєстрації, але не від’єднує машини, які вже зареєструвалися за його допомогою. Щоб забрати доступ у машини, потрібно видалити відповідний peer.
Чи потрібен окремий identity provider?
Для невеликої інсталяції — ні. Вбудоване сховище користувачів обробляє облікові записи, створені в dashboard, і цього достатньо для кількох користувачів.
Зовнішній identity provider потрібен, якщо він у вас уже є і ви не хочете підтримувати другий список користувачів. NetBird приймає будь-який provider, який підтримує OIDC. Зареєструйте confidential OIDC client у своєму provider, а потім додайте його в dashboard NetBird, указавши 4 значення: назву, client ID, client secret та issuer. NetBird надасть redirect URL, який потрібно вставити назад у налаштування provider. Готові інтеграції доступні для Google, Microsoft Entra ID, Okta, Zitadel, Keycloak, Authentik і Pocket ID, а для інших систем використовуйте generic OIDC. Якщо ви вже використовуєте Authentik як self-hosted single sign-on, цей варіант дає змогу зберегти один список облікових записів замість двох.
Локальний вхід залишається доступним після додавання provider, а кожен налаштований provider відображається на сторінці входу. Збережіть один локальний обліковий запис адміністратора із надійним паролем. Якщо конфігурація OIDC буде неправильною, у вас усе одно залишиться спосіб увійти.
NetBird чи Headscale: яку control plane запустити?
Обидва усувають одну й ту саму залежність — hosted control server, до якого ваші клієнти в іншому разі зверталися б. Але це різні за структурою проєкти.
Headscale повторно реалізує control server Tailscale, а ви продовжуєте використовувати офіційні клієнти Tailscale. Офіційної web console немає. Користувачами та pre-authentication keys керують за допомогою команди headscale, яка працює з config file. Існують community web interfaces, але вони не входять до складу проєкту. Це підходить тим, хто хоче зберігати свій стан у files, а зміни — у version control.
NetBird постачає весь продукт: власний клієнт, власний dashboard, вбудований identity provider і access policies, які редагуються в браузері. На вашому VPS буде більше компонентів. Водночас такий варіант значно простіше передати колезі, який не планує відкривати термінал.
Запускайте Headscale, якщо ви вже використовуєте клієнти Tailscale або хочете мінімально можливий control plane. Запускайте NetBird, якщо кільком людям потрібно керувати peers, а також потрібні console і SSO без самостійного складання такої системи. Перш ніж остаточно обрати один із варіантів, перевірте що насправді покриває безкоштовний план Tailscale, оскільки група з не більш як six users і необмеженою кількістю devices нічого не платить за hosted control plane і може взагалі не мати причин запускати власний. Після перевищення цього ліміту рахунок зростає відповідно до кількості людей, а не машин, тому розрахунок вартості Tailscale для вашої групи дасть вам суму для порівняння з витратами на VPS і часом, який ви витратите на цю інфраструктуру.
Який мінімальний VPS потрібен для роботи цього рішення?
Задокументований мінімум — 1 CPU і 2 GB пам’яті. За власними примітками NetBird, поточний мінімум тепер близький до 1 GB RAM, оскільки керування користувачами стало локальним. У старій схемі було потрібно від 2 GB до 4 GB, коли до стеку входив повноцінний deployment Zitadel. Оберіть VPS із 2 GB. Додатковий запас пам’яті дає змогу під час оновлення завантажувати нові images, поки старі ще зберігаються на диску.
На невеликому сервері безпечно не встановлювати три компоненти. Відмовтеся від сервісу NetBird Proxy. Він призначений для публікації внутрішніх сервісів за публічними іменами хостів і не пов’язаний із підключенням peer-вузлів. Відмовтеся від CrowdSec. Його варто додати пізніше на сервері, доступному з Інтернету, а не під час початкового розгортання. Залиште стандартне сховище SQLite у томі netbird_data. Переходьте на PostgreSQL лише після розподілу deployment між кількома серверами або за появи реального паралельного навантаження. У документації зазначено, що таку міграцію можна виконати пізніше.
Relay — єдиний компонент, від якого не можна відмовлятися. Якщо NAT у двох peer-вузлів призначає інший порт для кожного призначення, вони ніколи не встановлять прямий тунель. У такому разі relay — єдиний спосіб забезпечити їхню роботу. Його вимкнення майже не заощаджує пам’ять і порушує з’єднання так, що причину важко визначити.
Коли одного сервера вже недостатньо, найперше винесіть із нього relay. Окремий relay запускається з параметрами NB_LISTEN_ADDRESS, NB_EXPOSED_ADDRESS, NB_AUTH_SECRET і NB_ENABLE_STUN. Спільний секрет на relay і головному сервері має бути ідентичним. Інакше клієнти не зможуть пройти автентифікацію на relay.
Типові причини збоїв і їхні ознаки
На панелі керування відображається попередження про сертифікат. Traefik не отримав сертифікат. Виконайте docker compose logs traefik | grep -i acme. Є дві причини. Або dig +short netbird.example.com ще не вказує на цей VPS, або TCP 80 закритий десь між Let's Encrypt і контейнером, зазвичай у мережевому firewall провайдера, а не на ufw. Усуньте причину, перш ніж повторювати спробу в циклі, оскільки невдалі перевірки мають обмеження частоти, і ви втратите можливість повторних спроб на одну годину.
Клієнт повідомляє, що підключився, але панель керування порожня. Клієнт зареєструвався в hosted service NetBird, оскільки не було вказано --management-url. Виконайте netbird status --detail і прочитайте рядок Management:, у якому зазначено сервер, з яким клієнт фактично взаємодіє. Якщо ви бачите Management: Connected to https://api.netbird.io:443, клієнт підключився до cloud. Виконайте sudo netbird down, а потім ще раз sudo netbird up --management-url https://netbird.example.com.
Для кожного peer відображається Connection type: Relayed. Прямі тунелі не створюються, тому весь трафік проходить через ваш VPS і додає затримку через додатковий hop. Перевірте UDP 3478 у firewall VPS і firewall провайдера, оскільки STUN дає peer змогу визначити власні публічні адресу та порт. netbird status --detail також виводить Direct: false і типи кандидатів ICE (interactive connectivity establishment) для кожного peer. Це показує, наскільки далеко просунулася спроба підключення. У деяких мережах relayed є єдиним доступним результатом, і це не означає наявність проблеми.
Peer приєднується, але не може отримати доступу до жодного ресурсу. Наявність у mesh не означає, що два peer можуть обмінюватися трафіком. Це визначається access policies, а group без призначеної policy не має доступу ні до чого. Перевірте policy на панелі керування, перш ніж починати налагоджувати маршрути та firewall.
netbird status повідомляє про проблему з daemon. Сервіс не запущений. Використайте sudo netbird service status і sudo netbird service start. Журнали клієнта зберігаються в /var/log/netbird/client.log. Якщо ви не можете визначити причину, netbird debug bundle --anonymize --system-info збирає журнали, стан, маршрути, налаштування DNS і стан firewall в один архів.
Резервне копіювання та оновлення
Уся інсталяція залежить від двох компонентів: каталогу, що містить docker-compose.yml і config.yaml, та Docker volume, у якому зберігаються база даних і ключі шифрування. Створюйте їхні резервні копії разом. config.yaml містить ключ, який шифрує дані у сховищі, тому копія бази даних без нього не відновить дані, які можна прочитати.
docker volume ls
docker compose down
sudo tar czf netbird-config.tgz -C ~ netbird
docker run --rm -v netbird_netbird_data:/data -v "$PWD":/backup \
alpine tar czf /backup/netbird-data.tgz -C /data .
docker compose up -dCompose додає префікс із назви каталогу проєкту до імен volume, тому volume, задокументований як netbird_data, зазвичай має назву netbird_netbird_data. Спочатку виконайте docker volume ls і використайте ім’я, яке він виведе. Інакше команда docker run непомітно створить порожній volume і не заархівує жодних даних. Зберігайте архіви не на VPS. Якщо у вас уже є інструмент резервного копіювання, restic або BorgBackup виконає резервне копіювання за межами сервера.
Оновлення сервера складається з отримання нових образів і повторного створення контейнерів:
docker compose pull
docker compose up -d
docker compose psПерш ніж покладатися на це, виконайте docker compose config | grep image:. Будь-який тег зі значенням latest потрібно закріпити за конкретною версією. Причина та сама, що й під час закріплення версії інсталяційного скрипту: ви маєте знати, що саме запущено, і мати версію, до якої можна повернутися, якщо після оновлення виникнуть проблеми. Оновлюйте клієнти через той package manager, за допомогою якого їх було встановлено.
FAQ
Чи потрібен власний identity provider для self-hosted NetBird?
Ні. Поточні релізи містять вбудоване сховище користувачів, тому перший обліковий запис адміністратора можна створити у браузері за адресою https://netbird.example.com, а потім додати користувачів із dashboard. Зовнішній OIDC provider необов’язковий. Його можна додати пізніше, вказавши чотири значення: ім’я, client ID, client secret та issuer. Інструкції, у яких перед NetBird пропонують розгорнути Zitadel або Keycloak, описують конфігурацію, яка більше не є необхідною. Їх виконання додає ще один сервіс, який потрібно обслуговувати.
Чому всі мої peers мають статус Connection type: Relayed?
Прямі з’єднання не встановлюються, тому traffic проходить через relay на вашому VPS. Зазвичай причина полягає в тому, що UDP 3478 заблокований. Це STUN-порт, який peers використовують для визначення власної публічної адреси та порту. Відкрийте його у firewall VPS і в окремому network firewall вашого провайдера. Потім ще раз виконайте netbird status --detail і перевірте рядок Direct:. У мережі, де NAT призначає різний порт для кожного призначення, статус relayed є єдино можливим результатом. Це не означає, що конфігурацію налаштовано неправильно.
Мій client підключився, але dashboard не показує peers. Що сталося?
Client зареєструвався у hosted service NetBird, а не на вашому сервері. Так відбувається, коли параметр --management-url не вказано. Команда netbird status --detail виводить сервер, з яким встановлено з’єднання, у рядку Management:. Значення на кшталт https://api.netbird.io:443 підтверджує цю проблему. Виконайте sudo netbird down, потім sudo netbird up --management-url https://netbird.example.com, і peer з’явиться у вашому dashboard.
Чим self-hosted NetBird відрізняється від Headscale?
Обидва рішення замінюють hosted control server на сервер, яким ви керуєте самостійно. Headscale — це лише control plane: ним керують за допомогою команди headscale і конфігураційного файлу. Офіційної web console немає, а рішення використовує офіційні Tailscale clients. NetBird постачається з власним client, admin dashboard та інтеграцією з identity provider в одному stack. Headscale простіше запускати, а його стан зберігається у файлах. NetBird зручніше передавати користувачам, які не працюватимуть у terminal.
Який VPS потрібен для self-hosted NetBird server?
Задокументований мінімум становить 1 CPU і 2 GB memory. Саме конфігурацію з 2 GB варто замовляти. Практичний мінімум у recent releases знизився приблизно до 1 GB, оскільки identity provider тепер вбудований і не потребує окремого розгортання. Під час інсталяції відмовтеся від необов’язкових сервісів proxy та CrowdSec і залишайтеся на стандартному SQLite store, доки справді не знадобиться PostgreSQL.