Hướng dẫn cài đặt và cấu hình WireGuard VPN Server trên Linux: Kết nối từ xa an toàn, nhẹ và tốc độ cao

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Vấn đề với VPN truyền thống và tại sao WireGuard ra đời

Hầu hết các sysadmin khi cần VPN đều nghĩ ngay đến OpenVPN — cài được, chạy được, nhưng cấu hình cực kỳ rườm rà. Chứng chỉ CA, file .ovpn dài hàng trăm dòng, daemon nặng nề. Và mỗi khi client đổi mạng — từ WiFi sang 4G chẳng hạn — kết nối đứt ngay, phải reconnect lại từ đầu.

Mình gặp đúng bài toán đó khi công ty cần cho team remote truy cập vào hệ thống nội bộ. Trên con server chạy CentOS 7 cũ, mình đã mày mò đủ kiểu để đạt performance chấp nhận được — và sau nhiều lần thử nghiệm, WireGuard là thứ duy nhất thực sự giải quyết được vấn đề mà không kéo theo đống headache mới.

Từ Linux 5.6, WireGuard được tích hợp thẳng vào kernel — không cần module bên thứ ba. Toàn bộ codebase chỉ khoảng 4.000 dòng, so với hàng trăm nghìn dòng của stack OpenVPN + OpenSSL. Ít code hơn đồng nghĩa với ít điểm tấn công hơn, dễ audit bảo mật hơn, và overhead xử lý packet thấp hơn rõ rệt.

Khái niệm cốt lõi trước khi cài đặt

Khác với OpenVPN phân biệt cứng server/client, WireGuard dùng mô hình peer-to-peer — mỗi máy trong mạng là một peer bình đẳng, có cặp key riêng (private key + public key).

  • Interface: WireGuard tạo một network interface ảo (thường đặt tên wg0), tương tự như interface eth0 hay tun0.
  • Endpoint: Địa chỉ IP:port thực tế để các peer kết nối đến nhau (thường chỉ server mới cần khai báo).
  • AllowedIPs: Dải IP nào được phép đi qua tunnel. Đây là điểm khác biệt so với OpenVPN — WireGuard dùng chính trường này để định tuyến, không cần route table phức tạp.
  • PersistentKeepalive: Gửi packet giữ kết nối mỗi N giây — quan trọng khi client đứng sau NAT.

Điểm mấu chốt: WireGuard giữ trạng thái kết nối qua thay đổi mạng nhờ cơ chế roaming — client đổi IP không làm tunnel đứt, miễn là hai peer còn trao đổi được packet.

Thực hành: Cài đặt WireGuard Server

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

Trên Ubuntu 20.04/22.04:

sudo apt update
sudo apt install -y wireguard wireguard-tools

Trên CentOS 7/8 hoặc RHEL (cần thêm repo EPEL):

# CentOS 7
yum install -y epel-release
yum install -y kmod-wireguard wireguard-tools

# CentOS 8 / Stream
dnf install -y epel-release elrepo-release
dnf install -y kmod-wireguard wireguard-tools

Kiểm tra kernel module đã load chưa:

modprobe wireguard
lsmod | grep wireguard

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

WireGuard dùng Curve25519 cho key exchange — cùng thuật toán mà Signal Protocol sử dụng. Tạo key chỉ cần một lệnh:

cd /etc/wireguard
umask 077  # Quan trọng: đảm bảo private key không bị đọc bởi user khác
wg genkey | tee server_private.key | wg pubkey > server_public.key
cat server_private.key  # Lưu lại giá trị này
cat server_public.key   # Dùng cho client config

Lệnh umask 077 đảm bảo file key tạo ra có permission 600. Bỏ qua bước này, private key có thể bị đọc bởi bất kỳ user nào trên cùng server — và toàn bộ tunnel coi như bị compromise.

Bước 3: Tạo cấu hình server (/etc/wireguard/wg0.conf)

Tạo file cấu hình với nội dung sau:

cat > /etc/wireguard/wg0.conf << 'EOF'
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>

# Bật IP forwarding và NAT để client ra được internet qua VPN
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# Peer: Client 1
[Peer]
PublicKey = <CLIENT1_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
EOF

Lưu ý: Thay eth0 bằng interface thực của server (kiểm tra bằng ip route | grep default). Thay các placeholder <...> bằng key thực tế.

Bật IP forwarding vĩnh viễn:

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

Bước 4: Khởi động WireGuard và bật autostart

systemctl enable --now wg-quick@wg0
systemctl status wg-quick@wg0

# Xem trạng thái tunnel
wg show

Output của wg show sẽ hiển thị interface wg0, listening port, và danh sách peer đã kết nối.

Cấu hình phía Client

Tạo key pair cho client

Thực hiện trên máy client (Linux, macOS, Windows đều dùng cách tương tự):

wg genkey | tee client_private.key | wg pubkey > client_public.key

File cấu hình client (wg0.conf hoặc tunnel.conf)

[Interface]
Address = 10.0.0.2/24
PrivateKey = <CLIENT_PRIVATE_KEY>
DNS = 1.1.1.1  # Tùy chọn: dùng DNS qua tunnel

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <SERVER_PUBLIC_IP>:51820
AllowedIPs = 0.0.0.0/0  # Route toàn bộ traffic qua VPN
# Hoặc chỉ route subnet nội bộ:
# AllowedIPs = 10.0.0.0/24, 192.168.1.0/24
PersistentKeepalive = 25

Khởi động tunnel trên client:

sudo wg-quick up ./tunnel.conf

# Kiểm tra kết nối
ping 10.0.0.1  # Ping đến server
curl ifconfig.me  # Kiểm tra IP public (nên thấy IP của server VPN)

Thêm peer mới vào server mà không cần restart

Đây là một điểm mình rất thích ở WireGuard — thêm client mới không cần reload service:

# Thêm peer động (không ngắt kết nối hiện tại)
wg set wg0 peer <CLIENT2_PUBLIC_KEY> allowed-ips 10.0.0.3/32

# Lưu cấu hình hiện tại vào file
wg-quick save wg0

Mở firewall cho cổng WireGuard

Đừng quên mở port UDP 51820 trên firewall server:

# UFW (Ubuntu)
ufw allow 51820/udp

# firewalld (CentOS/RHEL)
firewall-cmd --permanent --add-port=51820/udp
firewall-cmd --reload

# iptables trực tiếp
iptables -A INPUT -p udp --dport 51820 -j ACCEPT

Nếu server đứng sau NAT (VPS cloud), nhớ mở port trong security group/network ACL của nhà cung cấp cloud.

Xử lý sự cố thường gặp

Một số vấn đề mình đã gặp và cách giải quyết:

  • Client kết nối được nhưng không ra internet: Kiểm tra ip_forward đã bật chưa (sysctl net.ipv4.ip_forward), và rule NAT MASQUERADE đúng interface.
  • Tunnel up nhưng ping không thông: Chạy wg show — nếu thấy dòng latest handshake thì đã bắt tay thành công. Không có dòng đó nghĩa là public key hoặc endpoint đang sai.
  • CentOS 7 không load được module: Kernel mặc định CentOS 7 (3.10.x) không hỗ trợ WireGuard native — phải dùng DKMS hoặc nâng kernel lên mainline qua ELRepo (yum install -y kernel-ml từ repo ELRepo).
  • Kết nối bị drop sau vài phút: Thêm PersistentKeepalive = 25 vào peer config phía client.

Kết luận

Sau vài tuần dùng thực tế, cả team hết phàn nàn về VPN bị đứt. Đổi mạng từ văn phòng về nhà, từ WiFi sang 4G — tunnel vẫn giữ nguyên. Thêm thành viên mới vào cũng xong trong vài phút, không cần đụng đến service đang chạy.

WireGuard không phải là phiên bản cải tiến của OpenVPN — đây là cách tiếp cận khác hẳn. 4.000 dòng chạy trong kernel thay vì hàng trăm nghìn dòng chạy ở userspace. Khi cần mở rộng: đổi AllowedIPs thành dải subnet cụ thể để có split tunneling, hoặc khai báo thêm DNS trong [Interface] phía client để truy cập service nội bộ bằng domain thay vì gõ IP.

Share: