Skip to content

VPN client (WireGuard)

Looking for the organization's gateways?

Site-to-site gateways, peers and exposures are managed with bnerd vpn gateways.

Connect this machine to your organization's WireGuard VPN. The CLI enrols the machine as a device, and b'nerd issues the tunnel configuration for it — you no longer paste a public key to an administrator or hand-maintain a vpn: block.

This page is the command reference: flags, defaults and exit codes. For what the concepts mean — which services a device may reach, who decides that, and why an enrolment is refused — see the VPN service documentation.

Your private key never leaves this machine

bnerd vpn up generates the key pair locally and writes the private half to <config-dir>/<device>.key with mode 0600. Only the public key is sent to b'nerd. The CLI never prints, logs or transmits the private key, and it deletes that file only when you pass --regenerate-keys.

Connect

bnerd vpn up

On the first run this enrols the machine against the organization's ready WireGuard gateway, fetches the tunnel configuration, writes <config-dir>/<interface>.conf and brings the interface up. Afterwards the existing enrolment is reused, so running it again is cheap and idempotent.

Requires root/sudo

Bringing the interface up needs elevated privileges. Enrolment itself does not.

Flags

Flag Type Default Description
--device string this machine's hostname Device name. A name you pass must already be a valid DNS-1123 label; the hostname default is sanitised into one.
--gateway string the single ready gateway Gateway ID to enrol against. Required when the organization has more than one ready WireGuard gateway.
--interface string bnerd0 WireGuard interface name
--regenerate-keys bool false Discard the local private key, generate a new pair and enrol a new device

Choosing a gateway

bnerd vpn up discovers gateways through the member-readable enrollable-gateway list, so a plain org member needs no gateway rights. A static access token needs the vpn_devices:write scope (it includes read; scopes nest read < write < manage < *) — not vpn_gateways:* — and it must be an org-wide token: gateways and devices are organization-level, so a token pinned to one project is refused. A token without the scope fails with:

Error: Access token does not have permission for this action — this token lacks the `vpn_devices:write` scope; create an org-wide token with that scope (or a wider level: read < write < manage < *)

If several gateways are ready, the CLI refuses to guess and names the candidates:

Error: this organization has several ready WireGuard VPN gateways — pass --gateway
with one of: gw-1 (hq-wg, ready), gw-2 (lab-wg, ready)

When enrolment is refused

Condition Exit What it means What to do
gateway still provisioning 4 The gateway has not reported its key, address and service CIDR yet Wait a few minutes and run again
device limit reached 5 The gateway is at its device limit (50 per gateway by default, at most 60) Revoke a device you no longer use, or ask b'nerd to raise the limit
no free address 5 The gateway's road-warrior address range is full Revoke a device you no longer use, or contact b'nerd
service CIDR unsupported 5 The gateway's CIDR cannot host road-warrior devices Contact b'nerd to set a road-warrior range
device revoked 1 Someone revoked this enrolment Run bnerd vpn up again to re-enrol; your local key is kept

See Exit codes for the full mapping.

Disconnect

bnerd vpn down

Purely local — the device stays enrolled, so bnerd vpn up reconnects without touching the API. To withdraw a device's access for good, revoke it.

Check status

bnerd vpn status
bnerd vpn status -w      # refresh every 2 seconds

bnerd vpn down and bnerd vpn status both accept --interface.

Devices

bnerd vpn devices list [--all]
bnerd vpn devices revoke <device-id>

list shows your own devices: id, name, gateway, tunnel address, health, traffic counters and whether the device is active or revoked. --all is an org-admin view of every device in the organization and adds the owner's email; a plain member asking for it gets a clear refusal rather than a silently narrowed list.

Health and counters are not live

health, last_handshake and the byte counters in devices list are what b'nerd last read from the gateway, and b'nerd reads it when it reconciles the gateway (for example after an enrolment or a revoke) — not continuously. A device can show unknown or an old handshake while its tunnel is fine. For the live state of this machine's tunnel use bnerd vpn status (it reads the local interface).

revoke cuts the device off at the gateway and keeps the record, so who had access and when it was withdrawn stays visible. It is idempotent, and it does not touch the private key on the device itself — that machine can enrol again with bnerd vpn up.

There is no devices enrol command on purpose: a device is enrolled by the machine that owns it, because the private key is generated there.

Exit codes

Every VPN command uses the CLI-wide mapping, so a script can branch on the outcome without parsing messages.

Code Meaning When you will see it here
0 Success
1 Failed, read the message The device was revoked (410). Re-run the same command to re-enrol. Also any local failure: an unreadable key file, an unusable interface name.
2 Not found A device id that does not exist, or one you may not read
3 Not permitted devices list --all as a plain member
4 Conflict, retry later The gateway is still provisioning — on enrolment and on fetching the configuration alike
5 Refused The gateway's device limit is reached, its address range is full, or its service CIDR cannot host devices
6 Server error

Code 4 is the one worth branching on: it is transient and the identical command will succeed once the gateway finishes reconciling. Code 5 will not resolve on its own — someone has to revoke a device or change the gateway.

Revocation is deliberately not a code of its own. The remedy is to run the same command again, which the message already tells you, so it falls into the generic 1.

Configuration

Key Default Description
vpn.config-dir ~/.config/bnerd/wireguard Where key files and generated .conf files live
vpn.interface bnerd0 Default interface name
vpn.cleanup-config false Remove the generated .conf on vpn down

One tunnel per interface, one key per device

The two files are keyed differently, on purpose:

  • the private key is <config-dir>/<device>.key — it is the device's identity, so each device keeps its own;
  • the tunnel config is <config-dir>/<interface>.conf — it describes one live interface, and only one device can occupy an interface at a time.

So running bnerd vpn up for a second device on the same interface replaces that .conf while leaving both key files intact. Give the second device its own --interface if you want both tunnels at once.

Enrolments outlive the config file

Replacing the .conf does not un-enrol anything. Both devices stay enrolled at b'nerd and both keep counting against the gateway's device limit until you bnerd vpn devices revoke them.

Examples

# Connect this laptop (enrols on first run)
sudo bnerd vpn up

# Pin the device name and the gateway
sudo bnerd vpn up --device bernd-laptop --gateway gw-1

# Second tunnel on its own interface
sudo bnerd vpn up --device bernd-lab --interface bnerd1

# See what is enrolled, then retire an old phone
bnerd vpn devices list
bnerd vpn devices revoke dev-7f3a

# Start over from a fresh key pair
sudo bnerd vpn up --regenerate-keys

Deprecated: bnerd up / bnerd down / bnerd status

The top-level bnerd up, bnerd down and bnerd status are aliases of bnerd vpn up, bnerd vpn down and bnerd vpn status: same flags, same behaviour, same stdout. They print a one-line deprecation notice on stderr and will be removed in a future release. Use the bnerd vpn forms in new scripts.

Legacy Replacement
bnerd up [--device] [--gateway] [--interface] [--regenerate-keys] bnerd vpn up (same flags)
bnerd down [--interface], bnerd up --down bnerd vpn down
bnerd status [--interface] [-w], bnerd up --status bnerd vpn status
bnerd up --generate-keys not needed: bnerd vpn up generates the device key on first run; --regenerate-keys replaces it
bnerd up --show-peer-info not needed: the public key is enrolled automatically; bnerd vpn devices list shows the device

The two removed flags fail with an error that names the replacement. The static vpn: keys the old client read (server-endpoint, server-public-key, private-key, public-key, client-address, allowed-ips, dns) are ignored; the aliases read only the three keys bnerd vpn up reads.

See also

  • VPN service documentation — the concepts behind these commands: the gateway's device_authorization default and the narrow-only per-device override that decides what a device may reach, the per-gateway device limits, and what each enrolment refusal means for the product.
  • bnerd vpn gateways — the org-admin side: gateways, peers and exposures.

Guides