Mở thẳng cổng 5432 của PostgreSQL hoặc 3306 của MySQL ra Internet là một hành động tiềm ẩn nhiều rủi ro, tạo điều kiện cho các hệ thống rà soát tự động dò tìm lỗ hổng. Trong khi đó, việc quản lý danh sách whitelist IP tĩnh lại trở thành gánh nặng vận hành khi developer làm việc remote, di chuyển liên tục giữa quán cafe và mạng gia đình khiến IP thay đổi không ngừng. Nhiều kỹ sư hệ thống tìm đến giải pháp VPN truyền thống như WireGuard thuần, nhưng việc cấp phát key thủ công, sửa file config liên tục mỗi khi có nhân sự mới lại tiêu tốn rất nhiều thời gian.
Để giải quyết bài toán này, việc xây dựng Mesh Network trên VPS bằng Headscale đang được ứng dụng rộng rãi trong các dự án công nghệ.
Nỗi đau kinh điển khi mở cổng Database cho team remote
Khi vận hành hạ tầng cho một đội ngũ phát triển phân tán, các Sysadmin và DevOps thường xuyên phải đối mặt với những vấn đề nhức nhối về hiệu năng và bảo mật mạng:
- Quản lý IP public và whitelist IP động: Hệ thống mạng cá nhân của developer thay đổi IP liên tục mỗi lần khởi động lại router. Nếu hệ thống API bị rate-limit hoặc tường lửa block IP vì nhận diện hành vi thay đổi mạng liên tục, luồng công việc sẽ bị gián đoạn. Việc admin phải đăng nhập server để mở port public rồi add IP mới vào whitelist là một tác vụ thủ công, kém hiệu quả.
- Điểm nghẽn Hub-and-Spoke của VPN truyền thống: Khi sử dụng các mô hình VPN tập trung, mọi request truy vấn database từ máy client đều phải vòng qua một máy chủ VPN trung gian. Điều này tạo ra nút thắt cổ chai băng thông, đẩy độ trễ (latency) lên cao khi team cần kéo các tập dữ liệu lớn về môi trường local để test.
- Quản lý key và routing thủ công: WireGuard thuần yêu cầu người quản trị phải sinh Public/Private key, gán IP tĩnh và cấu hình
AllowedIPscho từng thiết bị. Khi team scale lên hàng chục người, file config trở thành một ma trận, rất khó bảo trì và dễ xảy ra sai sót cấu hình chéo.

Sự dịch chuyển kiến trúc: Từ WireGuard thuần sang Headscale
Để khắc phục các điểm yếu của VPN truyền thống, kiến trúc mạng hiện đại phân tách rõ ràng hệ thống thành hai phần: Control Plane (Mặt phẳng điều khiển) và Data Plane (Mặt phẳng dữ liệu).
- WireGuard thuần (Data Plane): Xử lý việc mã hóa và truyền tải gói tin ở tốc độ cao. Tuy nhiên, giao thức này thiếu đi một bộ não để điều phối các node trong mạng. Nó đòi hỏi cấu hình peer-to-peer phải được thiết lập thủ công trên từng máy.
- Headscale (Control Plane): Đóng vai trò là máy chủ điều phối trung tâm. Headscale không tham gia vào quá trình truyền tải traffic thực tế. Nhiệm vụ của nó là xác thực thiết bị, cấp phát IP nội bộ, phân phối bản đồ mạng (network map) và trao đổi Public Key một cách tự động. Sau khi nhận bản đồ mạng từ Headscale, các client sẽ tự thiết lập đường hầm WireGuard trực tiếp với nhau.
Việc tự host Headscale mang lại lợi thế về quyền kiểm soát dữ liệu (Data Sovereignty). Tổ chức không phải gửi siêu dữ liệu (metadata), thông tin thiết bị hay file log lên hạ tầng đám mây của các nhà cung cấp bên thứ ba. Hơn nữa, việc tự vận hành hệ thống này giúp tối ưu chi phí cho các dự án có tốc độ scale nhân sự nhanh, vì bạn không bị tính phí theo số lượng người dùng hay thiết bị.
Chuẩn bị hạ tầng & sơ đồ kiến trúc để xây dựng Mesh Network trên VPS
Việc xây dựng Mesh Network trên VPS không tiêu tốn nhiều tài nguyên tính toán, bởi máy chủ chỉ làm nhiệm vụ điều hướng thông tin cấu hình. Lưu lượng truy vấn Database nặng nề sẽ đi trực tiếp (Peer-to-Peer) giữa máy Dev và DB Server.
Yêu cầu hạ tầng cơ bản:
- 1 Cloud VPS chạy Linux (khuyên dùng Ubuntu 22.04 hoặc 24.04 LTS).
- Cấu hình: 1 vCPU, 2GB RAM, 20GB SSD. (Mức 2GB RAM đảm bảo hệ thống chạy mượt mà cả Headscale core, giao diện Web UI và hệ thống Reverse Proxy Caddy).
- 1 Tên miền (Domain) đã trỏ bản ghi A về địa chỉ IP Public của VPS (ví dụ:
vpn.congtycua.com).
Các port cần mở trên Firewall của VPS (Security Group/UFW):
80/TCPvà443/TCP: Phục vụ Caddy xác thực Let’s Encrypt và xử lý traffic HTTPS cho giao diện quản trị.41641/UDP: Port kết nối trực tiếp của WireGuard, hỗ trợ thiết lập đường truyền peer-to-peer.3478/UDP: Phục vụ STUN server, giúp các thiết bị dò tìm IP public của nhau để xuyên NAT (NAT traversal) hiệu quả, đặc biệt khi dev ngồi sau các router mạng gia đình.

Thực chiến 5 bước cấu hình Headscale, Headplane và Caddy
Để hệ thống hoạt động ổn định và có tính trực quan cao, hạ tầng sẽ được đóng gói qua Docker Compose, kết hợp Caddy (tự động HTTPS) và Headplane (Giao diện Web UI quản trị hiện đại).
Bước 1: Khai báo Docker Compose và sinh API Key an toàn
Nhiều hệ thống gặp lỗi khi khởi chạy toàn bộ container cùng lúc vì Headplane cần một API Key từ Headscale để giao tiếp, nhưng API Key lại chưa được tạo. Để xử lý bài toán này gọn gàng mà không sinh ra container dư thừa, chúng ta sẽ khai báo tệp docker-compose.yml trước, sau đó mượn volume để sinh key.
Tạo cấu trúc thư mục trên VPS:
mkdir -p /opt/headscale/{config,data}
Di chuyển vào thư mục vừa tạo:
cd /opt/headscale
Tải tệp cấu hình mẫu từ repository chính thức:
wget -O ./config/config.yaml https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml
Chỉnh sửa tệp config.yaml. Với các phiên bản Headscale v0.29 trở lên, cú pháp IP đã thay đổi. Bạn cần sử dụng block prefixes thay cho định dạng cũ để tránh lỗi bỏ qua cấu hình:
server_url: https://vpn.congtycua.com
listen_addr: 0.0.0.0:8080
# Cấu hình IP chuẩn cho dải mạng ảo
prefixes:
v4: 100.64.0.0/10
allocation: sequential
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
# Bật MagicDNS để phân giải tên miền nội bộ
dns_config:
magic_dns: true
base_domain: tailnet.local
nameservers:
- 1.1.1.1
- 8.8.8.8
# Khai báo file Policy (Sẽ tạo ở phần Zero Trust sau)
policy:
mode: file
path: /etc/headscale/policy.hujson
Tạo tệp docker-compose.yml. Việc ghim cứng phiên bản v0.29.3 cho Headscale và 0.7.0 cho Headplane được khuyên dùng để bảo vệ hệ thống khỏi các lỗi đứt gãy (breaking changes):
version: '3.8'
services:
headscale:
image: headscale/headscale:0.29.3
container_name: headscale
restart: unless-stopped
volumes:
- ./config:/etc/headscale
- ./data:/var/lib/headscale
command: serve
networks:
- mesh-net
headplane:
image: ghcr.io/tale/headplane:0.7.0
container_name: headplane
restart: unless-stopped
environment:
- HEADSCALE_URL=http://headscale:8080
# Sẽ điền mã API Key vào đây sau khi sinh
- HEADSCALE_API_KEY=your_api_key_here
# Tạo một chuỗi ngẫu nhiên làm secret cookie
- COOKIE_SECRET=random_string_xyz_123
networks:
- mesh-net
caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
networks:
- mesh-net
networks:
mesh-net:
volumes:
caddy_data:
caddy_config:
Mượn cấu hình volume từ tệp Compose vừa tạo để sinh API Key (lệnh --rm giúp container tự động xóa sau khi chạy xong nhiệm vụ, giữ hệ thống sạch sẽ):
docker-compose run --rm headscale headscale apikeys create --expiration 9999h
Sao chép chuỗi mã API Key vừa sinh ra, mở lại file docker-compose.yml và dán vào biến HEADSCALE_API_KEY.
Bước 2: Tích hợp định tuyến Caddy và khởi chạy hệ thống
Tạo tệp Caddyfile để xử lý routing nội bộ và cấp SSL. Ở đây, ta áp dụng chiến lược định tuyến ngược: ưu tiên phân luồng đường dẫn quản trị cho Headplane và đẩy toàn bộ traffic còn lại về Headscale để không đánh rơi các endpoint ngầm của Tailscale client (như /machine, /derp):
vpn.congtycua.com {
# Truy cập Web UI Headplane qua thư mục /admin
reverse_proxy /admin* headplane:3000
# Đẩy toàn bộ API và traffic lưới mạng còn lại về Headscale
reverse_proxy * headscale:8080
}
Khởi chạy hệ thống hoàn chỉnh:
docker-compose up -d
Lúc này, bạn có thể truy cập https://vpn.congtycua.com/admin trên trình duyệt để sử dụng giao diện Headplane, giúp quản lý user, node và policy trực quan.
Bước 3: Khởi tạo User và cấp Auth Key chuyên biệt
Từ phiên bản v0.29, Headscale phân định rất rõ giữa thiết bị của người dùng cá nhân (User-owned) và thiết bị máy chủ hạ tầng (Tagged devices). Mọi thao tác qua CLI cũng yêu cầu ID số học thay vì tên chuỗi.
Khởi tạo không gian làm việc cho team:
docker exec -it headscale headscale users create dev-team
Tra cứu ID của user vừa tạo:
docker exec -it headscale headscale users list
(Giả sử kết quả trả về ID của dev-team là 1).
Tạo Key cho Developer (User-owned):
Tạo một Pre-auth key có khả năng dùng nhiều lần (reusable) với thời hạn 30 ngày bằng tham số -u kết hợp ID:
docker exec -it headscale headscale preauthkeys create -u 1 --reusable --expiration 720h
Hệ thống cung cấp chuỗi hskey-auth-xxxx.... Dùng mã này để dev kết nối máy tính cá nhân.
Tạo Key cho Máy chủ (Infrastructure/Tagged devices):
Đối với Database Server, bạn không nên dùng key của user thông thường. Hãy tạo một Pre-auth Key được nhúng sẵn nhãn mạng. Thao tác này sẽ tự động gán thiết bị vào nhóm hệ thống tagged-devices và cấp thẻ tag:database mà không cần cấu hình rườm rà:
docker exec -it headscale headscale preauthkeys create --tags tag:database --reusable --expiration 720h
Lưu lại mã hskey-auth-yyyy... này dành riêng cho hạ tầng server.
Bước 4: Cài đặt Tailscale Client và kích hoạt Tailscale SSH trên Database
Trên Database Server (chạy Ubuntu/Debian), tải và thực thi script cài đặt Tailscale:
curl -fsSL https://tailscale.com/install.sh | sh
Kích hoạt dịch vụ khởi chạy cùng hệ thống:
sudo systemctl enable --now tailscaled
Thay vì quản lý SSH Key (authorized_keys) hoặc mở port 22 đối mặt với nguy cơ bị brute-force, bạn có thể áp dụng công nghệ Tailscale SSH. Tính năng này cho phép Sysadmin kết nối vào server dựa trên danh tính mạng Mesh được cấp quyền trong ACL.
Kết nối server vào mạng lưới bằng Key có sẵn Tag và kích hoạt cờ SSH:
sudo tailscale up --login-server https://vpn.congtycua.com --authkey hskey-auth-yyyy-MA-CUA-DB --ssh
Nhờ key đã nhúng sẵn tag từ Bước 3, máy chủ sẽ tự động nhận diện danh tính tag:database.
Bước 5: Join máy Dev vào mạng lưới & ứng dụng MagicDNS
Trên các thiết bị cá nhân (Windows, macOS, Linux), developer cài đặt ứng dụng Tailscale chính thức và kết nối bằng lệnh:
tailscale up --login-server https://vpn.congtycua.com --authkey hskey-auth-xxxx-MA-CUA-DEV --accept-dns=true
Tham số --accept-dns=true cho phép thiết bị nhận cấu hình MagicDNS. Thay vì nhớ địa chỉ IP nội bộ 100.64.0.10, developer có thể ping hoặc truy vấn database thông qua tên định danh thân thiện:
ping db-prod.tailnet.local
Thiết lập Zero Trust ACL và Defense-in-Depth
Triết lý bảo mật Zero Trust (Không tin tưởng mặc định) yêu cầu mọi kết nối phải được xác thực và chỉ mở đúng port dịch vụ được cấu hình. Nếu bỏ qua bước thiết lập Policy, mạng Mesh sẽ hoạt động ở chế độ Allow-all, cho phép các node truy cập chéo tự do, gây rủi ro lớn.
Khai báo Policy, Grants và tích hợp Automate Tests
Trong hệ thống Headscale/Tailscale, mạng lưới chỉ tự động chuyển sang trạng thái chặn mặc định (Deny-by-default) khi hệ thống đọc thấy sự tồn tại của mảng acls. Ngay cả khi bạn sử dụng khối grants (cú pháp phân quyền hiện đại), việc khai báo mảng acls: [] rỗng là thao tác bắt buộc để khóa các luồng traffic tự do.
Đặc biệt, ở phiên bản Headscale v0.29+, bạn có thể sử dụng khối tests để tự động xác thực tính đúng đắn của các luật ACLs/Grants, đảm bảo hệ thống không bị cấu hình sai lệch.
Tạo tệp policy.hujson tại thư mục /opt/headscale/config/:
{
// Bắt buộc phải có mảng này để kích hoạt chặn mọi luồng traffic mặc định
"acls": [],
"groups": {
"group:devs": ["dev-team"]
},
"tagOwners": {
"tag:database": ["group:devs"]
},
"grants": [
// Cấp quyền cho nhóm Dev truy cập node tag:database chỉ qua cổng TCP 5432
{
"src": ["group:devs"],
"dst": ["tag:database"],
"ip": ["tcp:5432"]
}
],
"ssh": [
// Cho phép nhóm Dev sử dụng tính năng Tailscale SSH vào DB Server.
// Đặt action là "accept" để luồng SSH hoạt động tự động dựa trên ACL, tránh bị treo phiên xác thực.
{
"action": "accept",
"src": ["group:devs"],
"dst": ["tag:database"],
"users": ["ubuntu", "root"]
}
],
"tests": [
// Tự động kiểm thử xem Dev có được vào cổng 5432 và bị chặn ở cổng 80 hay không
{
"src": "user1@group:devs",
"accept": ["tag:database:5432"],
"deny": ["tag:database:80"]
}
]
}
Kiểm tra cú pháp và áp dụng thay đổi vào hệ thống (hoặc bạn có thể dán cấu hình này trực tiếp trên giao diện Headplane):
docker exec -it headscale kill -HUP 1
Đóng băng Firewall vật lý và liên kết IP nội bộ
Mạng Mesh giải quyết việc phân quyền ở lớp mạng ảo (L3/L4 ảo). Để đạt phương án bảo mật nhiều lớp (Defense-in-Depth), hạ tầng vật lý của Database Server cần được bảo vệ nghiêm ngặt bằng tường lửa UFW cục bộ.
Sử dụng UFW để chặn mọi traffic từ Internet, chỉ cho phép dữ liệu lưu thông qua card mạng ảo tailscale0:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow in on tailscale0
Port 22 vật lý có thể chặn vì đã dùng Tailscale SSH:
sudo ufw delete allow 22/tcp
Kích hoạt tường lửa UFW:
sudo ufw enable
Tiếp đó, điều chỉnh cấu hình hệ quản trị cơ sở dữ liệu. Mở file postgresql.conf và giới hạn IP lắng nghe (listen) để dịch vụ không nhận diện IP Public:
listen_addresses = 'localhost, 100.64.0.10'
Xác thực Database ở lớp ứng dụng
Headscale ACL chỉ kiểm soát luồng gói tin mạng. Nó quyết định thiết bị nào được phép tạo kết nối TCP tới cổng 5432, nhưng không can thiệp vào quyền hạn đọc/ghi cấu trúc bảng dữ liệu bên trong.
Do đó, chốt chặn bảo mật ở lớp ứng dụng vẫn là yếu tố không thể bỏ qua để tối ưu database VPS Linux một cách an toàn. Quản trị viên cần tinh chỉnh tệp pg_hba.conf để yêu cầu xác thực bằng mật khẩu mạnh (sử dụng thuật toán scram-sha-256), đồng thời thiết lập Role phù hợp cho từng developer. Việc kết hợp chặt chẽ giữa bảo mật lớp mạng (Mesh VPN kiểm soát truy cập network) và lớp ứng dụng (Database Auth kiểm soát truy cập data) sẽ thiết lập một kiến trúc hạ tầng kiên cố.

Câu hỏi thường gặp (FAQ)
1. Headscale có tính phí không?
Không. Headscale là mã nguồn mở hoàn toàn, không giới hạn số lượng user hay thiết bị. Bạn chỉ phải chi trả tiền thuê VPS hạ tầng.
2. Cần VPS cấu hình mạnh để chạy Headscale không?
Không. Headscale chỉ xử lý thông tin điều phối (Control Plane), không gánh traffic dữ liệu thực tế. Một VPS 1 vCPU, 1-2GB RAM đủ sức phục vụ hàng trăm node.
3. Nếu VPS Headscale ngừng hoạt động, mạng Mesh có bị ngắt kết nối?
Không ngay lập tức. Các thiết bị đã kết nối vẫn duy trì liên lạc trực tiếp (P2P) bình thường. Tuy nhiên, bạn sẽ không thể thêm node mới hoặc cập nhật Policy cho đến khi máy chủ Headscale online trở lại.
4. Dữ liệu truyền qua Headscale có bị lộ không?
Không. Dữ liệu thực tế được mã hóa đầu cuối (End-to-End Encryption) bằng WireGuard và truyền trực tiếp giữa các thiết bị. VPS Headscale hoàn toàn không nhìn thấy hay can thiệp vào gói tin dữ liệu này.
5. Tailscale SSH có an toàn hơn dùng cổng 22 vật lý?
Có. Việc dùng Tailscale SSH giúp bạn đóng hoàn toàn port 22 ra Internet, tránh bị brute-force. Việc xác thực được xử lý qua danh tính mạng Mesh thay vì quản lý file authorized_keys thủ công.
6. Có bắt buộc phải dùng Headplane không?
Không bắt buộc nhưng được khuyên dùng. Bạn hoàn toàn có thể quản lý Headscale qua giao diện dòng lệnh (CLI). Headplane chỉ đóng vai trò giao diện Web UI giúp thao tác trực quan và tiết kiệm thời gian hơn.
Kết luận
Quá trình tích hợp Headscale và Headplane cung cấp cho đội ngũ vận hành một bộ công cụ điều phối mạng trực quan. Việc xây dựng Mesh Network trên VPS mang lại một môi trường làm việc thông suốt cho dev team, đảm bảo dữ liệu truyền tải được mã hóa an toàn, đồng thời giúp tổ chức kiểm soát hạ tầng bảo mật theo cách chủ động.
