Skip to content

Replace TTYD web terminal with key-only SSHD and Mosh - #3

Merged
stephen-cox merged 3 commits into
mainfrom
feature/sshd-mosh
Sep 3, 2026
Merged

Replace TTYD web terminal with key-only SSHD and Mosh#3
stephen-cox merged 3 commits into
mainfrom
feature/sshd-mosh

Conversation

@stephen-cox

Copy link
Copy Markdown
Owner

The browser terminal was unusable on mobile: no modifier keys, flaky selection, keyboard-induced resizes. Reverse the earlier swap and standardise on SSH.

  • openssh-server on 2222, key-only (no password, kbd-interactive or root login; AllowUsers dev; LoginGraceTime/MaxAuthTries hardened; ClientAlive keepalives to survive mobile NAT timeouts)
  • Interactive logins attach to the shared 'main' tmux session; system /etc/tmux.conf enables mouse mode and a 50k history
  • Mosh on UDP 60000 for roaming and local echo on mobile networks
  • sshd host key persisted (/etc/ssh/host-keys) so fingerprints survive restarts; startup fails closed without authorized_keys
  • Compose and Kubernetes examples updated (hostNetwork restores node-direct :2222; the terminal Ingress is removed)
  • CI generates a keypair and proves login, password/root refusal, tmux attach and host-key stability across container recreation
  • Includes the in-flight Git identity wiring (GIT_USER_NAME/EMAIL env, ConfigMap, CI checks, docs) found uncommitted in the tree

ttyd is gone entirely; openssh-server and mosh come from Ubuntu and pick up patches via the weekly no-cache rebuild.

The browser terminal was unusable on mobile: no modifier keys, flaky
selection, keyboard-induced resizes. Reverse the earlier swap and
standardise on SSH.

- openssh-server on 2222, key-only (no password, kbd-interactive or
  root login; AllowUsers dev; LoginGraceTime/MaxAuthTries hardened;
  ClientAlive keepalives to survive mobile NAT timeouts)
- Interactive logins attach to the shared 'main' tmux session; system
  /etc/tmux.conf enables mouse mode and a 50k history
- Mosh on UDP 60000 for roaming and local echo on mobile networks
- sshd host key persisted (/etc/ssh/host-keys) so fingerprints survive
  restarts; startup fails closed without authorized_keys
- Compose and Kubernetes examples updated (hostNetwork restores
  node-direct :2222; the terminal Ingress is removed)
- CI generates a keypair and proves login, password/root refusal,
  tmux attach and host-key stability across container recreation
- Includes the in-flight Git identity wiring (GIT_USER_NAME/EMAIL env,
  ConfigMap, CI checks, docs) found uncommitted in the tree

ttyd is gone entirely; openssh-server and mosh come from Ubuntu and
pick up patches via the weekly no-cache rebuild.
${{ runner.temp }} is only valid in step-level env blocks; the job-level
reference made GitHub reject the whole workflow file at parse time. Move
the SSH_AUTHORIZED_KEYS_DIR definition into the key-creation step and
export it through GITHUB_ENV so all later steps see it. Verified with
actionlint (clean).
… uid

A bind mount keeps the host's uid on authorized_keys. sshd StrictModes
rejects key files owned by neither the user nor root, so GitHub runners
(uid 1001 vs dev's 1000) got 'Permission denied (publickey)' — and any
real host with a non-1000 uid (macOS: 501) would too.

- start.sh copies the delivered keys to a root-owned
  /etc/ssh/authorized_keys/dev on every boot; sshd reads that path
  first via AuthorizedKeysFile, with .ssh/authorized_keys kept as a
  live second source for keys added interactively
- CI keeps the private key outside the directory mounted into the
  container (ci_key in RUNNER_TEMP, only authorized_keys is mounted)
@stephen-cox
stephen-cox merged commit 94d9a82 into main Sep 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant