Khắc phục tình trạng VPN WireGuard bị treo

Trước đây tôi có viết bài Dựng mạng VPN với WireGuard . Sau một thời gian sử dụng, để ý thấy do các máy con (client) của tôi thỉnh thoảng xảy ra tình trạng treo WireGuard: từ các máy khác không ping đến nó được. Vì vậy tôi lại tiếp tuc đề tài WireGuard này, giới thiệu một cách khắc phục.

Trước tiên, xin nêu vài nguyên nhân khiến VPN WireGuard bị treo:

  • WireGuard của năm 2018 (lúc tôi viết bài trên) được nạp lên hệ thống dưới dạng DKMS. Như ta đã biết, khác với các giải pháp VPN thông thường, WireGuard chạy dưới dạng một driver/module của nhân Linux. Nhưng khi được phân phối ở dạng DKMS, mỗi lần máy được nâng cấp nhân mới thì module này phải trải qua quá trình build lại từ mã nguồn bên ngoài. Điều này đôi khi gây ra tình trạng, phiên bản cũ vẫn còn lơ lửng trong RAM và phiên bản mới chưa thế chân vào được, thế là WireGuard bị treo. Từ Linux 5.6 trở đi thì WireGuard đã được tích hợp vào nhân, không còn ở dạng DKMS nữa nên tình trạng này không còn.

  • Network interface của WireGuard (ví dụ wg0) được khởi tạo khi máy vẫn chưa thực sự kết nối với Internet (sai thứ tự), việc kết nối với server VPN không thành công, khiến việc cấu hình không hoàn tất. Hoặc khi đang chạy ngon bỗng dưng Internet bị rớt, mất luôn mối kết nối với server. Điều này hay xảy ra với các máy con (client) vì các máy này không được đảm bảo luôn có Internet, thậm chí là không phải lúc nào cũng có điện.

Dựa vào các nguyên nhân trên thì có hai bước phải làm để trị dứt điểm tình trạng WireGuard treo.

  1. Nâng cấp hệ điều hành. Nếu máy của bạn dùng Ubuntu thì nâng cấp lên Ubuntu 20.04 là vừa đủ. Mặc dù Ubuntu 20.04 mới chỉ có Linux 5.4 thôi nhưng đội ngũ tác giả đã "backport" lại sự tích hợp WireGuard của Linux 5.6 vào. Sau khi nâng cấp, nhớ gỡ gói wireguard-dkms ra.

  2. Không dùng script wg-quick để khởi tạo network interface cho WireGuard nữa, mà chuyển việc đó cho các phần mềm chuyên quản lý mạng như systemd-networkd, NetworkManager v.v... để đảm bảo việc khởi tạo network interface cho WireGuard diễn ra sau khi đã kết nối Internet. Dưới đây tôi sẽ trình bày cách chuyển đổi khi bạn đang có WireGuard chạy với wg-quick rồi.

Bài chỉ dẫn này dành cho systemd-networkd trên Ubuntu. Tôi viết cho Ubuntu vì đây là hệ điểu hành mà các máy con của tôi dùng. Ngoài systemd-networkd, tôi cũng đã thử nghiệm NetworkManager, nhưng trên Ubuntu 20.04, NetworkManager dường như có bug khiến thông số "persistent-keepalive" của WireGuard không được tôn trọng, nên tôi không viết về NetworkManager nữa.

Ta sẽ bắt đầu bằng cách chỉnh sửa cấu hình mạng trong Netplan. Netplan là một phần mềm riêng của Ubuntu để giúp việc cấu hình mạng đơn giản hơn. Bản thân Netplan không phải là phần mềm quản lý mạng, tức là nó không cùng thể loại với systemd-networkd, NetworkManager. Nó chỉ giúp việc sinh ra các file cấu hình cho systemd-networkd, NetworkManager bằng một file đầu vào đơn giản hơn.

Bây giờ hãy mở file cấu hình Netplan của bạn, trong /etc/netplan. Ví dụ trên máy tôi thì là file /etc/netplan/wired.yml. Ban đầu nó có nội dung tương tự thế này (máy này chỉ có một cổng mạng dây (Ethernet) là enp1s0):

network:
  version: 2
  renderer: networkd
  ethernets:
    enp1s0:
      dhcp4: true
      optional: true

Giả sử mạng LAN ảo, do WireGuard tạo ra, của bạn là 192.168.2.0/24, và máy con có địa chỉ trong mạng LAN ảo này là 192.168.2.100. Thêm vào file đó cấu hình cho WireGuard như sau:

  tunnels:
    wg0:
      mode: wireguard
      key: private_key_cua_may_con
      addresses: [192.168.2.100/24]
      peers:
        - keys:
            public: public_key_cua_server
          allowed-ips: [192.168.2.0/24]
          keepalive: 25
          endpoint: ip_cua_server:51820

Lưu ý, chữ tunnels thụt lề cùng cấp với ethernets.

Ta sẽ tắt tính năng tự khởi động service wg-quick đi, để tránh nó tranh chấp với systemd-networkd:

sudo systemctl disable wg-quick@wg0.service

Nếu bạn đang không truy cập từ xa vào máy con qua ngả VPN này thì nó thể tắt nó luôn bằng lệnh:

sudo systemctl disable --now wg-quick@wg0.service

Tiếp đến, yêu cầu Netplan sinh ra cấu hình mới cho systemd-networkd và làm các bước cần thiết để systemd-networkd tạo mới lại mạng theo chỉ dẫn trong cấu hình này:

sudo netplan apply

Ta có thể kiểm tra wg0 có đang được tạo ra và quản lý bởi systemd-networkd bằng cách:

$ networkctl
IDX LINK   TYPE      OPERATIONAL SETUP      
  1 lo     loopback  carrier     unmanaged  
  2 enp1s0 ether     routable    configured 
  3 wg0    wireguard routable    configured

Nhớ ping thử từ máy khác xem VPN có hoạt động thật không. Sau đó bạn có thể xóa file /etc/wireguard/wg0.conf đi được rồi.

Thế là xong, bây giờ ta có thể yên tâm WireGuard không còn bị treo nữa. Nhân tiện xin khoe hình ảnh trang nội bộ của AgriConnect để theo dõi trạng thái online/offline của các máy đặt tại trang trại khách hàng, cũng như bot Telegram cảnh báo khi có máy bị offline:

AgriConnect Status

Status bot