Các bài viết về cách thiết lập WireGuard VPN bằng Docker trước đây của mình như wg-easy, wirehole-ui đều dùng cho mục đích tạo WireGuard VPN Server. Rồi sau đó sẽ dùng WireGuard client trên Windows, Linux hay iOS để kết nối vào WireGuard VPN Server.
Bài viết này mình sẽ hướng dẫn cách thiết lập WireGuard client trên máy chủ Linux sử dụng Docker và chuyển hướng kết nối mạng của máy chủ đi qua WireGuard VPN.
I. Yêu cầu chuẩn bị
- Một máy chủ đã được cài đặt sẵn Docker và Docker Compose.
- Một máy chủ đã được thiết lập sẵn WireGuard VPN Server: có thể sử dụng wg-easy hoặc Wirehole-UI để thiết lập.
- File cấu hình WireGuard client được tạo ra bởi WireGuard Server, có dạng như dưới đây
[Interface]
PrivateKey = sO7U9OS0s5vxxxdfY1aNHzVYXpJhKAaU/HG9MyfaWU=
Address = 10.6.0.8/24
DNS = 10.2.0.100
[Peer]
PublicKey = 9NknLwkQRaxxxsfNr9wKIC15KsqRvN5eOwUZxuhDFWI=
PresharedKey = xhqj9bnxxxuuFtzbVJ5GJPD6D4YAMHdk6RbL5JVkT+M=
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 0
Endpoint = 222.222.96.107:51822
II. Chuyển hướng mạng của máy chủ đi qua WireGuard VPN
Thứ tự công việc cần làm:
- Thiết lập WireGuard client sử dụng image WireGuard của Linuxserver
- Chỉnh sửa Routing Table để điều hướng mạng đi qua IP của WireGuard client container.
1. Tạo Docker network
Để có thể điều hướng mạng bằng routing table, container Wireguard client cần sử dụng IP tĩnh để tránh rắc rối về sau. Mình sẽ tạo 1 mạng docker bridge mới với tên gọi wgnet
bằng lệnh
docker network create --subnet 172.30.0.0/24 wgnet
Kiểm tra lại thông số của wgnet
bằng lệnh docker inspect wgnet
[
{
"Name": "wgnet",
"Id": "395281362a007244f03d8b8008a12c55ecea141410143d970376029564d5a02c",
"Created": "2022-09-28T21:40:39.761479649+07:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.30.0.0/24"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
Kiểm tra Routing Table hiện tại bằng lệnh ip route show
default via 192.168.0.1 dev ens18
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.18.0.0/16 dev br-3e6bd5841382 proto kernel scope link src 172.18.0.1
172.20.0.0/16 dev br-aadab51557e3 proto kernel scope link src 172.20.0.1
172.22.0.0/16 dev br-31493810cb58 proto kernel scope link src 172.22.0.1
172.24.0.0/16 dev br-e6e5decbac26 proto kernel scope link src 172.24.0.1
172.30.0.0/24 dev br-395281362a00 proto kernel scope link src 172.30.0.1 linkdown
192.168.0.0/24 dev ens18 proto kernel scope link src 192.168.0.138
Có thể thấy mạng 172.30.0.0/24
đã được tạo và hiện ra trong routing table của máy chủ. Tuy nhiên nó đang có trạng thái linkdown
vì chưa có container nào kết nối vào mạng này.
Hiện tại tất cả kết nối ra Internet đều được điều hướng qua LAN gateway 192.168.0.1
, được cấu hình qua mục default via 192.168.0.1 dev ens18
Chúng ta cần phải chỉnh sửa lại routing table này sau khi đã thiết lập thành công Wireguard container, để cho kết nối mạng sẽ đi qua WireGuard chứ không phải qua LAN Gateway.
2. Tạo file cấu hình wg0.conf
Trong bài này mình sẽ lấy file cấu hình từ Wireguad VPN Server được thiết lập bằng Wirehole-UI. Truy cập vào dashboard của wg-easy, tạo client mới và tải file cấu hình về, có nội dung tương tự như dưới đây
[Interface]
PrivateKey = sO7U9OS0s5vxxxdfY1aNHzVYXpJhKAaU/HG9MyfaWU=
Address = 10.6.0.8/24
DNS = 10.2.0.100
[Peer]
PublicKey = 9NknLwkQRaxxxsfNr9wKIC15KsqRvN5eOwUZxuhDFWI=
PresharedKey = xhqj9bnxxxuuFtzbVJ5GJPD6D4YAMHdk6RbL5JVkT+M=
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 0
Endpoint = 222.222.96.107:51822
Với cấu hình này, một đường truyền tunnel sẽ được tạo ra và tất cả kết nố bên trong WireGuard container sẽ đi qua tunnel này. Tuy nhiên, chúng ta muốn còn kết nối của máy chủ, nằm ngoài container đi qua Wireguard Tunnel. Do đó, cần phải cấu hình NAT để kết nối đi đúng hướng bằng lệnh sau:
iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
Để thiết lập tự động, mình sẽ dùng thông số PostUp
và PreDown
trong file cấu hình của WireGuard.
- PostUp: lệnh sẽ chạy sau khi WireGuard tunnel được tạo.
- PostDown: lệnh sẽ chạy trước khi WireGuard tunnel bị hủy.
PostUp = iptables -t nat -A POSTROUTING -o wg+ -j MASQUERADE
PreDown = iptables -t nat -D POSTROUTING -o wg+ -j MASQUERADE
Lưu lại cấu hình cuối cùng trong thư mục /home/thuanbui/wireguad-client/config/wg0.conf
mkdir -p /home/thuanbui/wireguard-client/config
nano /home/thuanbui/wireguard-client/config/wg0.conf
Nhập vào nội dung sau và lưu lại
[Interface]
PrivateKey = sO7U9OS0s5vxxxdfY1aNHzVYXpJhKAaU/HG9MyfaWU=
Address = 10.6.0.8/24
DNS = 10.2.0.100
PostUp = iptables -t nat -A POSTROUTING -o wg+ -j MASQUERADE
PreDown = iptables -t nat -D POSTROUTING -o wg+ -j MASQUERADE
[Peer]
PublicKey = 9NknLwkQRaxxxsfNr9wKIC15KsqRvN5eOwUZxuhDFWI=
PresharedKey = xhqj9bnxxxuuFtzbVJ5GJPD6D4YAMHdk6RbL5JVkT+M=
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 0
Endpoint = 222.222.96.107:51822
3. Tạo Wireguard client container
Tạo file docker-compose.yml
để thiết lập Wireguard Client
cd /home/thuanbui/wireguard-client
nano docker-compose.yml
Nhập vào nội dung sau
services:
wireguard:
image: lscr.io/linuxserver/wireguard
container_name: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Ho_Chi_Minh
volumes:
- ./config:/config
- /lib/modules:/lib/modules
networks:
default:
ipv4_address: 172.30.0.50
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
restart: unless-stopped
networks:
default:
name: wgnet
external: true
Các thông số cần chú ý:
- Phần
networks
được cấu hình để WireGuard container kết nối vào Docker netwokwgnet
đã tạo trước đó. - Dòng 17: cấu hình IP tĩnh cho container
172.30.0.50
Kích hoạt Docker container bằng lệnh docker-compose up -d
.
Để bảo đảm WireGuard Tunnel đã được tạo thành công, kiểm tra lại logs bằng lệnh docker logs wireguard
. Nếu thấy nó kết thúc với nội dung như dưới đây nghĩa là Tunnel đã được tạo thành công
s6-rc: info: service 99-ci-service-check successfully started
Warning: `/config/wg0.conf' is world accessible
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.6.0.8/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] resolvconf -a wg0 -m 0 -x
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
sysctl: setting key "net.ipv4.conf.all.src_valid_mark", ignoring: Read-only file system
[#] iptables-restore -n
[#] iptables -t nat -A POSTROUTING -o wg+ -j MASQUERADE
Nếu trong logs hiện ra lỗi như dưới đây, bạn cần chỉnh sửa lại dòng AllowedIPs
trong file wg0.conf, xóa ::/0
và chỉ chừa lại 0.0.0.0/0
. Sau đó khởi động lại container.
Error: IPv6 is disabled on nexthop device.
[#] resolvconf -d wg0 -f
[#] ip link delete dev wg0
Kiểm tra lại routing table bằng lệnh ip route show
default via 192.168.0.1 dev ens18
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.18.0.0/16 dev br-3e6bd5841382 proto kernel scope link src 172.18.0.1
172.20.0.0/16 dev br-aadab51557e3 proto kernel scope link src 172.20.0.1
172.22.0.0/16 dev br-31493810cb58 proto kernel scope link src 172.22.0.1
172.24.0.0/16 dev br-e6e5decbac26 proto kernel scope link src 172.24.0.1
172.30.0.0/24 dev br-395281362a00 proto kernel scope link src 172.30.0.1
192.168.0.0/24 dev ens18 proto kernel scope link src 192.168.0.138
Có thể thấy mạng 172.130.0.0/24
giờ đã được kích hoạt vì đã có WireGuard kết nối vào, không còn trạng thái linkdown nữa.
Tuy nhiên lúc này, kết nối ra ngoài của máy chủ vẫn chưa chạy qua WireGuard Tunnel, kiểm tra bằng lệnh curl ifconfig.me
.
115.xxx.xxx.xx
Kết quả trả về là Public IP của máy chủ nghĩa là kết nối vẫn chưa đi qua WireGuard tunnel.
4. Chỉnh sửa routing table
Sử dụng lệnh sau để chỉnh sửa lại Routing table
sudo ip route del default
sudo ip route add 222.222.96.107 via 192.168.0.1
sudo ip route add default via 172.30.0.50
- Dòng 1: xóa routing mặc định
- Dòng 2:
222.222.96.107
là IP của WireGuard VPN, cần phải được đi qua LAN Gateway để tránh bị vòng lặp - Dòng 3: tạo routing mặc định cho mọi kết nối đi qua IP của WireGuard container
172.30.0.50
Kiểm tra lại ip route show
sẽ thấy kết nối ra ngoài được điều hướng đi qua 172.30.0.50
default via 172.30.0.50 dev br-395281362a00
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.18.0.0/16 dev br-3e6bd5841382 proto kernel scope link src 172.18.0.1
172.20.0.0/16 dev br-aadab51557e3 proto kernel scope link src 172.20.0.1
172.22.0.0/16 dev br-31493810cb58 proto kernel scope link src 172.22.0.1
172.24.0.0/16 dev br-e6e5decbac26 proto kernel scope link src 172.24.0.1
172.30.0.0/24 dev br-395281362a00 proto kernel scope link src 172.30.0.1
192.168.0.0/24 dev ens18 proto kernel scope link src 192.168.0.138
222.222.96.107 via 192.168.0.1 dev ens18
Kiểm tra lại IP của máy chủ bằng lệnh curl ifconfig.me
222.222.96.107
Kết quả trả về bây giờ là IP của WireGuard Server. Nghĩa là chúng ta đã cấu hình thành công cho kết nối của máy chủ đi qua WireGuard Tunnel. Hura!
5. Thiết lập System Service
Routing table của máy chủ sẽ quay lại mặc định mỗi khi khởi động lại máy, khiến cho các thông số vừa mới chỉnh không còn hiệu lực. Để cấu hình cho kết nối mạng của máy chủ luôn luôn đi qua WireGuard Tunnel, chúng ta sẽ tạo 1 system service để nó tự động chỉnh sửa routing table mỗi khi khởi động
sudo nano /lib/systemd/system/iproute.service
Nhập vào nội dung sau
[Unit]
Description=Route everything through WireGuard
After=docker.service
[Service]
Type=oneshot
Restart=on-failure
ExecStart=ip route del default
ExecStart=ip route add 222.222.96.107 via 192.168.0.1
ExecStart=ip route add default via 172.30.0.50
[Install]
WantedBy=multi-user.target
Kích hoạt service
sudo systemctl enable iproute.service
Vậy là xong. Máy chủ sẽ luôn tự động kết nối thông qua WireGuard Tunnel mỗi khi khởi động lại.
Chúc bạn thực hiện thành công!
Nguồn tham khảo: https://www.linuxserver.io/blog/routing-docker-host-and-container-traffic-through-wireguard