Guide · OpenWrt
OpenWrt WireGuard: a working tunnel in LuCI
WireGuard on OpenWrt is not a bolt-on. The protocol itself is a kernel module in Linux, so on a router running OpenWrt there is no out-of-tree build and no DKMS step: the driver is already in the image. What you add is the tooling — wireguard-tools for the wg command, and luci-proto-wireguard when you want the tunnel to appear as an interface type in the web interface. This guide walks the whole path: packages, keys, peers, the firewall rule, a site-to-site link between two OpenWrt routers, and the tunnel that gets you back to Home Assistant without opening port 8123 to the internet.
What WireGuard is, in one paragraph
WireGuard is a VPN protocol built on the Noise framework, with Curve25519 for key exchange and ChaCha20, Poly1305, BLAKE2 and SipHash24 for transport and hashing. Peers are configured by exchanging public keys and nothing else — the project's own description is "as easy to configure and deploy as SSH" — and a peer can roam between IP addresses without renegotiating. It is deliberately silent: it sends no packets unless a peer has traffic to send. That silence is the source of the most common support question on phones behind NAT, which we come back to below. Source: wireguard.com.
Which packages, and the 25.12 packaging change
OpenWrt stable is 25.12.6, published 18 October 2026; oldstable is 24.10.8, published 26 July 2026 (OpenWrt releases). The two branches handle packages differently, and this is where most copy-pasted instructions go wrong.
On 25.12.x the package manager is apk. The packages/ and luci/ directories for 25.12.6 contain index.json and .apk files, not .ipk; 24.10.8 still ships .ipk and still uses opkg. So:
- 25.12.6: install with
apk add luci-proto-wireguard wireguard-tools. The LuCI package in this release is built asluci-proto-wireguard-26.304.26398~e969939.apk(25.12.6 package index). - 24.10.8: install with
opkg install luci-proto-wireguard wireguard-tools. The LuCI package there isluci-proto-wireguard_26.301.70438~aa4865e_all.ipk(24.10.8 package index).
luci-proto-wireguard is a protocol handler: it teaches LuCI what a WireGuard interface is, so the Interfaces page offers it alongside DHCP client, static address and PPPoE. Without it, wg still works from a shell but the tunnel never shows up in the web interface.
25.12.6 also bumped wireguard-tools to 1.0.20260223 from 1.0.20250521, and fixed sysupgrade -u and -f behaviour that had broken "with apk" (release notes). If you keep configuration across upgrades with sysupgrade -u, that fix is the one that matters to you.
Step one: keys
Every peer has a private key and a public key, both base64. Generate them on the router, or anywhere with wg installed, exactly as the quickstart describes:
umask 077; wg genkey > privatekey
wg pubkey < privatekey > publickey
The umask 077 is not decoration — it is what keeps the private key readable only by its owner. Source: WireGuard quickstart. Do not reuse one key pair for several peers; each device gets its own, which is also what makes revoking a lost phone a one-line change.
Step two: the interface
In LuCI, add a new interface and choose the WireGuard VPN protocol that luci-proto-wireguard provides. Give it an address on a private range — the quickstart's own example uses 192.168.2.1/24 for the router side and 192.168.2.2 for the other peer — and set a listen port. Port 51820 appears in every example, but it is a convention, not a requirement: pick any UDP port, as long as every peer's endpoint names the same one.
The same interface can be built from a shell, which is useful when you are scripting or when LuCI is not installed:
ip link add dev wg0 type wireguard
ip address add dev wg0 192.168.2.1/24
wg set wg0 listen-port 51820 private-key /etc/wireguard/privatekey
ip link set up dev wg0
Those four commands are the quickstart's own sequence (wireguard.com/quickstart). Vanilla wg leaves the interface setup to you; wg-quick is the wrapper that automates the wg-and-ip dance from a single config file. On OpenWrt you rarely need wg-quick, because the init system and LuCI already do that work — wg setconf and wg set are what you reach for when you want to apply settings by hand.
Step three: peers
A peer entry is four things: the other side's public key, the addresses or subnets you expect to find behind it (allowed-ips), where to reach it (endpoint), and optionally a keepalive. Set from the shell, that looks like the quickstart's example:
wg set wg0 peer <PUBKEY> allowed-ips 192.168.88.0/24 endpoint 209.202.254.14:8172
In LuCI the same fields are a form under the interface's Peers tab. Two habits save trouble later:
allowed-ipsis a routing statement as much as a permission. List only the subnets that peer should reach. A phone that should see your house does not need0.0.0.0/0unless you intend to send all its traffic through the tunnel.- The server side should not carry an
endpointfor a roaming client. Clients dial in; the router learns their address from the last authenticated packet.
wg show prints the live state — handshakes, transfer counters, the current endpoint — and wg showconf prints the configuration in a form you can save. With no arguments, wg behaves like wg show across all interfaces (quickstart). When a tunnel "doesn't work", the handshake timestamp in that output tells you whether you have a routing problem or a key problem.
Step four: the firewall
Only one port needs to face the internet: the UDP port you set as the interface's listen port. Add an inbound rule on the WAN zone for that protocol and port, with the destination set to the router itself. Do not forward 8123, SSH or the LuCI port — the point of the tunnel is that they stay closed. On the tunnel side, make sure the WireGuard interface is in a firewall zone that can reach the LAN, otherwise the handshake succeeds and nothing behind the router answers.
Site-to-site between two OpenWrt routers
Two routers, one tunnel, each the other's peer. Each side lists the other's LAN subnet in allowed-ips, plus the tunnel address of the far router if you want to reach the router itself. The side with a static public address sets no endpoint on its peer entry; the side behind a consumer connection points its endpoint at the public address and sets persistent-keepalive so the tunnel stays open through its own NAT. This is the same shape as a hub-and-spoke setup with a single client, just symmetric. If you are still choosing the hardware, see our OpenWrt mesh network feature.
The keepalive gotcha
WireGuard sends nothing when a peer is idle. That is a feature for battery and bandwidth, and a bug report generator for phones. A phone on a carrier network or a laptop behind a hotel router sits behind NAT; the NAT mapping expires after a few minutes of silence, and the next packet from the server side has nowhere to go. The fix is on the peer that is behind NAT: persistent-keepalive at 25 seconds. The quickstart notes exactly this — peers behind NAT or a firewall need a keepalive to stay reachable (quickstart). If a tunnel works for two minutes and then dies, this is almost always why.
Getting back to Home Assistant
The safe pattern for remote access to a home server is a tunnel that reaches only the LAN, with no inbound rule for the service itself. Give the phone a peer whose allowed-ips is your LAN subnet; the phone then resolves and reaches the Home Assistant machine on its usual port, and the router's firewall keeps everything else closed. Split tunnelling — LAN traffic through the tunnel, everything else direct — is usually what you want on a phone, and it falls out of a narrow allowed-ips. If you would rather not run a publicly reachable endpoint or manage key files on every device, Tailscale is the other common answer in this space and is covered separately in our plan; the trade is convenience for a third-party coordination service. For the local-radio side of the same house, see how a Thread network fits together.
Hardware that runs it today
Any OpenWrt-supported router will do — WireGuard is in the kernel, not an add-on module — but these three have official builds on both current branches, which is what you want if you intend to keep the tunnel patched:
- GL.iNet GL-MT3000 (mediatek/filogic), official 24.10.8 and 25.12.6 builds — firmware selector; device page; GL-MT3000 on Amazon.
- GL.iNet GL-MT6000 (mediatek/filogic), official 24.10.8 and 25.12.6 builds — firmware selector; device page; GL-MT6000 on Amazon.
- Linksys E8450 / Belkin RT3200 (mediatek/mt7622), official 24.10.8 and 25.12.6 builds — firmware selector; device page; Linksys E8450 on Amazon.
Support status here comes from the firmware selector and the device pages, not from a lab test. Check the selector for your exact model before buying — a router that is only supported on the development snapshot will lose its tunnel config on the next image change. Comparing OpenWrt with the other common router firmware is covered in OpenWrt vs DD-WRT.
FAQ
Is WireGuard built into OpenWrt, or do I install a package?
The WireGuard implementation itself is a kernel module on Linux, so there is no out-of-tree DKMS build step on OpenWrt. What you install is the userspace tooling (wireguard-tools for the wg command) and, if you want it in the web interface, the LuCI protocol handler luci-proto-wireguard.
Which packages do I need for WireGuard in LuCI, and what changed in 25.12?
You need luci-proto-wireguard for the interface type in LuCI and wireguard-tools for the wg command. OpenWrt 25.12.6 ships apk packages, not opkg, so opkg install commands from older guides do not work; use apk add. Version 24.10.8 still uses ipk packages and opkg.
How do I open the WireGuard port on the OpenWrt firewall, and should I use 51820?
You add an inbound rule for UDP on whichever port you set as the interface listen port, pointed at the router itself. 51820 is only a convention from the WireGuard quickstart examples; any UDP port works as long as both ends agree and the port is allowed.
How do I reach my Home Assistant box from outside without exposing it?
Put the Home Assistant machine on the router's LAN and give the phone or laptop a WireGuard peer whose allowed-ips covers only that LAN subnet. The tunnel then reaches port 8123 without any inbound rule for Home Assistant itself; the only open port is the WireGuard UDP port.
Why does my WireGuard tunnel drop after a few minutes on a phone behind NAT?
WireGuard sends nothing when idle, so a NAT or firewall may forget the mapping. Setting persistent-keepalive to 25 seconds on the peer keeps the hole open.
Can I run a WireGuard site-to-site link between two OpenWrt routers?
Yes. Each router is a peer of the other, and each lists the other's LAN subnet in allowed-ips. If one side has no public address, the side behind NAT sets persistent-keepalive and the public side needs a reachable endpoint.
As an Amazon Associate, HA News earns from qualifying purchases.