infra/stacks/terminal/files/devvm
Viktor Barzin e88ce131f1 terminal: cut over to multi-session lobby on terminal.viktorbarzin.me
Promotes the staged multi-session UX from term.viktorbarzin.me to the
primary terminal.viktorbarzin.me hostname. `ttyd.service` on the DevVM
moves to the same ExecStart that `ttyd-multi.service` was running:
`/usr/local/bin/ttyd -W -a -t enableClipboard=true -I
/usr/local/share/ttyd/index.html -p 7681 /usr/local/bin/tmux-attach.sh`.
The lobby HTML supersedes the old per-user-attach index.html
(ttyd-session.sh wrapper retired alongside).

Terraform: retires the `terminal-multi` Service+Endpoints and the
term.viktorbarzin.me ingress (Cloudflare DNS record for `term` is
released by module deletion). The tmux-api Service+Endpoints stay, but
its IngressRoute now matches terminal.viktorbarzin.me — same path-prefix
specificity wins against the catch-all ingress.

DevVM follow-up (applied manually as before — see files/devvm/README.md):
restart ttyd to pick up the new unit, stop+disable ttyd-multi.service.
2026-05-13 16:34:36 +00:00
..
README.md terminal: cut over to multi-session lobby on terminal.viktorbarzin.me 2026-05-13 16:34:36 +00:00
tmux-api.service terminal: add multi-tmux-session lobby on term.viktorbarzin.me (additive) 2026-05-13 15:24:04 +00:00
tmux-attach.sh terminal: add multi-tmux-session lobby on term.viktorbarzin.me (additive) 2026-05-13 15:24:04 +00:00
ttyd.service terminal: cut over to multi-session lobby on terminal.viktorbarzin.me 2026-05-13 16:34:36 +00:00

DevVM terminal files

These files configure ttyd + tmux-api on the DevVM (10.0.10.10). ttyd serves the multi-session lobby (and per-session attach via ?arg=<name>) on port 7681; tmux-api is a small Go REST API on 7684 that powers the lobby's list/kill actions.

terminal-ro.service (port 7682, single read-only session) and clipboard-upload (port 7683) are unchanged by these files.

Layout

Source Destination on DevVM
tmux-attach.sh /usr/local/bin/tmux-attach.sh (chmod 0755)
ttyd.service /etc/systemd/system/ttyd.service
tmux-api.service /etc/systemd/system/tmux-api.service
../index.html (one level up) /usr/local/share/ttyd/index.html
../../tmux-api/ binary, built GOOS=linux GOARCH=amd64 /usr/local/bin/tmux-api (chmod 0755)

Apply

From the workstation (infra/ repo root):

DEVVM=10.0.10.10   # SSH config provides the user

# 1. Build the tmux-api binary for linux/amd64
( cd infra/stacks/terminal/tmux-api && GOOS=linux GOARCH=amd64 go build -o /tmp/tmux-api . )

# 2. HTML page + wrapper script
scp infra/stacks/terminal/files/index.html $DEVVM:/tmp/index.html
scp infra/stacks/terminal/files/devvm/tmux-attach.sh $DEVVM:/tmp/tmux-attach.sh
ssh $DEVVM "sudo install -m 0644 /tmp/index.html /usr/local/share/ttyd/index.html && \
            sudo install -m 0755 /tmp/tmux-attach.sh /usr/local/bin/tmux-attach.sh && \
            rm /tmp/index.html /tmp/tmux-attach.sh"

# 3. tmux-api binary
scp /tmp/tmux-api $DEVVM:/tmp/tmux-api
ssh $DEVVM "sudo install -m 0755 /tmp/tmux-api /usr/local/bin/tmux-api && rm /tmp/tmux-api"

# 4. systemd units
scp infra/stacks/terminal/files/devvm/ttyd.service     $DEVVM:/tmp/
scp infra/stacks/terminal/files/devvm/tmux-api.service $DEVVM:/tmp/
ssh $DEVVM "sudo mv /tmp/ttyd.service     /etc/systemd/system/ && \
            sudo mv /tmp/tmux-api.service /etc/systemd/system/ && \
            sudo systemctl daemon-reload && \
            sudo systemctl enable --now tmux-api && \
            sudo systemctl restart ttyd"

# 5. Sanity checks
ssh $DEVVM "systemctl status ttyd tmux-api --no-pager"
ssh $DEVVM "curl -sf localhost:7684/sessions"
ssh $DEVVM "curl -sf localhost:7681/ | head -5"
ssh $DEVVM "systemctl is-active terminal-ro"   # unrelated unit, unaffected

Notes

  • User=wizard — single Unix user owns the tmux server. Sessions are shared across every browser tab that attaches.
  • ttyd version must be ≥ 1.7 for the -a flag (allow URL args → argv). The DevVM currently has 1.7.7.
  • Argv flow: ?arg=foo on the URL → ttyd appends foo as $1 to tmux-attach.sh → the wrapper regex-validates and runs tmux new-session -A -s "$name". ttyd uses argv (never a shell string), so there is no injection path.
  • No external exposure of 7684/7681 — the DevVM is reachable only from the cluster (10.0.10.10 is on the internal VLAN). Authentik forward-auth on the ingress is the access gate.
  • Cutover historyterm.viktorbarzin.me and ttyd-multi.service (port 7685) were the staging surface for this design. Both were retired in the same commit that promoted the multi-session config to port 7681.