How to compile the WireGuard kernel module for LineageOS

4 min read

WireGuard is a free and open-source VPN, simpler, faster, and more secure than concurrent solutions. It is available as a Linux kernel module, but as a fallback, the Android application contains a user-space implementation that cannot provide the same level of performance and power efficiency as the kernel module.

Although WireGuard was merged into Linux 5.6, most Android devices still use older kernels. There are two methods to install the kernel module on an Android device:

This article presents a simple approach for unsupported devices:

  1. Fetch WireGuard through repo.
  2. Patch the kernel sources.
  3. Make the boot image.
  4. Flash it on the device.

To make the boot image, you need a working LineageOS build environment. See: How to build LineageOS inside a container.


The code samples use the following variables:

  • SRC_DIR: the top of the source tree (e.g., ~/android/lineage).
  • KERNEL_DIR: the relative location of the kernel from SRC_DIR (e.g., kernel/cyanogen/msm8916).
  • DEVICE: the Android device name (e.g., crackling).
  • ARCH: the system architecture (e.g., arm64).

Try to make the boot image without WireGuard first, to ensure everything is working properly.

Fetch WireGuard

Add the WireGuard module repository, backported for older kernel versions, in a local repo manifest (replace KERNEL_DIR with the appropriate path):

<?xml version="1.0" encoding="UTF-8"?>
	<remote name="zx2c4" fetch="" />
	<project remote="zx2c4" name="wireguard-linux-compat" path="kernel/wireguard-linux-compat" revision="master" sync-s="true">
		<linkfile src="src" dest="KERNEL_DIR/net/wireguard" />

The manifest instructs repo to clone the module to SRC_DIR/kernel/wireguard-linux-compat, and symlink this directory to KERNEL_DIR/net/wireguard.

Run repo sync, optionally with --force-sync, to fetch the module:

$ repo sync [--force-sync]

Patch the kernel

The kernel build system needs to know about this module. Add WireGuard to the net module Makefile:

 obj-$(CONFIG_LLC)        += llc/
 obj-$(CONFIG_NET)        += ethernet/ 802/ sched/ netlink/
 obj-$(CONFIG_NETFILTER)  += netfilter/
+obj-$(CONFIG_WIREGUARD)  += wireguard/
 obj-$(CONFIG_INET)       += ipv4/
 obj-$(CONFIG_XFRM)	      += xfrm/
 obj-$(CONFIG_UNIX)	      += unix/

Source the WireGuard module config from the net module config:

 if INET
 source "net/ipv4/Kconfig"
 source "net/ipv6/Kconfig"
 source "net/netlabel/Kconfig"
+source "net/wireguard/Kconfig"

Enable WireGuard in the kernel config for the device:


Make the boot image

Run the pre-build commands:

$ . ./build/
$ breakfast DEVICE

Then, make the boot image:

$ mka bootimage
[100% 8181/8181] Target boot image: out/target/product/DEVICE/boot.img
==== build completed successfully (23:45 (mm:ss)) ====

Flash the boot image

There are a few methods to install the boot image (they all end up flashing the boot partition in some way). Depending on how you update your phone, you might prefer to manually flash the boot partition, or to deliver the update through an installation package.

Method 1: fastboot

Reboot the device to the bootloader, then run:

$ fastboot flash boot boot.img

This method does not run /system/addon.d scripts. In particular, Magisk will not automatically patch the boot image in order to maintain root access.

Method 2: Patch an installation package

  1. Download the latest installation package for your device.

  2. Update boot.img inside the archive:

    $ zip boot.img
    updating: boot.img
    	zip warning: Local Entry CRC does not match CD: boot.img
     (deflated 57%)
  3. Install with ADB sideload as usual (TWRP ignores invalid signatures, but you may have to sign the build for other recoveries).


After rebooting the device, WireGuard should be using the kernel module as its backend:

WireGuard Android application backend information