dev_arc_aws/TERMIX_MIGRATION.md
Claude 5d56a1d902
Phase 1b: SSH jump-host chaining, TOFU host-key verification, multi-host Settings UI
Terminal connections can now reference a jumpHostIntegrationId on the SSH
integration config; the backend connects to the jump host first and tunnels
to the real target via ssh2's forwardOut(), rather than connecting directly.

Added an ssh_host_keys table and a hostVerifier callback that accepts and
stores a host's fingerprint on first connect, then hard-rejects on any
mismatch on subsequent connects (trust-on-first-use).

Settings previously only ever showed/edited one integration per type, which
silently prevented configuring more than one SSH host at all. Added a
dedicated multi-host SSH section (per-host Save/Test/Delete, Add SSH Host,
and a Jump Host dropdown) so jump-host chaining is actually usable from the UI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BbJV5nm8KPVH1oNJYKpnoF
2026-06-19 11:04:46 +00:00

79 lines
10 KiB
Markdown

# Termix → ArchNest Migration Plan
Status doc for porting Termix's full feature set into ArchNest as a single app, single backend, single auth, single database — reskinned to match ArchNest's design. Written so any session (human or AI) can see exactly what's done, what's next, and why decisions were made.
Source: `https://github.com/SamuelSJames/Termix` (user's fork), cloned for reference at the time of writing. Upstream is `Termix-SSH/Termix`, an Electron + Express + Drizzle ORM self-hosted SSH/RDP/VNC management app — **not** a small terminal widget. It ships as its own Docker image with a `guacd` sidecar for RDP/VNC.
## Decision: why merge into ArchNest's backend, not Termix's
ArchNest's backend (Fastify + better-sqlite3 + JWT) is small and already has things worth keeping: the bookmarks system, the integration adapter framework (Proxmox/AWS/NetBird/Cloudflare/Weather/SSH health checks — see `backend/src/integrations/`), the audit log, and a working auth/profile system built this session. Termix's backend is much bigger but its *value* is the SSH/tunnel/file-manager/Docker/RDP feature logic, not its auth system (OIDC/LDAP/2FA) or its Drizzle schema. So: **port Termix's feature modules onto ArchNest's existing Fastify app and auth**, don't adopt Termix's backend wholesale.
## What is explicitly NOT being ported (user-approved tradeoff)
- Electron desktop app + native installers (Chocolatey/Flatpak/AppImage/MSI/Cask) — ArchNest is a web app.
- OIDC/LDAP/2FA/SSO and Termix's own multi-user auth system — replaced by ArchNest's existing JWT auth. User confirmed they don't currently use 2FA/OIDC/LDAP, so this is an accepted downgrade, not an oversight.
- ~30 language translations (i18n) — not a stated goal, not being ported.
- All Termix branding — logos, icons, About/product copy, links to Termix's Discord/docs/GitHub. Every ported UI component gets reskinned to ArchNest's Tailwind theme (gold `#C8A434`, the existing dark palette) as part of porting it, not as a separate pass.
Everything else — SSH terminal, tunnels, file manager, Docker management, RDP/VNC/Telnet, host metrics — is in scope to fully port, feature-equivalent, just rebuilt on ArchNest's stack.
## Phases
Each phase is independently committable and testable. Do not start a later phase before the previous one is working end-to-end and committed — this is a large port and needs to land in reviewable chunks.
### Phase 1 — SSH Terminal (IN PROGRESS)
The actual `/terminal` page: a real interactive SSH terminal in the browser (xterm.js + WebSocket), reusing the SSH credentials already stored in ArchNest's integrations (no second "add a host" flow — Termix's separate host-manager concept is being merged into ArchNest's existing `integrations` table/SSH adapter, not duplicated).
**Termix source files this phase is based on** (sizes as of the fork snapshot, for scoping):
- `src/backend/ssh/terminal.ts` (2,570 lines) — WebSocket route handling, message protocol (connect/data/resize/disconnect), output buffering.
- `src/backend/ssh/terminal-session-manager.ts` (570 lines) — session lifecycle, reattach-on-reconnect, per-user session caps, idle timeout, optional session logging to disk.
- `src/backend/ssh/ssh-connection-pool.ts` (225 lines) — connection reuse.
- `src/backend/ssh/host-resolver.ts`, `jump-host-chain.ts`, `terminal-jump-hosts.ts` (~900 lines combined) — jump-host / bastion chaining.
- `src/backend/ssh/auth-manager.ts`, `credential-username.ts`, `host-key-verifier.ts`, `terminal-auth-helpers.ts` (~950 lines combined) — credential resolution, host key verification/trust-on-first-use.
- `src/backend/ssh/opkssh-auth.ts`, `opkssh-cert-auth.ts` (~1,350 lines) — OPKSSH (OpenPubkey SSH) certificate auth.
- `src/backend/ssh/tmux-monitor.ts`, `tmux-helper.ts`, `tmux-monitor-helpers.ts` (~1,350 lines) — tmux session detection/monitoring inside the terminal.
- Frontend: `src/ui/features/terminal/*` — xterm.js wrapper, tab system, up-to-4-panel split screen, theme/font customization.
**Scope split for this phase, given the size above:**
- **Phase 1a (doing this now)**: core single-session SSH terminal. WebSocket connect/data/resize/disconnect, using ArchNest's existing SSH integration config/secrets (host/port/username/password/privateKey/passphrase — already in `backend/src/integrations/ssh.ts`) instead of Termix's separate host table. One terminal per tab, no split panes yet, no jump hosts, no OPKSSH, no tmux monitor, no session recording/logging. Ported onto Fastify's WebSocket support, reusing ArchNest's JWT auth for the WS handshake.
- **Phase 1b (follow-up, not blocking 1a)**: jump-host/bastion chaining, host-key verification/trust-on-first-use UI, tab system + up to 4 split panes, terminal theme/font customization settings.
- **Phase 1c (follow-up, lower priority)**: OPKSSH cert auth, tmux session monitor/reattach, session recording/logging to disk.
Rationale for splitting: 1a alone is a real, useful terminal (matches what `/terminal` needs to stop being a placeholder) and is testable end-to-end on its own. Bundling jump-hosts/OPKSSH/tmux into the first pass risks a large unreviewable change with no working checkpoint in between.
**Status:**
-**Phase 1a — done.** `/terminal` is a real interactive SSH terminal: `backend/src/routes/terminal.ts` (WebSocket, connect/input/resize/disconnect over `ssh2`), `backend/src/db/secrets.ts` (shared secret loader), `src/pages/Terminal.tsx` (xterm.js + host picker, reuses ArchNest's existing SSH integrations — no duplicate host table). Verified end-to-end against a real test SSH server. No jump hosts, no tabs/split panes, no OPKSSH, no tmux monitor yet — see 1b/1c below.
- 🟡 **Phase 1b — in progress.** Done so far:
- **Jump-host chaining**: an SSH integration's config can carry `jumpHostIntegrationId` referencing another SSH integration. `backend/src/routes/terminal.ts` connects to the jump host first, opens a `forwardOut()` channel to the real target, and connects the target `Client` over that channel (single-hop; mirrors Termix's core mechanism without its multi-hop/credential-sharing complexity). Verified end-to-end with two real test SSH servers (one as jump, one as target).
- **Host-key verification (TOFU)**: new `ssh_host_keys` table (`backend/src/db/index.ts`) stores a SHA-256 fingerprint per SSH integration on first successful connect; subsequent connects are rejected if the fingerprint changes, via `ssh2`'s `hostVerifier` connect option. No interactive accept/reject-changed-key UI yet — first-use accept-and-store, hard-reject on mismatch. Verified both the accept-on-first-use and reject-on-mismatch paths against a real test server.
- **Settings UI for multiple SSH hosts**: `src/pages/Settings.tsx` previously could only show/edit one integration per type, which silently broke multi-host SSH. Added a dedicated `SshHostsSection` with its own per-host cards (Save/Test/Delete) and an "Add SSH Host" flow, including a `Jump Host` dropdown populated from the other configured SSH hosts.
- Not yet done: tab system + up-to-4 split panes and terminal theme/font customization in `src/pages/Terminal.tsx` — that page is still single-session only.
- ⬜ Phase 1c — not started.
### Phase 2 — SSH Tunnels (NOT STARTED)
Source: `src/backend/ssh/tunnel.ts` (2,414 lines) + `tunnel-c2s-relay.ts`, `tunnel-socks5-relay.ts`, `tunnel-ssh-primitives.ts`, `tunnel-utils.ts`, `tunnel-c2s-relay-utils.ts` (~830 lines combined) + frontend `src/ui/features/tunnel/*`. Local/remote/dynamic SOCKS forwarding, automatic reconnection, health monitoring. Builds on Phase 1's connection pool. Client-to-server tunnel presets (save/rename/load/delete) need a small new table in ArchNest's schema.
### Phase 3 — Remote File Manager (NOT STARTED)
Source: `src/backend/ssh/file-manager*.ts` (six files, ~3,900 lines combined: list/content/action/operation/download routes + session + utils) + frontend `src/ui/features/file-manager/*`. View/edit code/images/audio/video, upload/download/rename/delete/move, sudo support, server-to-server moves. Runs over the SSH connections from Phase 1.
### Phase 4 — Docker Container Management (NOT STARTED)
Source: `src/backend/ssh/docker.ts` (2,243 lines) + `docker-container-routes.ts` (1,093 lines) + `docker-console.ts` (751 lines) + frontend `src/ui/features/docker/*`. Start/stop/pause/remove containers, view stats, `docker exec` terminal. **Check for overlap** with ArchNest's existing `backend/src/integrations/docker.ts` adapter (currently just used for health-status resources) before porting — may be able to extend the existing adapter rather than bolt on a second, separate Docker code path.
### Phase 5 — RDP/VNC/Telnet (NOT STARTED)
Source: `src/backend/guacamole/*` + `guacamole-lite` dependency + frontend `src/ui/features/guacamole/*`. **Biggest infra lift**: requires a `guacd` sidecar container (see `docker/docker-compose.yml` in the Termix fork) added to ArchNest's own `docker-compose.yml` — this is a new runtime dependency, not just ported code. Should be scoped in detail (including how `guacd` networking/ports interact with ArchNest's existing deployment on `racknerd1`/NPM) before starting.
### Also worth checking during/after the phases above
- `src/backend/ssh/host-metrics*.ts` (~3,900 lines combined across 8 files) — CPU/memory/disk/network/uptime/firewall/port-monitor/log-viewer/users-permissions/certificates widgets. Not yet assigned to a phase; likely overlaps with ArchNest's existing SSH adapter health probe (`backend/src/integrations/ssh.ts`) and Infrastructure page — worth a deliberate decision on whether to fold these widgets into the existing Infrastructure page rather than recreate Termix's own dashboard-cards system (`src/ui/dashboard/*`).
- `src/backend/ssh/host-transfer.ts` (3,428 lines) — appears to be server-to-server file/data transfer; likely folds into Phase 3 (file manager) rather than being separate.
- Data export/import of SSH hosts/credentials/file-manager data — a nice-to-have, not yet scheduled.
## Tracking
Update the phase status lines above as work lands. Each phase should get its own commit(s) on `claude/wonderful-faraday-qxym5t`, following the existing commit message style (descriptive title + why, `Co-Authored-By`/`Claude-Session` trailer).