WireGuard VPN trên Ubuntu Server: Cài đặt và cấu hình từ A đến Z

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Vấn đề thực tế: Team bạn remote access kiểu gì?

Sau khi audit security cho 10+ server của các dự án khác nhau, mình nhận thấy hầu hết đều có chung một vấn đề: không có VPN hoặc dùng VPN theo kiểu “tạm bợ”. Cụ thể là:

  • Mở thẳng SSH port 22 ra internet, bot scan thấy ngay
  • Dùng OpenVPN nhưng setup rối, người dùng cuối phải copy file .ovpn lằng nhằng
  • Một số team dùng TeamViewer hoặc ngrok — giải pháp “tạm” thành vĩnh viễn

Kết quả không khó đoán: bot scan port suốt ngày đêm, brute-force SSH lúc 3 giờ sáng, log server ngập rác. Mình từng check auth.log của một con staging server — 24 giờ có tới 15,000 lần thử login từ IP Trung Quốc và Nga. Server đó chỉ chạy môi trường dev, nhưng bị compromise vẫn là headache không cần thiết.

Câu trả lời khá hiển nhiên: đóng hết port public lại, chỉ cho vào qua VPN. Nhưng VPN nào vừa dễ dùng, vừa nhanh, lại không phải mất cả buổi cấu hình?

Tại sao OpenVPN không phải lúc nào cũng là câu trả lời?

Mình không nói OpenVPN xấu — nó battle-tested, ổn định, đã dùng nhiều năm. Nhưng có vài điểm làm mình ngại khi setup mới:

  • Chậm hơn cần thiết: OpenVPN chạy ở userspace, mỗi gói tin phải đi kernel → userspace → kernel. Benchmark thực tế cho thấy OpenVPN thường chỉ đạt 100–200Mbps, trong khi WireGuard có thể bão hòa đường 1Gbps trên cùng phần cứng. Cái chênh lệch này rất rõ khi làm việc qua VPN với database hoặc file server
  • Config phức tạp: PKI infrastructure, CA, certificate, file .ovpn — mỗi lần thêm client mới là cả một quy trình
  • Khó debug: Khi có sự cố, log của OpenVPN đôi khi không giúp ích gì nhiều

Đã có hạ tầng OpenVPN chạy ổn rồi thì không cần đổi. Còn setup mới từ đầu, WireGuard là thứ mình sẽ đề xuất ngay.

WireGuard: VPN thế hệ mới, code base nhỏ đến bất ngờ

Jason Donenfeld viết WireGuard với chỉ khoảng 4,000 dòng code — so với OpenVPN ~70,000 dòng. Ít code = ít attack surface = dễ audit hơn. Linus Torvalds gọi nó là “a work of art” và tích hợp thẳng vào Linux kernel từ version 5.6 — tức Ubuntu 20.04 trở lên đã có sẵn, không cần cài thêm module.

Đây là lý do mình dùng WireGuard cho mọi setup mới:

  • Chạy trong kernel: Không có overhead userspace như OpenVPN, throughput cao hơn hẳn
  • Handshake cực nhanh: Khoảng 100ms để establish connection — OpenVPN thường mất 1–2 giây
  • Cryptography hiện đại: ChaCha20, Poly1305, Curve25519 — không phải RSA/AES cũ kỹ
  • Config tối giản: Mỗi peer chỉ cần public key — không cần CA, không cần certificate
  • Stealth mặc định: WireGuard không respond với packet không hợp lệ, port scan sẽ thấy port này như đóng

Cài đặt và cấu hình WireGuard từng bước

Mô hình setup: 1 Ubuntu Server làm VPN gateway (có IP public) + N client (laptop dev, máy văn phòng…). Môi trường test: Ubuntu 22.04 LTS.

Bước 1: Cài đặt WireGuard

sudo apt update
sudo apt install wireguard -y

Trên Ubuntu 20.04+, WireGuard có sẵn trong repo chính thức, không cần thêm PPA.

Bước 2: Tạo key pair cho server

WireGuard dùng public/private key — không cần username hay password. Mỗi peer (server hoặc client) đều có 1 cặp key riêng.

sudo mkdir -p /etc/wireguard
cd /etc/wireguard

# Tạo private key rồi derive public key từ nó
wg genkey | sudo tee server_private.key | wg pubkey | sudo tee server_public.key

# Xem nội dung key
sudo cat server_private.key
sudo cat server_public.key

Quan trọng: Private key không được share với ai. Public key thì chia sẻ thoải mái — đó là nguyên lý của asymmetric cryptography.

Bước 3: Tạo file cấu hình server

sudo nano /etc/wireguard/wg0.conf

Nội dung file cấu hình:

[Interface]
# Dán nội dung server_private.key vào đây
PrivateKey = <SERVER_PRIVATE_KEY>

# IP của tunnel interface (dải IP nội bộ VPN, không phải IP public)
Address = 10.0.0.1/24

# Port WireGuard lắng nghe (UDP)
ListenPort = 51820

# Bật IP forwarding và NAT khi tunnel lên
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# Thêm mỗi client vào 1 block [Peer]
[Peer]
# Public key của client 1
PublicKey = <CLIENT1_PUBLIC_KEY>
# IP được cấp cho client này trong tunnel
AllowedIPs = 10.0.0.2/32

Chú ý: Thay eth0 bằng interface mạng thực tế của server. Chạy ip a để xác nhận trước — tùy VPS provider có thể là ens3, enp0s3, hoặc eth0. Đừng đoán, cứ kiểm tra cho chắc.

Bước 4: Bật IP Forwarding

# Bật ngay lập tức
sudo sysctl -w net.ipv4.ip_forward=1

# Bật vĩnh viễn (tồn tại qua reboot)
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Bước 5: Tạo key pair cho client

Trên máy client chạy Linux:

sudo apt install wireguard -y
wg genkey | tee client_private.key | wg pubkey | tee client_public.key

Nếu client là Windows hoặc macOS, dùng app WireGuard chính thức — app có nút “Generate keypair” trong UI, không cần dùng terminal.

Bước 6: Cấu hình client

Tạo file config này trên client (hoặc import vào app WireGuard trên Windows/macOS):

[Interface]
# Dán nội dung client_private.key vào đây
PrivateKey = <CLIENT_PRIVATE_KEY>

# IP được cấp cho client trong VPN tunnel
Address = 10.0.0.2/24

# DNS khi kết nối VPN (tùy chọn)
DNS = 1.1.1.1

[Peer]
# Public key của SERVER
PublicKey = <SERVER_PUBLIC_KEY>

# IP public của server + port
Endpoint = <SERVER_PUBLIC_IP>:51820

# Traffic nào đi qua VPN:
# 0.0.0.0/0 = toàn bộ traffic (full tunnel)
# 10.0.0.0/24 = chỉ traffic nội bộ VPN (split tunnel)
AllowedIPs = 10.0.0.0/24

# Giữ kết nối khi đứng sau NAT (router gia đình, 4G...)
PersistentKeepalive = 25

Bước 7: Khởi động WireGuard trên server

# Khởi động tunnel
sudo wg-quick up wg0

# Bật tự động chạy khi reboot
sudo systemctl enable wg-quick@wg0

# Kiểm tra trạng thái
sudo wg show

Output của wg show hiển thị thông tin tunnel và danh sách peer. Thấy dòng latest handshake ở phần peer là client đã kết nối thành công.

Bước 8: Mở port trên firewall server

# Nếu dùng UFW
sudo ufw allow 51820/udp
sudo ufw reload

# Nếu dùng iptables trực tiếp
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT

Kiểm tra kết nối thực tế

Client kết nối xong, test nhanh từ terminal:

# Ping server qua VPN IP (không phải IP public)
ping 10.0.0.1

# SSH vào server qua VPN IP
ssh [email protected]

Ping và SSH được qua 10.0.0.1 là VPN hoạt động tốt. Handshake thường xong dưới 1 giây — lần đầu kết nối bạn sẽ ngạc nhiên vì nó nhanh như vậy. Từ đây có thể đóng SSH port 22 trên firewall — chỉ ai có WireGuard key mới vào được server.

Thêm client mới: Không cần restart service

Đây là điểm mình thích nhất ở WireGuard. Thêm client mới không cần sign certificate hay restart tunnel:

# Thêm peer mới ngay lập tức (có hiệu lực không cần restart)
sudo wg set wg0 peer <CLIENT2_PUBLIC_KEY> allowed-ips 10.0.0.3/32

# Đồng thời thêm vào /etc/wireguard/wg0.conf để tồn tại qua reboot:
# [Peer]
# PublicKey = <CLIENT2_PUBLIC_KEY>
# AllowedIPs = 10.0.0.3/32

Troubleshooting các lỗi thường gặp

  • Ping được 10.0.0.1 nhưng không ra được internet: Chạy cat /proc/sys/net/ipv4/ip_forward — phải ra 1. Đúng rồi mà vẫn lỗi? Kiểm tra tên interface trong PostUp có khớp với ip a không
  • Không kết nối được gì: Chạy sudo wg show — không thấy latest handshake nghĩa là UDP port 51820 đang bị block. Kiểm tra UFW hoặc Security Group trên VPS
  • Kết nối bị ngắt sau vài phút: Thêm PersistentKeepalive = 25 vào config client — bắt buộc phải có khi client đứng sau NAT
  • Lỗi “invalid key”: File config phải chứa nội dung key thực (chuỗi base64), không phải tên file server_private.key

Setup xong cho cả team, log server sạch bóng. Không còn brute-force SSH, không còn hàng nghìn failed login mỗi ngày. Server đóng gần hết port public, chỉ mở 51820/UDP và 443/TCP — đúng kiểu security mà mình muốn từ đầu.

Share: