Files
devdesk/docs/DEPLOY.md
T
jaredandClaude Opus 5.5 be9b026a01
build-deb / Lint, test, package (push) Successful in 2m12s
build-deb / Deploy to CT 126 (push) Successful in 3s
build-deb / Notify on failure (push) Skipped
feat: v0.5.0 header, switcher, phone key bar, shared polling, Matrix "needs you"
- Header: no SSO chip ("Sign in again" only on expiry), state dot on the
  session chip, LIVE as a dot, ⋯ menu for text size/notifications/fullscreen,
  Panels badge for waiting sessions and alerts.
- Session switcher on the chip; bare URL reattaches the last session; + New
  opens the panel form with project folders.
- Notifications when other sessions start waiting; alerts polled with the
  panels closed; one tab polls for all tabs over BroadcastChannel.
- Sidebar: context bar per session instead of the Context panel; compact
  Repo/CI with "Ask Claude to fix CI"; legible labels.
- Phone: key bar, drawer with backdrop, visualViewport-aware layout, DOM
  renderer on touch, compact connection dot.
- devdesk-notify-matrix: one Matrix message per wait that lasts
  DEVDESK_MATRIX_DELAY seconds with nobody attached.

Closes #8
Closes #13
Closes #14
Closes #15
Closes #16
Closes #17
Closes #28

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 23:34:59 -04:00

5.2 KiB
Raw Permalink Blame History

Deploying DevDesk (CT 126 · dev.lotusguild.org)

1. Install the package

Add the Gitea apt repository once:

curl -fsSL https://code.lotusguild.org/api/packages/LotusGuild/debian/repository.key \
  -o /etc/apt/keyrings/gitea-LotusGuild.asc
echo "deb [signed-by=/etc/apt/keyrings/gitea-LotusGuild.asc] https://code.lotusguild.org/api/packages/LotusGuild/debian bookworm main" \
  > /etc/apt/sources.list.d/lotusguild.list
apt update && apt install devdesk

On install, /etc/devdesk/secret.env is generated, devdesk-tmux.service and devdesk.service are enabled and started, and ttyd listens on :7681. Requests without the credential get a 401.

2. Nginx Proxy Manager (CT 139)

  • Proxy host: dev.lotusguild.org → http://10.10.10.58:7681.
    • Websockets Support on.
    • SSL: the existing wildcard *.lotusguild.org certificate, with Force SSL.
  • Advanced tab: paste npm-advanced.conf, replacing __DEVDESK_BASIC__ with the output of:
    . /etc/devdesk/secret.env && printf '%s' "$DEVDESK_CREDENTIAL" | base64 -w0
    
  • Why the credential matters: ttyd only checks the credential, so anything on the LAN that bypasses NPM is refused. If you rotate it, delete secret.env, run dpkg-reconfigure devdesk, update NPM, then systemctl restart devdesk.

3. Authelia (CT 167)

Add these to access_control.rules in /etc/authelia/configuration.yml, above any broader *.lotusguild.org rule:

- domain: dev.lotusguild.org
  policy: two_factor
  subject: ['user:jared']
- domain: dev.lotusguild.org
  policy: deny

Then run authelia validate-config --config /etc/authelia/configuration.yml && systemctl restart authelia.

4. DNS

  • Cloudflare: add a CNAME dev → apex, DNS-only (grey cloud).
  • Pi-hole: add "10.10.10.27 dev.lotusguild.org" to dns.hosts in pve-infra/containers/163-pihole/etc/pihole/pihole.toml. A push auto-deploys it, and LAN clients then reach NPM directly instead of hairpinning.

5. Auto-deploy on release

A v* tag makes CI publish the package, then send a signed webhook (the house HMAC pattern) to CT 126's existing webhook listener on :9000. The listener runs /usr/lib/devdesk/devdesk-deploy <ref>, which waits for that version in the apt registry and upgrades only devdesk with --force-confold. Running Claude sessions are untouched. The log is /var/log/devdesk-deploy.log.

Setup, done once:

  1. Generate a secret.
  2. Add this hook to /etc/webhook/hooks.json, next to 126-config-deploy. The file is local and untracked because it holds secrets.
    {
      "id": "devdesk-deploy",
      "execute-command": "/usr/lib/devdesk/devdesk-deploy",
      "command-working-directory": "/",
      "pass-arguments-to-command": [{"source": "payload", "name": "ref"}],
      "trigger-rule": {"and": [
        {"match": {"type": "payload-hash-sha256", "secret": "<WEBHOOK_SECRET>",
                   "parameter": {"source": "header", "name": "X-Gitea-Signature"}}},
        {"match": {"type": "regex", "regex": "^refs/tags/v[0-9]+\\.[0-9]+\\.[0-9]+$",
                   "parameter": {"source": "payload", "name": "ref"}}}
      ]}
    }
    
  3. Run systemctl restart webhook.
  4. Store the same secret as the devdesk repo's Actions secret WEBHOOK_SECRET.

6. Firewall (required)

The ttyd credential is the only thing between the LAN and a root shell, so only NPM may reach :7681. CT 126 ships this in pve-infra (containers/126-codingenvironment/etc/nftables.conf, installed by its deploy.sh):

table inet devdesk {
    chain input {
        type filter hook input priority filter - 10; policy accept;
        tcp dport 7681 ip saddr { 127.0.0.1, 10.10.10.27 } accept
        tcp dport 7681 ip6 saddr ::1 accept
        tcp dport 7681 counter reject with tcp reset
    }
}

Check from another LAN host: curl -m3 http://10.10.10.58:7681/ must fail with "connection refused". To rotate the credential: rm /etc/devdesk/secret.env && dpkg-reconfigure devdesk, put the new Authorization value in NPM proxy host 58's Advanced tab, then systemctl restart devdesk.

7. Matrix "Claude needs you" (optional)

  1. Deploy a hookshot transform named Devdesk (hookshot/devdesk.js in the matrix repo; pushing it to main auto-deploys it on LXC 151). Look up the hook UUID as described in that repo's README.
  2. umask 077; echo https://matrix.lotusguild.org/webhook/<uuid> > /etc/devdesk/matrix-webhook.
  3. Nothing to restart: the next wait that lasts DEVDESK_MATRIX_DELAY seconds with nobody attached posts a message.

Operations

Task Command
Sessions devdesk ls
Attach over SSH devdesk attach <name> (or devdesk pick)
New session (optionally in a project) devdesk new <name> [project], or the Sessions panel form
Rename a session devdesk rename <old> <new>, or ✎ in the Sessions panel
End a session devdesk end <name>, × in the Sessions panel, or [x] in the Claude window's exit menu
Restart the web side (safe) systemctl restart devdesk
Stop every session systemctl stop devdesk-tmux
Logs journalctl -u devdesk -u devdesk-tmux
UI-only update replace /usr/share/devdesk/index.html (ttyd re-reads it per request)