vike
Set up

vike-cli backend

Mint a vike-tradehub node's authentication keys on the daemon's own box with `backend setup`, then attach a client machine to a running node with `backend connect`, `status`, and `disconnect`.

vike-cli backend stands a vike-tradehub node's authentication up on the machine running it, and attaches a separate client machine to a node that is already running. It has two halves, and each runs on a different box — getting that right is the one thing to know before typing anything else:

  • backend setup runs on the daemon's box — the machine actually running vike-tradehub. It mints two keys, writes them into that box's own store, and never prints a key value.
  • backend connect, backend status, and backend disconnect run on the client's box — a laptop, a container, anywhere that wants to reach the daemon. They raise or close an SSH tunnel, take the two keys setup minted, and prove the connection with a real round trip against the node.

"Node" means the running vike-tradehub daemon: one process holding the live core, its venue mounts, and its authenticated socket. It is not Node.js and it is not rented compute — the word survives in the protocol (--node, the node.env file) even though the verb itself was renamed from vike-cli node to vike-cli backend, because "node" read as something else to people arriving from outside this codebase.

No subcommand here can print, log, or journal a key value, on any path. What reaches the screen instead is each key's key_id — a derived, non-reversible fingerprint (crates/vike-cli/src/cmd/node/mod.rs's key_id) that is safe to paste anywhere. Comparing the two ids setup printed on the daemon's box against the two connect or status print on the client's box is this design's whole answer to "did I just attach to the right node."

Usage

vike-cli backend setup       [--addr HOST:PORT] [--control] [--rotate]
vike-cli backend connect HOST [--port N] [--manual] [--no-tunnel] [--replace]
vike-cli backend status
vike-cli backend disconnect  [--port N]

A flag scoped to the other box is refused by name rather than silently dropped — --control on connect, or --manual on status, fails immediately and says which box the flag belongs on (crates/vike-cli/src/cmd/node/mod.rs's check_flag_scope). That matters most for --control: silently accepted on the wrong box, it would leave an operator believing the daemon's write channel was armed when nothing armed it.

setup — on the daemon's box

Mints both node keys from the OS CSPRNG (32 bytes each, hex-encoded), writes them into this box's store, sets the bind address, and prints each key's id plus a restart line. Run it once, on the machine actually running vike-tradehub:

vike-cli backend setup

Nothing here accepts a key, on any path

setup mints both keys itself — there is no argv form, no stdin form, and no --from-env form to refuse, because there is no operator-supplied value to accept. The one path on which a human ever touches key material is connect --manual, and only there.

The default bind address is 127.0.0.1:7879. To bind somewhere else and arm the write channel in one step:

vike-cli backend setup --control --addr 0.0.0.0:9100

--control is never the default and never inferred

flags.tradehub_control is written only when --control is passed. A box with fresh keys and no --control mints the control key but never writes flags.tradehub_control, so nothing on the daemon side has been told to trust it — run setup --control once you mean to arm the write channel (crates/vike-cli/src/cmd/node/setup.rs's CONTROL_FLAG_KEY).

Running setup again on a box that already has keys refuses rather than reissuing them:

$ vike-cli backend setup
OBSERVE_KEY and CONTROL_KEY already in .../settings/node.env, and `setup` will not silently
replace a key some client is signing with.
⚠ Re-run with --rotate to replace BOTH keys. Every client already holding the old ones — a
laptop's vike-cli, a vike-app --observe, a thin container — stops working the moment the daemon
restarts, and its symptom is an auth denial that reads like a revoked credential.
Nothing was written.

Pass --rotate once you mean it:

vike-cli backend setup --rotate

A rotation detaches every other client

--rotate replaces both keys and preserves every other line already in the store (crates/vike-cli/tests/node_cli.rs's rotate_replaces_both_keys_and_preserves_the_rest_of_the_store), but every client still holding the old pair fails its next handshake with an auth denial that reads like a revoked credential rather than like a rotation. Re-run backend connect on each of them afterward.

Every successful setup — first run or rotation — ends the same way, because the daemon reads both keys once at start and never re-reads them (crates/vike-cli/src/cmd/node/setup.rs's report):

sudo systemctl restart vike-tradehub          # a systemd deployment
docker restart vike-tradehub                  # the container

connect HOST — on the client's box

Raises an SSH tunnel to HOST (-N -f under the hood, so a taken port or an unreachable host fails synchronously rather than sitting there forwarding nothing), optionally takes the two keys, records the dial address, and finishes with a live round trip against the node.

On a first attachment, pipe both keys in:

printf '%s\n%s\n' "$OBSERVE" "$CONTROL" | vike-cli backend connect my-node --manual

Keys never go on the command line

--manual reads two lines from stdin — observe, then control — and is the only way a key value reaches this command. A second positional after HOST is refused (crates/vike-cli/tests/node_cli.rs's a_key_never_goes_on_the_command_line): argv lands in shell history and in ps output for every other user on the box. A blank second line means observe-only — a client that can watch the node and place nothing.

Without --manual, connect writes nothing to the store: it raises the tunnel, records the dial address, and verifies with whatever keys this box already resolves (the process environment first, then the store). That is the ordinary second and later run:

vike-cli backend connect my-node

A client already inside the trust boundary can skip the tunnel and dial the daemon directly:

vike-cli backend connect my-node --no-tunnel

A successful run ends with the round trip (crates/vike-cli/src/cmd/node/connect.rs's verify):

verified: node my-node — LIVE — build 0.1.24
  reached at 127.0.0.1:7879, 3 mount(s)
  observe key id 4f2a…
⚠ compare those ids with the ones `vike-cli backend setup` printed on the daemon's box. They
match, or you are talking to a different node.

A local key that disagrees with the incoming one is a refusal, not a silent switch

If this box already holds a different value for a key name than the one --manual was just given, connect refuses and prints both key ids rather than detaching whatever the old key reached (crates/vike-cli/src/cmd/node/connect.rs's replace_refusal). Pass --replace once you mean to point this client at a different node.

status — on the client's box

Reports the dial address, which keys resolved and from where, and whether the node answers right now — it prints the configuration half even when the round trip fails, so a bad address or a missing key is diagnosable from the same command that would otherwise just hang:

vike-cli backend status
dial address: 127.0.0.1:7879   (config.node_addr)
OBSERVE_KEY                4f2a…   read plane, from the store
CONTROL_KEY                9b1c…   write plane, from the process environment
⚠ a write key resolved here; whether the NODE admits orders is flags.tradehub_control on the
daemon's box, which this side cannot read.

On a box that has never attached, it names exactly what is missing rather than printing an empty table or dialling nothing (crates/vike-cli/tests/node_cli.rs's status_on_an_unattached_box_names_what_is_missing):

$ vike-cli backend status
dial address: NONE — config.node_addr is unset, so every node verb still needs --node
OBSERVE_KEY                absent          read plane
CONTROL_KEY                absent          write plane
vike-cli backend: no config.node_addr on this box, so there is no node to ask. `vike-cli backend
connect <host>` records one; `--node HOST:PORT` still names one per command.

disconnect — on the client's box

Closes the tunnel connect raised:

vike-cli backend disconnect

It matches the recorded forward spec, not a process id — ssh -f has already forked and exited by the time connect returns, so there is no child handle to hold onto (crates/vike-cli/src/cmd/node/connect.rs's run_disconnect). Running it with no recorded tunnel succeeds and says so, rather than failing on a state you already have:

no tunnel recorded by `vike-cli backend connect` on this box — nothing to close. (A tunnel
raised by hand is not recorded here; close it where you raised it.)

--port N closes a forward on that port even when nothing was recorded for it (it still checks the recorded port first, then falls back to a plain -L N:localhost:N match with no host filter):

vike-cli backend disconnect --port 9200

disconnect is not automated on Windows

pkill -f has no equivalent this workspace can reach without a Win32 call its lint policy forbids, so on Windows disconnect refuses and prints the exact command to run by hand instead:

Get-CimInstance Win32_Process -Filter "Name='ssh.exe'" |
  Where-Object CommandLine -like '*7879:localhost:7879*' |
  ForEach-Object { Stop-Process -Id $_.ProcessId }

Flags

FlagSubcommandMeaning
--addr HOST:PORTsetupAddress the daemon binds (default 127.0.0.1:7879)
--controlsetupAlso set flags.tradehub_control = true, admitting order commands from a peer holding the control key
--rotatesetupReplace keys already in the store
--port Nconnect, disconnectNode port to forward, dial, or close (default 7879)
--manualconnectRead both keys from stdin, one per line: observe, then control
--no-tunnelconnectThis client is already inside the trust boundary — dial HOST directly, raise no forward
--replaceconnectOverwrite a local key that differs from the incoming one
-h, --helpallPrint usage

The store

setup and connect --manual write into <project>/settings/node.env — the two node key names, kept apart from the much larger venue credential store so a reader of one need not open the other. Neither verb creates that file: an absent store is refused, naming the command that makes one (crates/vike-cli/src/cmd/node/mod.rs's open_store):

install -m600 /dev/null <project>/settings/node.env

If this box already has node keys under the old, shared credential file, they are still read from there — the refusal above is only about where the next write lands, not about losing keys that already exist.

$VIKE_SETTINGS_DIR names the settings directory outright, for a run against a project other than the one the working directory sits under.

  • secrets — the venue credential store backend's writes are kept apart from. Its own missing-store refusal points at install -m600 /dev/null <path>, never at secrets path or secrets template — those read a different file shaped for a different roster.
  • mcp — advertises no tool that can reach either of backend's credential writers

On this page