Node retarget
php artisan orbit:node-retarget NAME HOST [--ssh-port=PORT] changes the public SSH target of an active Node. It runs on the Gateway machine. The Node keeps its pinned host key, its WireGuard address, and every other identity field.
One lifecycle owner per Node name
node:add, node:remove, node:rename, and retarget each take one lock for the Node name. They hold it from the lookup to the last remote step and rollback. Another operation on the same name fails with node.provisioning_busy (HTTP 409) before it changes anything. A retry reads the Node again after it gets the lock. Operations on different names run at the same time. The lock does not block role or settings changes. A lock that nobody releases expires after one hour.
Two paths
Retarget picks its path from the Node’s role assignments. Any assignment counts, also aprovisioning or failed one, because a failed convergence can already have closed public SSH. When the first role is assigned, the Gateway moves the Node from operator DNS to managed DNS and removes its public SSH recovery rule; roleless retarget uses public SSH to converge the WireGuard peer before switching to the tunnel. Public SSH describes that boundary.
On the public SSH path, the Gateway scans the host key at the new address and requires the pinned fingerprint. It publishes the WireGuard peer over public SSH, using operator DNS mode for a Node with no role, probes SSH over WireGuard, and pins the key for both addresses.
On the WireGuard path, the Gateway scans the host key over the WireGuard address and requires the pinned fingerprint. It stores the new target, probes SSH over WireGuard, and pins the key for the new address.
The WireGuard path never opens a public SSH connection and never rewrites the Node’s WireGuard configuration, because a restart of
wg-quick@orbit would cut the session that drives it.
Repair a tunnel that is down
The Node starts its tunnel toward theEndpoint in /etc/wireguard/orbit.conf. When the Gateway’s public address changes, for example in a cloned topology on a new subnet, that endpoint is stale and the tunnel stays down. Retarget then fails with node.retarget_requires_vpn, and the Node record stays active and unchanged.
Repair the endpoint on the Node as root, then retry:
apps/e2e/resources/guest/retarget-vpn.sh.