VPN client manager for AsusWRT-Merlin routers. Manages up to five OpenVPN clients — server selection, scheduled refresh, OVPN config application, and a router WebUI tab.
Asuswrt-Merlin 384.15 / 384.13_4 or Fork 43E5 or later — asuswrt-merlin.ng
From an SSH session on the router:
/usr/sbin/curl --retry 3 "https://raw.githubusercontent.com/h0me5k1n/vpnmgr/main/vpnmgr.sh" -o "/jffs/scripts/vpnmgr" && chmod 0755 /jffs/scripts/vpnmgr && /jffs/scripts/vpnmgr installvpnmgr adds a tab to the VPN section in the router WebUI.
To launch the interactive CLI menu over SSH:
vpnmgrIf that doesn't work (script not yet on $PATH):
/jffs/scripts/vpnmgr| Provider | Status |
|---|---|
| NordVPN | Active — maintained and tested |
| Private Internet Access (PIA) | Untested — rewritten to use PIA JSON API; needs verification on a live account |
| WeVPN | Deprecated — WeVPN is no longer operational |
vpnmgr/
├── vpnmgr.sh # Core script — CLI, scheduler, VPN client control, self-update
├── vpnmgr_www.asp # WebUI page (AsusWRT-Merlin Addons API)
├── vpnmgr_www.js # WebUI logic
├── vpnmgr_www.css # WebUI styles
├── www/ # Bundled web assets (served from /ext/vpnmgr/www/)
│ ├── jquery.js # jQuery v3.5.1
│ └── detect.js # LAN detection helper
├── providers/ # Provider sub-scripts
│ ├── provider_nordvpn.sh # NordVPN — active
│ ├── provider_pia.sh # PIA — unmaintained
│ ├── provider_wevpn.sh # WeVPN — deprecated
│ └── provider_template.sh # Template for new providers
├── scripts/
│ ├── smoke-test.sh # Local CI smoke test
│ └── provider-test.sh # Live API test harness for provider modules
└── .github/workflows/ci.yml # GitHub Actions — runs smoke-test on every PR
Replace <branch> with the branch name:
/usr/sbin/curl --retry 3 "https://raw.githubusercontent.com/h0me5k1n/vpnmgr/<branch>/vpnmgr.sh" -o "/jffs/scripts/vpnmgr" && chmod 0755 /jffs/scripts/vpnmgr && /jffs/scripts/vpnmgr installTo switch a running installation between the stable release and the develop branch:
vpnmgr switch stable # pins to main
vpnmgr switch develop # pins to develop branchBefore deploying to a router, verify a provider's API integration works from your local machine (requires curl and jq):
bash scripts/provider-test.sh nordvpnThis exercises the live NordVPN API — country/city lookups, server recommendations, OVPN config download, and cert extraction — without touching any router state. write_certs is validated as a dry run: the CA and tls-auth blocks are extracted from the downloaded OVPN and verified, but nothing is written to the filesystem.
Providers marked DEPRECATED in their # Status: header skip network tests automatically.
Copy providers/provider_template.sh to providers/provider_<name>.sh and implement all 17 required functions. The contract is documented in the template header.
Run bash scripts/smoke-test.sh locally before opening a PR — CI enforces this on every push.
All .sh files must be busybox ash compatible. No bash arrays, no [[ ]], no let, no declare, no process substitution. The router does not have bash.
As of v3.1.0, vpnmgr no longer overrides the OpenVPN ping/ping-restart
keepalive directives for any provider. Earlier versions hardcoded ping 15
/ ping-restart 60 and explicitly discarded whatever the VPN server itself
pushed (pull-filter ignore "ping" / pull-filter ignore "ping-restart").
Since pushing tuned keepalive values via PUSH_REPLY is standard practice
for commercial VPN providers (NordVPN's own published Asuswrt-Merlin setup
guide, for example, sets only ping-timer-rem and relies on its servers'
pushed values), the old override could turn brief, harmless network jitter
into a full reconnect far more often than necessary — for some users this
showed up as frequent Inactivity timeout (--ping-restart), restarting
lines flooding the syslog. ping-timer-rem is still set, so the
ping-restart countdown still resets on any received packet.
If you're upgrading from an earlier version: this is a behaviour change for every managed VPN client — the actual keepalive timeout now comes from your provider instead of a fixed 60 seconds. If your provider (or its specific server) pushes an unusually short or missing keepalive and you see different reconnect behaviour after upgrading, please open an issue.
Two new per-client settings (menu option 8, or WebUI equivalent) control
log volume and detail instead:
| Setting | Default | Effect |
|---|---|---|
mute |
20 |
Emits OpenVPN's mute <N> directive, collapsing N consecutive identical log lines into a single summary line. Set to 0 to disable. |
debugverb |
false |
When enabled, adds verb 4 for detailed OpenVPN diagnostic logging. Leave off unless actively debugging a connection issue, since it increases log volume. |
-
NordVPN OVPN format: vpnmgr downloads OVPN files from NordVPN's CDN, which still serves the v1 format (tls-auth, multiple
remotelines). NordVPN's newer v2.6 format (tls-crypt, singleremote) is only available via manual download from the NordVPN portal — no programmatic per-server URL is known. The v1 CDN files work correctly; upgrading to v2.6 would require NordVPN to expose an API endpoint for per-server downloads. -
Migrating from jackyaz's version: if you currently have jackyaz/vpnmgr installed, you must uninstall it first before installing this version. Run
vpnmgr uninstallusing the old script, then follow the installation instructions above. The install command will detect an existing installation and refuse to proceed if one is found.
- Phase 1 — Fork merge: jackyaz's v2.3.2 merged as the new baseline; WeVPN ZIP files removed
- Phase 2 — Modular providers: all provider logic extracted to
providers/; CI smoke test added - Phase 3 — Branding sweep: URLs, integrity check, and banner updated to h0me5k1n
- Phase 4 — Web assets:
jquery.jsanddetect.jsbundled inwww/;jackyaz/shared-jydependency removed - Phase 5 — WebUI modernisation: dynamic provider loading from
providers.htm; ES5-clean JS; inline script blob replaced with externalvpnmgr_www.js - Phase 6 — Documentation: provider authoring guide, contributing guide, CLI/WebUI screenshots
- Phase 7 — Migration: automated detection of jackyaz's install with guided uninstall prompt
-
h0me5k1n/vpnmgr — the original project, NordVPN-only CLI.
-
jackyaz/vpnmgr — @jackyaz forked and massively expanded it across 429 commits: full WebUI, multi-provider support, scheduled refresh, self-update. Now archived. His work is the backbone of this codebase and is preserved in full in the commit history.
-
This repo — jackyaz's fork merged back as the new baseline, revived and maintained by h0me5k1n.
- @jackyaz — author of the expanded vpnmgr. His 429 commits are the foundation of this codebase.
- @h0me5k1n — original concept and current maintainer.
GPL-3.0 — see LICENSE.
Love the script and want to support future development? Any and all donations gratefully received!
PayPal donation |
|---|
Open an issue on this repo, or post in the Asuswrt-Merlin AddOns forum on SNBForums.
