11 KiB
nordvpn-client
Cross-platform NordVPN lifecycle skill for macOS and Linux.
Overview
nordvpn-client is the operator-facing VPN control skill for OpenClaw. It can:
- detect whether the host is ready for NordVPN automation
- install or bootstrap the required backend
- validate auth
- connect to a target country or city
- verify the public exit location
- disconnect and restore normal local networking state
The skill uses different backends by platform:
- Linux: official
nordvpnCLI - macOS: NordLynx/WireGuard with
wireguard-goandwireguard-tools
Commands
node skills/nordvpn-client/scripts/nordvpn-client.js status
node skills/nordvpn-client/scripts/nordvpn-client.js install
node skills/nordvpn-client/scripts/nordvpn-client.js login
node skills/nordvpn-client/scripts/nordvpn-client.js verify
node skills/nordvpn-client/scripts/nordvpn-client.js verify --country "Italy"
node skills/nordvpn-client/scripts/nordvpn-client.js verify --country "Italy" --city "Milan"
node skills/nordvpn-client/scripts/nordvpn-client.js connect --country "Italy"
node skills/nordvpn-client/scripts/nordvpn-client.js connect --city "Tokyo"
node skills/nordvpn-client/scripts/nordvpn-client.js connect --country "Japan" --city "Tokyo"
node skills/nordvpn-client/scripts/nordvpn-client.js disconnect
node skills/nordvpn-client/scripts/nordvpn-client.js status --debug
Credentials
Supported inputs:
NORDVPN_TOKENNORDVPN_TOKEN_FILENORDVPN_USERNAMENORDVPN_PASSWORDNORDVPN_PASSWORD_FILE
Default OpenClaw credential paths:
- token:
~/.openclaw/workspace/.clawdbot/credentials/nordvpn/token.txt - password:
~/.openclaw/workspace/.clawdbot/credentials/nordvpn/password.txt
Recommended setup on macOS is a token file with strict permissions:
mkdir -p ~/.openclaw/workspace/.clawdbot/credentials/nordvpn
chmod 700 ~/.openclaw/workspace/.clawdbot/credentials/nordvpn
printf '%s\n' '<your-nordvpn-token>' > ~/.openclaw/workspace/.clawdbot/credentials/nordvpn/token.txt
chmod 600 ~/.openclaw/workspace/.clawdbot/credentials/nordvpn/token.txt
Do not commit secrets into the repo or the skill docs.
Platform Backends
macOS
Current macOS backend:
- NordLynx/WireGuard
wireguard-gowireguard-tools- explicit macOS DNS management on eligible physical services:
103.86.96.100103.86.99.100
Important behavior:
NordVPN.appmay remain installed, but the automated backend does not reuse app login state.- the generated WireGuard config intentionally stays free of
DNS = ...sowg-quickdoes not rewrite every macOS network service behind the skill’s back. - during
connect, the skill first proves the tunnel is stable with a bounded persistence gate that reuses the allowed helperprobeaction and a verified public exit. - during
connect, the skill snapshots current DNS/search-domain settings on eligible physical services and then applies NordVPN DNS only after that stable gate, one last liveness check, and a post-DNS system-hostname-resolution check succeed. - during
disconnect, or after a failed/stale teardown, the skill restores the saved DNS/search-domain snapshot. - if persistence, exit verification, or post-DNS hostname resolution fails, the skill rolls back before treating the connect as successful and resumes Tailscale if it stopped it.
- when the skill intentionally stops Tailscale for a VPN session, it writes a short-lived suppression marker so host watchdogs do not immediately run
tailscale upand fight the VPN route change. - The skill automatically suspends Tailscale before connect if Tailscale is active.
- The skill resumes Tailscale after disconnect, or after a failed connect, if it stopped it.
- The Homebrew NordVPN app does not need to be uninstalled.
Linux
Current Linux backend:
- official
nordvpnCLI - official NordVPN installer
- token login through
nordvpn login --token ...
Install / Bootstrap
macOS
Bootstrap the automation backend:
node skills/nordvpn-client/scripts/nordvpn-client.js install
Equivalent Homebrew command:
brew install wireguard-go wireguard-tools
What install does on macOS:
- checks whether
wireguard-gois present - checks whether
wgandwg-quickare present - installs missing packages through Homebrew
Linux
node skills/nordvpn-client/scripts/nordvpn-client.js install
What install does on Linux:
- downloads NordVPN’s official installer script
- runs it
- leaves subsequent login/connect to the official
nordvpnCLI
macOS sudoers Setup
Automated macOS connect/disconnect requires passwordless sudo for the helper script that invokes wg-quick.
Installed OpenClaw helper path:
/Users/stefano/.openclaw/workspace/skills/nordvpn-client/scripts/nordvpn-wireguard-helper.sh
Edit sudoers safely:
sudo visudo
Add this exact rule:
stefano ALL=(root) NOPASSWD: /Users/stefano/.openclaw/workspace/skills/nordvpn-client/scripts/nordvpn-wireguard-helper.sh probe, /Users/stefano/.openclaw/workspace/skills/nordvpn-client/scripts/nordvpn-wireguard-helper.sh up, /Users/stefano/.openclaw/workspace/skills/nordvpn-client/scripts/nordvpn-wireguard-helper.sh down
Do not add extra helper actions just for persistence checks unless you are also updating host sudoers. The current implementation intentionally rides the persistence check on probe so the existing probe/up/down rule remains sufficient.
If you run the repo copy directly instead of the installed OpenClaw skill, adjust the helper path accordingly.
Common Flows
Status
node skills/nordvpn-client/scripts/nordvpn-client.js status
Use this first to answer:
- is the correct backend available?
- is the token visible?
- is
sudoReadytrue? - is the machine currently connected?
Login
node skills/nordvpn-client/scripts/nordvpn-client.js login
On macOS this validates the token and populates the local auth cache. It does not connect the VPN.
Connect
Country:
node skills/nordvpn-client/scripts/nordvpn-client.js connect --country "Germany"
City:
node skills/nordvpn-client/scripts/nordvpn-client.js connect --country "Japan" --city "Tokyo"
Expected macOS behavior:
- stop Tailscale if active
- select a NordVPN server for the target
- bring up the WireGuard tunnel
- prove persistence of the live
utun*runtime via the helperprobepath - verify the public exit location
- run one final liveness check before applying NordVPN DNS
- return JSON describing the chosen server and final verified location
Verify
node skills/nordvpn-client/scripts/nordvpn-client.js verify --country "Germany"
Use this after connect if you want an explicit location check without changing VPN state.
Disconnect
node skills/nordvpn-client/scripts/nordvpn-client.js disconnect
Expected macOS behavior:
- attempt
wg-quick downwhenever there is active or residual NordVPN WireGuard state - remove stale local NordVPN state files after teardown
- restore automatic DNS when the saved DNS snapshot is obviously just NordVPN-pinned leftovers
- resume Tailscale if the skill had suspended it
Output Model
Normal JSON is redacted by default.
Redacted fields in normal mode:
cliPathappPathwireguard.configPathwireguard.helperPathwireguard.authCache.tokenSource
Operational fields preserved in normal mode:
connectedwireguard.activewireguard.endpointrequestedTargetverification- public IP and location
For deeper troubleshooting, use:
node skills/nordvpn-client/scripts/nordvpn-client.js status --debug
--debug keeps the internal local paths, helper-hardening diagnostics, and other low-level metadata in the JSON output.
If you also run local watchdogs such as healthwatch.sh, they should honor the NordVPN Tailscale suppression marker at ~/.nordvpn-client/tailscale-suppressed and skip automatic tailscale up while the marker is fresh or the NordVPN WireGuard tunnel is active.
Troubleshooting
Invalid authorization header
Meaning:
- the token file was found
- the token value is not valid for NordVPN’s API
Actions:
- generate a fresh NordVPN access token
- replace the contents of
~/.openclaw/workspace/.clawdbot/credentials/nordvpn/token.txt - run:
node skills/nordvpn-client/scripts/nordvpn-client.js login
sudoReady: false
Meaning:
- the helper script is present
- the agent cannot run
wg-quicknon-interactively
Actions:
- add the
visudorule shown above - rerun:
node skills/nordvpn-client/scripts/nordvpn-client.js status
Expected:
wireguard.sudoReady: true
WireGuard tools missing
Meaning:
- macOS backend is selected
wireguard-go,wg, orwg-quickis missing
Actions:
node skills/nordvpn-client/scripts/nordvpn-client.js install
or:
brew install wireguard-go wireguard-tools
Tailscale interaction
Expected behavior on macOS:
- Tailscale is suspended before the NordVPN connect
- Tailscale is resumed after disconnect or failed connect
If a connect succeeds but later traffic is wrong, check:
node skills/nordvpn-client/scripts/nordvpn-client.js status
/opt/homebrew/bin/tailscale status --json
Look for:
connected: trueand a foreign exit IP while NordVPN is upconnected: falseand Texas/Garland IP after disconnect
Status says disconnected after a verified connect
This was a previous macOS false-negative path and is now normalized in the connect response.
Current expectation:
- if
connectverifies the target location successfully - the returned
statesnapshot should also show:connected: truewireguard.active: true
If that regresses, capture:
connectJSONverifyJSONstatus --debugJSON
Disconnect says “no active connection” but traffic is still foreign
The current macOS disconnect path now treats residual WireGuard state as sufficient reason to attempt teardown.
Safe operator check:
node skills/nordvpn-client/scripts/nordvpn-client.js disconnect
node skills/nordvpn-client/scripts/nordvpn-client.js verify
Expected after a good disconnect:
- Texas/Garland public IP again
wireguard.configPath: nullin normal status outputwireguard.lastConnection: null
If that regresses, capture:
disconnectJSONverifyJSONstatus --debugJSON
Recommended Agent Workflow
For VPN-routed work:
statusinstallif backend tooling is missingloginif token validation has not happened yetconnect --country ...orconnect --country ... --city ...verify- run the follow-up skill such as
web-automation disconnectverifyagain if you need proof the machine returned to the normal exit path