Files
stef-openclaw-skills/docs/nordvpn-client.md

11 KiB
Raw Permalink Blame History

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 nordvpn CLI
  • macOS: NordLynx/WireGuard with wireguard-go and wireguard-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_TOKEN
  • NORDVPN_TOKEN_FILE
  • NORDVPN_USERNAME
  • NORDVPN_PASSWORD
  • NORDVPN_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-go
  • wireguard-tools
  • explicit macOS DNS management on eligible physical services:
    • 103.86.96.100
    • 103.86.99.100

Important behavior:

  • NordVPN.app may remain installed, but the automated backend does not reuse app login state.
  • the generated WireGuard config intentionally stays free of DNS = ... so wg-quick does not rewrite every macOS network service behind the skills back.
  • during connect, the skill first proves the tunnel is stable with a bounded persistence gate that reuses the allowed helper probe action 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 up and 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 nordvpn CLI
  • 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-go is present
  • checks whether wg and wg-quick are present
  • installs missing packages through Homebrew

Linux

node skills/nordvpn-client/scripts/nordvpn-client.js install

What install does on Linux:

  • downloads NordVPNs official installer script
  • runs it
  • leaves subsequent login/connect to the official nordvpn CLI

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 sudoReady true?
  • 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 helper probe path
  • 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 down whenever 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:

  • cliPath
  • appPath
  • wireguard.configPath
  • wireguard.helperPath
  • wireguard.authCache.tokenSource

Operational fields preserved in normal mode:

  • connected
  • wireguard.active
  • wireguard.endpoint
  • requestedTarget
  • verification
  • 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 NordVPNs API

Actions:

  1. generate a fresh NordVPN access token
  2. replace the contents of ~/.openclaw/workspace/.clawdbot/credentials/nordvpn/token.txt
  3. run:
node skills/nordvpn-client/scripts/nordvpn-client.js login

sudoReady: false

Meaning:

  • the helper script is present
  • the agent cannot run wg-quick non-interactively

Actions:

  1. add the visudo rule shown above
  2. 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, or wg-quick is 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: true and a foreign exit IP while NordVPN is up
  • connected: false and 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 connect verifies the target location successfully
  • the returned state snapshot should also show:
    • connected: true
    • wireguard.active: true

If that regresses, capture:

  • connect JSON
  • verify JSON
  • status --debug JSON

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: null in normal status output
  • wireguard.lastConnection: null

If that regresses, capture:

  • disconnect JSON
  • verify JSON
  • status --debug JSON

For VPN-routed work:

  1. status
  2. install if backend tooling is missing
  3. login if token validation has not happened yet
  4. connect --country ... or connect --country ... --city ...
  5. verify
  6. run the follow-up skill such as web-automation
  7. disconnect
  8. verify again if you need proof the machine returned to the normal exit path