NordVPN Easy is a package-first NordVPN WireGuard integration for OpenWrt. The project is being built around native OpenWrt components: UCI configuration, init service integration, a LuCI frontend, and periodic health-check and recovery logic.
- install
luci-app-nordvpn-easyfrom LuCISystem -> SoftwareThis only works after the relevant OpenWrt feeds and package indexes are set up and refreshed. In the build system, run the usual feeds update/install steps first; on the device, refresh package lists withopkg updateorapk updatebefore attempting installation from LuCI. - configure NordVPN from LuCI and UCI instead of editing shell code
- keep the tunnel healthy through scheduled checks and event-triggered recovery
- support NordVPN recommended WireGuard servers, optionally filtered by country
openwrt-packages/nordvpn-easyBackend package with UCI defaults, init integration and the runtime shell coreopenwrt-packages/luci-app-nordvpn-easyLuCI frontend package
- Log in to LuCI.
- Open
System -> Software. - Click
Update lists.... - Install
luci-app-filebrowser. - Log out from LuCI.
- Log in again.
- Open
System -> File Browser. - Open
etc/opkg/keys. - Download:
https://github.com/tis24dev/NordVPN-Easy-OpenWrt/raw/gh-pages/packages/opkg/e45702ccdd8637fd - Upload the key file (without any extension, only name
e45702ccdd8637fd - Open
System -> Software. - Click
Configure opkgand go:/etc/opkg/customfeeds.conf - Add:
src/gz nordvpn-easy https://tis24dev.github.io/NordVPN-Easy-OpenWrt/packages/opkg - Save the
opkgconfiguration. - Click
Update lists.... - In the
Filterbox, search fornordvpn-easy. - Install
luci-app-nordvpn-easy. - Log out from LuCI.
- Log in again.
- Open
Services -> NordVPN Easy. - Configure the service.
- Log in to LuCI.
- Open
System -> Software. - Click
Update lists.... - Install
luci-app-filebrowser. - Log out from LuCI.
- Log in again.
- Open
System -> File Browser. - Open
etc/apk/keys. - Download:
https://github.com/tis24dev/NordVPN-Easy-OpenWrt/releases/latest/download/vpn-easy-tis24dev.pem - Upload the PEM file.
- Open
System -> Software. - Click
Configure apkand go:/etc/apk/repositories.d/customfeeds.list - Add:
https://github.com/tis24dev/NordVPN-Easy-OpenWrt/releases/latest/download/luci-app-nordvpn-easy.adb - Save the
apkconfiguration. - Click
Update lists.... - In the
Filterbox, search fornordvpn-easy. - Install
luci-app-nordvpn-easy. - Log out from LuCI.
- https://my.nordaccount.com/dashboard/nordvpn/access-tokens/
- login
- Get Access token
- Generate new token
- Copy the token
- Close webpage
- Open
Services -> NordVPN Easy - Paste the token
- Select nation/server
- Flag enable
- Save&Apply
- Wait green led
The runtime model is service-driven and one-shot based:
/etc/config/nordvpn_easystores user configuration generated from the packaged template/etc/init.d/nordvpn-easymanages setup and recurring hooks/usr/libexec/nordvpn-easy/core.shprovisions the VPN through a singleprovisionpathcronruns periodic checkshotplugtriggers checks when WAN or VPN interfaces change state
There is no permanently running watchdog loop.
Connect, Reconnect, Setup, and Reconcile always perform a clean reprovision: tear down any existing WireGuard UCI, fetch fresh NordLynx credentials and server data over the WAN, recreate wg0, then validate connectivity. Stale peer configuration is not reused.
Each check execution is one-shot and does this:
- pings the VPN interface
- skips recovery when WAN is down
- reprovisions the VPN when the runtime is degraded (for example no WireGuard handshake while the default route uses
wg0) - waits briefly and reprovisions again if ping still fails while WAN is up
This makes the project a service-managed maintenance job rather than a daemon that loops forever.
The packaged service is configured through UCI in /etc/config/nordvpn_easy.
The package ships its defaults as /usr/share/nordvpn-easy/defaults/nordvpn_easy
and creates or migrates the live UCI file during install/upgrade, preserving
existing user values without installing /etc/config/nordvpn_easy as an opkg
conffile. Removing the package purges the generated config, stale *-opkg
files and NordVPN Easy runtime/cache residues. Key settings include:
nordvpn_tokenwan_ifvpn_ifvpn_countrywireguard_persistent_keepalive(default15)wireguard_mtu(empty means automatic)firewall_mtu_fix(default1)- health-check timing values (
failure_retry_delay,post_restart_delay, and related delays)
Country filtering is supported. The backend resolves the requested country and then asks NordVPN for recommended WireGuard servers inside that country. City selection is not implemented.
NordLynx uses WireGuard over UDP. For routers behind NAT, NordVPN Easy keeps the
peer alive with wireguard_persistent_keepalive=15 by default on every provision.
Use Services → NordVPN Easy → Diagnostics for a structured assessment and full log export. The main NordVPN Easy page also shows an alert banner when a primary issue is detected (for example routing blackhole, missing handshake, or kill switch active without a tunnel).
Common probable_issue_code values:
| Code | Typical cause |
|---|---|
routing.blackhole_default_via_vpn |
Default route uses the VPN before WireGuard connects |
runtime.no_handshake |
Peer configured but no recent handshake |
operational.kill_switch_active |
Kill switch on while the tunnel is down |
connectivity.wan_down |
WAN probe failed while VPN is enabled |
runtime.endpoint_unreachable |
NordVPN endpoint host not reachable from WAN |
Background diagnostics_summary polls from the main page and LuCI view refresh
skip active WAN/DNS probes to avoid extra load. A full log download or manual
assessment refresh runs the complete probe set (typically under a few seconds).
Findings are ranked by severity: routing blackhole and WAN/DNS failures surface
before handshake or configuration warnings. The summary JSON includes
primary_finding.severity, health.degraded_since, and
connectivity.vpn_endpoint_reachable (UDP endpoint probe via WAN when active
probes are enabled).
When the VPN transitions to degraded during a cron or health-check run, the
service logs probable_issue_code to syslog (logread -e nordvpn-easy). Example:
healthcheck: VPN state degraded: probable_issue_code=runtime.no_handshake severity=critical
healthcheck: VPN state recovered: was probable_issue_code=runtime.no_handshake for 120s; now state=connected
A short rolling history is kept at /tmp/run/nordvpn-easy/diagnostics_history.log.
The VPN health-check clears a routing blackhole automatically: if the default
route points at the VPN interface without a WireGuard handshake, it runs ifdown
on the tunnel before attempting API or server-list recovery.
If long-lived streams or downloads drop after roughly 30 seconds while OpenVPN is stable, check diagnostics first. Common causes are an aggressive upstream NAT, MTU/MSS blackholes, or a bad VPN server path rather than an OpenWrt log-visible interface failure.
Suggested checks:
- keep
wireguard_persistent_keepaliveat15; try10only for very aggressive NAT devices - leave
firewall_mtu_fix=1enabled so TCP MSS is clamped on the VPN firewall zone - if streams still stall, test
wireguard_mtuvalues1420,1380, then1280 - rotate or choose a fallback server if only one NordVPN endpoint is affected
The NordLynx private key is stored locally by OpenWrt in /etc/config/network
under the WireGuard interface so netifd can bring the tunnel up. NordVPN Easy
does not expose that key in LuCI, logs, status JSON or diagnostics export.
- package names are fixed:
nordvpn-easyandluci-app-nordvpn-easy - LuCI reads and writes UCI config
nordvpn_easy - install/upgrade uses a template-backed config migrator to avoid opkg conffile conflicts
- the backend shell core is already wired into the package layout
- the runtime model is already
service + one-shot checks - the main missing work is validation on real OpenWrt targets and final feed integration
The project is currently a source repository for package development, not a final end-user distribution channel.
High-value validation work is:
- OpenWrt buildroot or feed validation
- LuCI rendering and action testing
- UCI-to-runtime rendering checks
- cron and hotplug behaviour on device
- recovery, rotation and country-filter validation on real routers
- One-shot health check:
/etc/init.d/nordvpn-easy check - Force server rotation:
/etc/init.d/nordvpn-easy rotate - Re-run setup logic:
/etc/init.d/nordvpn-easy setup - Reinstall cron and hotplug hooks:
/etc/init.d/nordvpn-easy install_hooks - Remove cron and hotplug hooks:
/etc/init.d/nordvpn-easy remove_hooks
- The public product name should remain
NordVPN Easy. - If you edit files on another machine, keep Unix
LFline endings. - Disabling IPv6 can help reduce leak risk in deployments that require stricter isolation, but actual leak prevention still depends on firewall, routing and failure-handling policy.
- When the tunnel is healthy, IPv4 traffic is usually routed through the VPN; verify the effective routing, firewall rules and failure modes on your target system.