# 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 `, 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. ```json { "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": "", "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. Optional hardening Enable the Proxmox firewall on CT 126 (`firewall=1` on net0) and allow tcp/7681 only from 10.10.10.27. The same rule suits code-server on :8680. ## Operations | Task | Command | |---|---| | Sessions | `devdesk ls` | | Attach over SSH | `devdesk attach ` (or `devdesk pick`) | | New session (optionally in a project) | `devdesk new [project]`, or the Sessions panel form | | Rename a session | `devdesk rename `, or ✎ in the Sessions panel | | End a session | `devdesk end `, × 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) |