372 lines
8.8 KiB
Markdown
372 lines
8.8 KiB
Markdown
# 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
|
||
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
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`
|
||
- NordVPN DNS in the generated WireGuard config:
|
||
- `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 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:
|
||
|
||
```bash
|
||
node skills/nordvpn-client/scripts/nordvpn-client.js install
|
||
```
|
||
|
||
Equivalent Homebrew command:
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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 `nordvpn` CLI
|
||
|
||
## macOS sudoers Setup
|
||
|
||
Automated macOS connect/disconnect requires passwordless `sudo` for the helper script that invokes `wg-quick`.
|
||
|
||
Installed OpenClaw helper path:
|
||
|
||
```text
|
||
/Users/stefano/.openclaw/workspace/skills/nordvpn-client/scripts/nordvpn-wireguard-helper.sh
|
||
```
|
||
|
||
Edit sudoers safely:
|
||
|
||
```bash
|
||
sudo visudo
|
||
```
|
||
|
||
Add this exact rule:
|
||
|
||
```sudoers
|
||
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
|
||
```
|
||
|
||
If you run the repo copy directly instead of the installed OpenClaw skill, adjust the helper path accordingly.
|
||
|
||
## Common Flows
|
||
|
||
### Status
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
node skills/nordvpn-client/scripts/nordvpn-client.js connect --country "Germany"
|
||
```
|
||
|
||
City:
|
||
|
||
```bash
|
||
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
|
||
- verify the public exit location
|
||
- return JSON describing the chosen server and final verified location
|
||
|
||
### Verify
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
- 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:
|
||
|
||
```bash
|
||
node skills/nordvpn-client/scripts/nordvpn-client.js status --debug
|
||
```
|
||
|
||
`--debug` keeps the internal local paths and other low-level metadata in the JSON output.
|
||
|
||
## Troubleshooting
|
||
|
||
### `Invalid authorization header`
|
||
|
||
Meaning:
|
||
|
||
- the token file was found
|
||
- the token value is not valid for NordVPN’s API
|
||
|
||
Actions:
|
||
|
||
1. generate a fresh NordVPN access token
|
||
2. replace the contents of `~/.openclaw/workspace/.clawdbot/credentials/nordvpn/token.txt`
|
||
3. run:
|
||
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
node skills/nordvpn-client/scripts/nordvpn-client.js install
|
||
```
|
||
|
||
or:
|
||
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
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
|
||
|
||
## Recommended Agent Workflow
|
||
|
||
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
|