Files
jaredandClaude Opus 5.5 74927a7640
build-deb / Lint, test, package (push) Successful in 3m53s
build-deb / Deploy to CT 126 (push) Successful in 10s
build-deb / Notify on failure (push) Skipped
fix: v0.9.1 robustness cleanups
- run_resume falls back to a new conversation only when the transcript file
  is gone; other failures end at the menu with the recorded id intact.
- The SessionStart hook resolves the session name under the registry lock;
  rename holds it across tmux rename-session and the registry move
  (dd_registry_locked, nestable).
- dd_load_env parses KEY=value like systemd instead of sourcing the files.
- devdesk-deploy: DPkg::Lock::Timeout, explicit FAILED lines on stdout and in
  the log; the hook answers synchronously and CI checks the HTTP status.
  logrotate for the deploy log.
- postinst drops duplicate terminal-features entries; hooks sweep stale
  temp files.

Closes #12

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 01:01:51 -04:00

99 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Deploying DevDesk (CT 126 · dev.lotusguild.org)
## 1. Install the package
Add the Gitea apt repository once:
```bash
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`](npm-advanced.conf), replacing `__DEVDESK_BASIC__` with the output of:
```bash
. /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:
```yaml
- 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` (rotated monthly).
The hook answers when the deploy has finished, with the script's last line, and with HTTP 500 if it failed. CI's **Deploy to CT 126** job therefore fails when the install fails, and the failure alert goes to Matrix.
**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.
```json
{
"id": "devdesk-deploy",
"execute-command": "/usr/lib/devdesk/devdesk-deploy",
"command-working-directory": "/",
"pass-arguments-to-command": [{"source": "payload", "name": "ref"}],
"include-command-output-in-response": true,
"include-command-output-in-response-on-error": true,
"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) |