Tự host NetBird VPN server trên VPS: Cách làm
Chạy NetBird mesh VPN trên một VPS với DNS, TLS, script quickstart cố định phiên bản và setup key cho peer tự đăng ký; xem khác biệt với Headscale.
NetBird VPN server tự host mang lại gì
Tự host NetBird VPN server đưa control plane lên một VPS do bạn sở hữu. Đây là phần lưu danh sách peer, quyết định máy nào được truy cập máy nào và hỗ trợ hai peer tìm thấy nhau phía sau NAT (network address translation). Các tunnel vẫn dùng WireGuard và được mã hóa trực tiếp giữa các máy của bạn. Điểm thay đổi là không còn công ty bên ngoài nào lưu inventory thiết bị hoặc quy trình đăng nhập của bạn.
NetBird nằm giữa hai mô hình mà có thể bạn đã biết. Đây là mesh overlay, nên các peer kết nối trực tiếp với nhau thay vì gửi toàn bộ lưu lượng qua một gateway. NetBird cũng có thể tự host từ đầu đến cuối, nên là một lựa chọn thay thế cho Headscale, control server tự host của Tailscale. Nếu bạn chỉ từng chạy tunnel qua một gateway duy nhất, hãy đọc sự khác nhau giữa WireGuard thông thường và mesh overlay trước. Mô hình này giúp bạn hiểu phần còn lại của trang.
Nếu mục tiêu thực tế của bạn là dùng một server làm điểm thoát cho toàn bộ lưu lượng, mesh sẽ có nhiều thành phần hơn mức cần thiết. WireGuard VPN thông thường trên một VPS duy nhất hoặc Tailscale exit node thực hiện việc đó với ít thành phần phải vận hành hơn.
Stack thực sự chạy những gì
Layout đã thay đổi gần đây, và phần lớn tài liệu cũ vẫn mô tả layout trước đây. Tính đến tháng 8 năm 2026, ở release v0.76.2, script quickstart mặc định tạo một file Compose với 3 service.
netbird-serverđảm nhiệm management API, signal service, relay có STUN listener tích hợp sẵn và identity provider tích hợp sẵn. Ở các release cũ, những thành phần này là các container riêng, còn identity provider là một bản cài đặt Zitadel riêng mà bạn phải build trước.dashboardlà admin web console.traefikthực hiện TLS termination và yêu cầu chứng chỉ từ Let's Encrypt trong lần khởi động đầu tiên.
Có thêm 2 service nhưng mặc định tắt, chỉ bật khi bạn trả lời yes tại prompt. Service NetBird Proxy publish các service nội bộ bằng public hostname. CrowdSec lọc network traffic có hành vi lạm dụng. Không service nào là bắt buộc để build một mesh hoạt động, và cả 2 đều tốn memory trên một máy nhỏ.
Nếu bạn đang chuyển từ wg-easy trong một Docker container duy nhất, đây là một bước nhảy về số lượng thành phần. Đổi lại, bạn có access policy và account riêng cho từng user, cùng các peer kết nối trực tiếp với nhau thay vì đi qua một gateway duy nhất.
Bạn cần chuẩn bị gì trước khi bắt đầu
Một tên miền public là bắt buộc. Dashboard, API và relay đều chạy HTTPS trên port 443. Traefik lấy certificate từ Let's Encrypt bằng HTTP challenge. Cách này cần một hostname phân giải đến VPS từ Internet public. Địa chỉ IP thuần sẽ không hoạt động trong luồng này.
Tạo một A record, netbird.example.com trỏ đến địa chỉ IPv4 public của VPS, rồi chờ DNS cập nhật trước khi chạy bất kỳ lệnh nào.
dig +short netbird.example.comLệnh đó phải in ra địa chỉ của server. Nếu chạy installer trước khi DNS propagate, yêu cầu certificate sẽ fail ngay lần khởi động đầu tiên. Các lần validation fail liên tiếp có thể chạm rate limit của Let's Encrypt, khiến bạn phải chờ một giờ mới thử lại được.
Có 3 port phải truy cập được từ Internet: TCP 80 cho certificate challenge và redirect sang HTTPS, TCP 443 cho dashboard, API, signal và relay traffic, và UDP 3478 cho STUN.
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 3478/udp
sudo ufw reload
sudo ufw statusBạn cũng phải mở các port này trên network firewall của provider. Đây thường là một lớp kiểm soát riêng trong panel VPS. Vì vậy, một máy có ufw status của chính nó trông đúng vẫn có thể từ chối kết nối.
STUN (session traversal utilities for NAT) giúp peer biết địa chỉ public và port mà NAT của chính nó đã cấp, để 2 peer có thể thử tạo tunnel trực tiếp. Nếu chặn UDP 3478, các peer vẫn kết nối được qua relay trên TCP 443 nên không có lỗi rõ ràng. Thay vào đó, mọi peer đều nhận Connection type: Relayed, và toàn bộ traffic đi qua VPS của bạn thay vì đi trực tiếp giữa các peer.
Về phần mềm, bạn cần Docker có Compose v2 plugin, cùng với jq và curl. Script kiểm tra tất cả các thành phần này và dừng nếu thiếu một thành phần. Nếu Docker mới được cài trên máy này, trước tiên hãy làm theo Cấu hình Docker Compose hoạt động trên VPS.
Các port nếu bỏ reverse proxy đi kèm
Chạy không có Traefik nghĩa là từng service được expose trực tiếp, và danh sách port sẽ dài hơn:
- TCP 80, redirect HTTP
- TCP 443, HTTPS
- TCP 33073, management gRPC
- TCP 10000, signal gRPC
- TCP 33080, relay qua WebSocket hoặc QUIC
- UDP 3478, STUN
Chỉ chọn cách này khi máy đã terminate TLS cho một dịch vụ khác. Nếu không, Traefik đi kèm sẽ cần ít rule hơn và ít gây lỗi hơn.
Cài đặt server NetBird bằng quickstart script
Lệnh một dòng được tài liệu hướng dẫn sẽ pipe bản release mới nhất trực tiếp vào shell:
curl -fsSL https://github.com/netbirdio/netbird/releases/latest/download/getting-started.sh | bashHãy pin phiên bản thay vì dùng lệnh đó. latest thay đổi, nên cùng một lệnh chạy cách nhau 2 tuần sẽ tạo ra 2 bản cài đặt khác nhau, và không có gì trên disk ghi lại bản nào đã tạo config của bạn. Hãy tải một bản release có tag, đọc script, rồi mới chạy.
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.shScript sẽ hỏi domain trước:
Enter the domain you want to use for NetBird (e.g. netbird.my-domain.com):Sau đó script hỏi cách xử lý 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):Chọn [0]. Các tùy chọn từ 2 đến 5 sẽ ghi một đoạn config và để bạn tự cấu hình phần kết nối. Đây là lựa chọn đúng trên máy đã chạy proxy, nhưng không phù hợp với máy mới cài. Tùy chọn 0 sẽ hỏi địa chỉ email Let's Encrypt để gửi thông báo khi chứng chỉ sắp hết hạn.
Khi cài lần đầu, hãy chọn không cài service NetBird Proxy. Service này cần thêm 2 bản ghi DNS, proxy.netbird.example.com và wildcard *.proxy.netbird.example.com, nhưng không mang lại lợi ích cho một mesh thông thường. CrowdSec cũng chọn không cài. Bạn có thể thêm cả 2 thành phần này sau.
Script ghi các file vào thư mục hiện tại: docker-compose.yml, config.yaml với mode 600, dashboard.env và traefik-dynamic.yaml nếu bạn chọn Traefik đi kèm. Hãy xem thư mục này là state cần giữ lại, vì config.yaml chứa key dùng để mã hóa dữ liệu trong store. Mất key này không thể khắc phục chỉ bằng cách cài lại.
docker compose ps
docker compose logs -f netbird-serverMọi service phải đọc được running, và log của server phải dừng ổn định thay vì restart liên tục. Hãy theo dõi chứng chỉ riêng:
docker compose logs traefik | grep -i acmeACME (automatic certificate management environment) là protocol Traefik dùng để lấy chứng chỉ. Lỗi ở đây hầu như luôn do DNS hoặc cổng 80 bị đóng.
Tạo tài khoản admin đầu tiên
Mở https://netbird.example.com. Với một bản cài mới, trang này hiển thị trang thiết lập thay vì biểu mẫu đăng nhập. Nhập địa chỉ email, tên và mật khẩu, rồi nhấp vào Create Account. Tài khoản này trở thành admin đầu tiên và trang sẽ chuyển hướng đến biểu mẫu đăng nhập.
Tài khoản này được lưu trong user store riêng của NetBird, do identity provider được tích hợp trong container netbird-server cung cấp. Không cần dùng thành phần bên ngoài. Đây là thay đổi lớn nhất so với NetBird self-hosted của một năm trước. Khi đó, một bản cài hoạt động được yêu cầu phải triển khai Zitadel hoặc Keycloak trước, rồi sao chép 4 giá trị OIDC (OpenID Connect) vào setup.env trước khi bất kỳ thành phần nào có thể khởi động.
Nếu trình duyệt hiển thị cảnh báo certificate thay vì trang thiết lập, certificate chưa được cấp. Hãy xử lý lỗi này trước khi tiếp tục. Dashboard trao đổi với API qua cùng hostname và sẽ hoạt động không ổn định theo cách khó chẩn đoán nếu certificate bị lỗi.
Kết nối peer đầu tiên
Cài đặt client trên bất kỳ máy Linux nào, bao gồm cả VPS nếu bạn muốn đưa máy đó vào mesh:
curl -fsSL https://pkgs.netbird.io/install.sh | shTrên Debian và Ubuntu, script này cấu hình repository package của NetBird rồi cài client qua apt. Vì vậy, package manager vẫn quản lý package này. Nếu bạn không muốn pipe script trực tiếp vào shell, hãy lưu script trước bằng curl -fsSL -o install.sh https://pkgs.netbird.io/install.sh và đọc nội dung trước khi chạy sh install.sh. Dù dùng cách nào, hãy xác nhận những gì đã được cài:
apt-cache policy netbirdnetbird là CLI client và daemon. netbird-ui là ứng dụng desktop tray, nên server headless không cần ứng dụng này.
Bây giờ trỏ client đến server của bạn:
sudo netbird up --management-url https://netbird.example.comNếu bỏ --management-url, client sẽ đăng ký với dịch vụ hosted của NetBird vì đó là giá trị mặc định được build sẵn. Lệnh vẫn chạy thành công, máy vẫn nhận được một địa chỉ, nhưng dashboard self-hosted của bạn vẫn trống. Hầu như ai cũng mắc lỗi này ít nhất một lần.
Lệnh sẽ in ra một URL để mở trong trình duyệt và hoàn tất đăng nhập. Sau đó:
netbird status
ip addr show wt0Đọc 4 dòng từ netbird status: Management: Connected, Signal: Connected, một dòng Relays: liệt kê mọi relay hiện có và một dòng NetBird IP: nằm trong dải overlay. wt0 là WireGuard interface do NetBird tạo, và interface này phải có cùng địa chỉ đó.
Đăng ký một máy thứ hai ở chế độ không cần tương tác bằng setup key
Đăng nhập bằng trình duyệt không phù hợp với máy không có trình duyệt và không có người thao tác trực tiếp. Setup key là token pre-authentication dùng để đăng ký máy mà không cần bước tương tác. Tạo key này trong dashboard, tại mục Setup Keys.
Có 2 loại. Key dùng một lần sẽ xác thực đúng 1 máy rồi bị tiêu thụ. Key có thể tái sử dụng sẽ đăng ký được nhiều máy, đồng thời có thể đặt giới hạn số lượng. Cả 2 loại đều có thời hạn và đều có thể tự động gán peer mới vào một group. Khi đó, các access rule của group sẽ áp dụng ngay khi máy xuất hiện.
sudo netbird up --setup-key <SETUP-KEY> \
--management-url https://netbird.example.com \
--hostname build-runner-01--hostname đặt tên hiển thị trong dashboard. Nếu không đặt, peer sẽ dùng tên mà máy tự khai báo. Một danh sách máy mà tất cả đều có tên ubuntu sẽ không giúp ích gì.
Với container và build agent tồn tại trong thời gian ngắn, hãy đánh dấu key là ephemeral khi tạo. Các peer được đăng ký bằng ephemeral key sẽ tự động bị xóa sau khi offline quá 10 phút. Nhờ đó, các entry không còn hoạt động không bị giữ lại trong danh sách peer.
Có một giới hạn cần hiểu trước khi dựa vào setup key: khi key hết hạn hoặc bị xóa, key chỉ ngừng cho phép đăng ký mới. Nó không ngắt kết nối các máy đã đăng ký bằng key đó. Muốn thu hồi quyền truy cập của một máy, bạn phải xóa peer tương ứng.
Bạn còn cần một identity provider riêng không?
Với một hệ thống nhỏ thì không. User store tích hợp sẵn xử lý các tài khoản được tạo từ dashboard, và như vậy là đủ cho một nhóm nhỏ người dùng.
Bạn nên dùng identity provider bên ngoài khi đã có sẵn một provider và không muốn duy trì thêm một danh sách người dùng. NetBird chấp nhận mọi provider hỗ trợ OIDC. Hãy đăng ký một OIDC client confidential trong provider của bạn, sau đó thêm client đó vào dashboard NetBird bằng 4 giá trị: tên, client ID, client secret và issuer. NetBird cung cấp redirect URL để bạn dán lại vào provider. NetBird có integration riêng cho Google, Microsoft Entra ID, Okta, Zitadel, Keycloak, Authentik và Pocket ID. Các provider khác dùng cấu hình OIDC generic. Nếu bạn đã chạy Authentik làm single sign-on tự host, đây là cách để duy trì một danh sách tài khoản thay vì hai danh sách.
Local login vẫn hoạt động sau khi bạn thêm provider, và mọi provider đã cấu hình đều xuất hiện trên trang login. Hãy giữ một tài khoản local admin với mật khẩu mạnh. Nếu cấu hình OIDC bị lỗi, bạn vẫn còn cách đăng nhập vào hệ thống.
NetBird hay Headscale: nên chạy control plane nào?
Cả hai đều loại bỏ cùng một dependency: control server được host sẵn mà các client thường phải kết nối về. Tuy nhiên, hai dự án có mô hình rất khác nhau.
Headscale triển khai lại control server của Tailscale, còn bạn tiếp tục dùng các client Tailscale chính thức. Dự án không có web console chính thức. Bạn quản lý user và pre-authentication key bằng lệnh headscale dựa trên một file cấu hình. Có các web interface do cộng đồng phát triển, nhưng chúng không thuộc dự án. Mô hình này phù hợp nếu bạn muốn lưu state trong file và quản lý thay đổi bằng version control.
NetBird cung cấp toàn bộ sản phẩm: client riêng, dashboard riêng, identity provider tích hợp sẵn và access policy có thể chỉnh sửa trong trình duyệt. VPS của bạn sẽ có nhiều thành phần hơn, nhưng việc bàn giao cho một đồng nghiệp không bao giờ mở terminal sẽ dễ hơn nhiều.
Hãy chạy Headscale nếu bạn đã dùng Tailscale client hoặc muốn control plane nhỏ gọn nhất có thể. Hãy chạy NetBird nếu nhiều người cần quản lý peer và bạn muốn có console cùng SSO mà không phải tự lắp ghép các thành phần đó.
Chạy được trên VPS nhỏ đến mức nào?
Mức tối thiểu được tài liệu ghi nhận là 1 CPU và 2 GB bộ nhớ. Ghi chú của NetBird hiện đặt mức thấp nhất gần 1 GB RAM, vì việc quản lý user đã chạy local, thay vì 2 GB đến 4 GB như layout cũ cần khi stack có đầy đủ một deployment Zitadel. Hãy chọn VPS 2 GB. Phần tài nguyên dư thêm cho phép quá trình upgrade tải image mới trong khi image cũ vẫn còn trên disk.
Có 3 thành phần có thể bỏ qua an toàn trên máy nhỏ. Không cài NetBird Proxy. Service này dùng để publish service nội bộ trên hostname public, không liên quan đến việc các peer kết nối với nhau. Không cài CrowdSec. Bạn có thể thêm nó sau này cho máy bị expose, thay vì cài ngay từ đầu. Giữ store SQLite mặc định trong volume netbird_data. Chỉ chuyển sang PostgreSQL khi bạn tách deployment giữa nhiều máy hoặc gặp vấn đề concurrency thực tế. Tài liệu ghi rõ việc migration này có thể thực hiện sau.
Relay là component không thể bỏ. Hai peer có NAT gán một port khác cho từng destination sẽ không bao giờ thiết lập được tunnel trực tiếp. Khi đó relay là đường truyền duy nhất giúp chúng hoạt động. Tắt relay chỉ tiết kiệm rất ít memory nhưng lại làm hỏng kết nối theo cách khó truy vết.
Khi một máy không còn đủ tài nguyên, relay là component đầu tiên nên chuyển sang máy khác. Một relay độc lập chạy với NB_LISTEN_ADDRESS, NB_EXPOSED_ADDRESS, NB_AUTH_SECRET và NB_ENABLE_STUN. Shared secret phải giống hệt trên relay và server chính. Nếu không, client sẽ không authenticate được với relay.
Các dạng lỗi và dấu hiệu bạn sẽ thấy
Dashboard hiển thị cảnh báo chứng chỉ. Traefik chưa lấy được chứng chỉ. Chạy docker compose logs traefik | grep -i acme. Có hai nguyên nhân. Hoặc dig +short netbird.example.com chưa trỏ đến VPS này, hoặc TCP 80 bị chặn ở đâu đó giữa Let's Encrypt và container, thường là trên firewall mạng của nhà cung cấp chứ không phải trên ufw. Hãy khắc phục nguyên nhân trước khi thử lại liên tục, vì các lần xác thực thất bại bị giới hạn tần suất và bạn sẽ bị khóa quyền thử lại trong một giờ.
Client báo đã kết nối nhưng dashboard trống. Client đã đăng ký với dịch vụ hosted của NetBird vì thiếu --management-url. Chạy netbird status --detail và đọc dòng Management:; dòng này cho biết client thực sự đang kết nối đến server nào. Nếu thấy Management: Connected to https://api.netbird.io:443, nghĩa là client đã kết nối đến cloud. Chạy sudo netbird down, rồi chạy lại sudo netbird up --management-url https://netbird.example.com.
Mọi peer đều hiển thị Connection type: Relayed. Không có tunnel trực tiếp nào được thiết lập, nên toàn bộ traffic đi qua VPS và tăng thêm một hop latency. Kiểm tra UDP 3478 trên firewall của VPS và firewall của nhà cung cấp, vì STUN cho phép peer xác định địa chỉ và port public của chính nó. netbird status --detail cũng in ra Direct: false và các loại candidate ICE (interactive connectivity establishment) của từng peer, cho biết quá trình kết nối đã tiến xa đến đâu. Trên một số mạng, relayed là kết quả duy nhất có thể có và không có gì sai.
Một peer tham gia nhưng không truy cập được bất kỳ đâu. Có mặt trong mesh không có nghĩa là hai peer được phép nói chuyện với nhau. Access policy quyết định điều đó, và một group không được gắn policy sẽ không truy cập được gì. Kiểm tra policy trong dashboard trước khi bắt đầu debug route và firewall.
netbird status báo lỗi daemon. Service không chạy. Dùng sudo netbird service status và sudo netbird service start. Log của client nằm ở /var/log/netbird/client.log. Với mọi vấn đề chưa xác định được nguyên nhân, netbird debug bundle --anonymize --system-info sẽ thu thập log, trạng thái, route, DNS setting và trạng thái firewall vào một archive duy nhất.
Sao lưu và nâng cấp
Hai thành phần này chứa toàn bộ dữ liệu cần thiết của hệ thống: thư mục chứa docker-compose.yml và config.yaml, cùng Docker volume chứa database và các encryption key. Hãy sao lưu chúng cùng nhau. config.yaml chứa key dùng để mã hóa dữ liệu trong store, nên bản sao database không có key này sẽ không khôi phục được dữ liệu có thể đọc.
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 thêm tiền tố là thư mục project vào tên volume, nên volume được ghi là netbird_data thường sẽ xuất hiện với tên netbird_netbird_data. Chạy docker volume ls trước và dùng tên mà lệnh in ra. Nếu không, docker run sẽ âm thầm tạo một volume rỗng và không archive được gì. Lưu các archive bên ngoài VPS. Nếu bạn đã có công cụ sao lưu, restic hoặc BorgBackup có thể xử lý phần sao lưu offsite.
Nâng cấp server gồm pull image và tạo lại container:
docker compose pull
docker compose up -d
docker compose psTrước khi dựa vào quy trình đó, hãy chạy docker compose config | grep image:. Mọi tag có giá trị latest nên được pin vào một version, vì cùng lý do bạn đã pin install script: bạn cần biết version nào đang chạy và cần có một version để quay lại khi quá trình nâng cấp gặp lỗi. Client được nâng cấp bằng package manager đã dùng để cài đặt chúng.
FAQ
Tôi có cần identity provider riêng để tự host NetBird không?
Không. Các bản phát hành hiện tại đã có user store tích hợp sẵn, nên bạn tạo tài khoản admin đầu tiên trong trình duyệt tại https://netbird.example.com rồi thêm user từ dashboard. External OIDC provider là tùy chọn và có thể thêm sau bằng 4 giá trị: name, client ID, client secret và issuer. Các hướng dẫn yêu cầu bạn triển khai Zitadel hoặc Keycloak trước NetBird đang mô tả một cấu hình không còn bắt buộc, và làm theo chúng khiến bạn phải vận hành thêm một service.
Tại sao tất cả peer của tôi đều hiển thị Connection type: Relayed?
Kết nối trực tiếp không được thiết lập, nên traffic đi qua relay trên VPS của bạn. Nguyên nhân thường gặp là UDP 3478 bị chặn. Đây là STUN port mà peer dùng để phát hiện public address và port của chính nó. Hãy mở port này trên firewall của VPS và firewall mạng riêng của nhà cung cấp, sau đó chạy lại netbird status --detail và đọc dòng Direct:. Trên mạng có NAT cấp một port khác cho từng đích đến, relayed là kết quả duy nhất có thể xảy ra và không có cấu hình nào bị sai.
Client của tôi đã kết nối nhưng dashboard không hiển thị peer nào. Chuyện gì đã xảy ra?
Client đã đăng ký với hosted service của NetBird thay vì server của bạn. Điều này xảy ra khi --management-url bị bỏ qua. netbird status --detail in ra server mà client đang kết nối trên dòng Management:, nên giá trị như https://api.netbird.io:443 xác nhận điều đó. Chạy sudo netbird down, sau đó chạy sudo netbird up --management-url https://netbird.example.com, rồi peer sẽ xuất hiện trong dashboard.
NetBird tự host khác Headscale như thế nào?
Cả hai đều thay thế control server hosted bằng một server do bạn vận hành. Headscale chỉ là control plane: bạn quản lý nó bằng lệnh headscale và một file cấu hình, không có web console chính thức, đồng thời nó điều khiển các Tailscale client chính thức. NetBird cung cấp client riêng, admin dashboard và tích hợp identity provider trong cùng một stack. Headscale nhỏ gọn hơn khi vận hành và lưu state trong các file. NetBird dễ bàn giao cho những người không sử dụng terminal hơn.
Server NetBird tự host cần VPS cấu hình thế nào?
Mức tối thiểu được ghi trong tài liệu là 1 CPU và 2 GB memory, nên chọn gói có 2 GB. Mức thực tế đã giảm xuống khoảng 1 GB trong các bản phát hành gần đây vì identity provider hiện được tích hợp sẵn thay vì phải triển khai riêng. Khi cài đặt, hãy bỏ qua proxy và CrowdSec service tùy chọn, đồng thời dùng SQLite store mặc định cho đến khi bạn thực sự cần PostgreSQL.