# Saved servers (/docs/v0.4/remote/servers)



A **saved server** is one record on the machine you sit at: a name, an address,
a secret, and the fingerprint of the certificate that machine presented. The
store is readable only by its owner, and `koshi remote list` never prints a
secret.

| Command                                    | Result                                                 |
| ------------------------------------------ | ------------------------------------------------------ |
| `koshi remote new`                         | Save a server, asking for its name, address and secret |
| `koshi remote edit <SERVER>`               | Change one saved server's name, address or secret      |
| `koshi remote list [--format table\|json]` | List the servers this machine has saved                |
| `koshi remote forget <SERVER>`             | Drop one saved server                                  |
| `koshi remote set-secret <SERVER>`         | Replace the secret of one saved server                 |

## Naming a server [#naming-a-server]

`--remote` takes either the `host:port` a machine listens on or the name it was
saved under. The first connection names the address, and `--save-as` gives it a
short name:

```bash
koshi attach --remote laptop.local:7654 --save-as work web
```

After that the name stands in, and nothing is retyped:

```bash
koshi attach --remote work web
```

`koshi remote new` saves a server without attaching to one of its sessions. It
asks the three questions in turn, then dials once to check the secret. See the
[setup walkthrough](/docs/v0.4/remote/setup#client--6-save-the-server).

## Pinned certificates [#pinned-certificates]

On the first connection koshi records the fingerprint of the certificate the
server presented — the sha256 of it, as 64 lowercase hex characters — and pins
it.

A later connection presenting a different certificate is **always** refused,
and the refusal names the address and both fingerprints.

```bash
koshi remote forget work   # only when the server really was reinstalled
```

Connect again to pin the new certificate.

<Callout type="warn">
  A changed fingerprint means the machine answering that address is not the one
  you pinned. Forget the record only when you know why the certificate changed.
</Callout>

A server saved past a failed check holds no fingerprint, and its first
connection pins the certificate it meets.

## Editing a saved server [#editing-a-saved-server]

```bash
koshi remote edit work
```

It asks the same three questions with the saved values in brackets. An empty
answer keeps the value in brackets, and an empty secret keeps the saved secret,
so only what changes is typed:

```text
$ koshi remote edit work
press Enter to keep the value in brackets. An empty secret keeps the saved one. Ctrl-C stops without saving.
name [work]:
address [laptop.local:7654]: laptop.local:7655
secret:
checking laptop.local:7655 …
updated work at laptop.local:7655.
```

An edit that **keeps** the address requires the pinned fingerprint on the
check, so a certificate that changed under that address does not pass. An edit
that **changes** the address requires none: a pinned fingerprint stands for the
address the record held when that certificate was met.

A check that passes pins the certificate the server presented, either way. A
check that does not pass keeps the pinned fingerprint while the address is
unchanged, and keeps none once the address changed. When the check does not
pass, the last question names it:

```text
save the change anyway? The certificate at that address is pinned on the first connection to it. [y/N]
```

Nothing is written until every answer has settled. Ctrl-C at any question, and
input that ends before an answer arrives, leave the saved server unchanged.

## Rotating a secret [#rotating-a-secret]

Once the serving machine grants a fresh secret:

```bash
koshi remote set-secret work
```

It reads the new secret the way a connection does — from
`KOSHI_REMOTE_SECRET`, or asked for at the terminal.

## Two koshi processes at once [#two-koshi-processes-at-once]

The store is read again at the moment the record is written, and the read and
the write are held against every other `koshi` by a lock on
`remote/servers.lock` beside the store.

* A server another `koshi` saved while the questions were open is still saved,
  and a name or address that another record took meanwhile is refused with
  nothing written.
* Every command that changes a saved server takes that lock, `koshi attach`
  included, which stamps the record it dialled.
* A lock another `koshi` still holds after five seconds reads
  `koshi: IPC unavailable: another koshi is changing the saved servers; try again`.
  The operating system releases the lock if the `koshi` holding it dies.
* The lock is never held while a question waits for an answer.

An edit re-reads its record at that same moment. A record whose name, address,
secret, or fingerprint another `koshi` changed while the questions were open is
refused, and the older values are not written:

```text
koshi: invalid arguments: work changed while the questions were open, so nothing was saved; run `koshi remote edit work` again
```

The added time and the last-used time are not compared, so another `koshi` that
only dialled this server does not stop the edit.

## The sweep [#the-sweep]

A bare `koshi list-sessions` and a bare `koshi attach` sweep every saved server
and append what answered. The sweep waits **two seconds in total**, not two
seconds per server, so one unreachable machine cannot slow the list. A server
not heard from inside that wait is left out.

A server that answers and refuses the saved secret is not hidden — it prints
the command that replaces that secret:

```text
work: the saved secret was refused; run `koshi remote set-secret work`
```

A saved server that pins no certificate is left out of the sweep, and one
stderr line names it. Naming it connects, pins the certificate that server
presents, and the sweep includes it from then on:

```bash
koshi list-sessions --remote work
```

## Reconnecting [#reconnecting]

`remote-reconnect` is on by default and belongs to the terminal you sit at. It
applies only to a terminal viewing a session on another machine.

A dropped link dials that machine again — after 1 second, then 2, 4, 8, and 8
before every dial after that — for up to 120 seconds. While it waits, the tab
strip reads a tag shaped like:

```text
RECONNECTING (attempt 4, retry in 8s)
```

The first number is the dial it is about to make; the second is the seconds
left before that dial, counting down by one each second. The attempt number
rises by one on every dial, so the fourth dial and every dial after it waits
the full 8 seconds.

Joining again puts back the tab you were on, the focused pane of each tab, the
fullscreened pane of each tab, and the scroll offset of each pane. Keys typed
while the link is down are dropped; a resize is kept.

A refusal no dial can change stops the dialing at once, without waiting the 120
seconds out. When the dialing stops, koshi puts your terminal back the way it
found it, then prints the cause, then `the session continues without you`, then
the command that lists the session on that server and the command that joins it
again. It exits with a non-zero status.

Off, a dropped link ends the terminal, printing how to attach again by hand. A
link to a session on this machine ends the terminal either way.

```kdl title="koshi.kdl"
version 1
remote-reconnect #true
```
