@lamalibre/create-lamaste 4.3.1 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/package.json +2 -2
  2. package/src/lib/service-config.js +6 -0
  3. package/vendor/docs/00-introduction/how-it-works.md +2 -2
  4. package/vendor/docs/00-introduction/quickstart.md +5 -5
  5. package/vendor/docs/00-introduction/what-is-lamaste.md +5 -5
  6. package/vendor/docs/01-concepts/certificates.md +3 -3
  7. package/vendor/docs/01-concepts/mtls.md +2 -2
  8. package/vendor/docs/01-concepts/security-model.md +38 -1
  9. package/vendor/docs/01-concepts/tickets.md +2 -2
  10. package/vendor/docs/01-concepts/tunneling.md +4 -4
  11. package/vendor/docs/02-guides/agent-setup.md +6 -6
  12. package/vendor/docs/02-guides/certificate-management.md +2 -2
  13. package/vendor/docs/02-guides/cloud-provisioning.md +3 -3
  14. package/vendor/docs/02-guides/desktop-app-setup.md +11 -11
  15. package/vendor/docs/02-guides/installation.md +3 -3
  16. package/vendor/docs/02-guides/onboarding.md +2 -2
  17. package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +2 -2
  18. package/vendor/docs/03-architecture/installer-flow.md +2 -2
  19. package/vendor/docs/03-architecture/installer.md +4 -4
  20. package/vendor/docs/03-architecture/management-flow.md +1 -1
  21. package/vendor/docs/03-architecture/overview.md +5 -5
  22. package/vendor/docs/03-architecture/panel-client.md +7 -7
  23. package/vendor/docs/03-architecture/panel-server.md +2 -2
  24. package/vendor/docs/03-architecture/state-management.md +2 -2
  25. package/vendor/docs/03-architecture/system-overview.md +1 -1
  26. package/vendor/docs/04-api-reference/agent-hosted-plugins.md +394 -34
  27. package/vendor/docs/04-api-reference/app-host.md +87 -38
  28. package/vendor/docs/04-api-reference/audit-and-notifications.md +10 -10
  29. package/vendor/docs/04-api-reference/certificates.md +22 -19
  30. package/vendor/docs/04-api-reference/lifecycle-hooks.md +34 -12
  31. package/vendor/docs/04-api-reference/onboarding.md +1 -1
  32. package/vendor/docs/04-api-reference/overview.md +137 -135
  33. package/vendor/docs/04-api-reference/registry-and-oidc.md +3 -1
  34. package/vendor/docs/04-api-reference/tunnels.md +14 -10
  35. package/vendor/docs/05-operations/backup-and-restore.md +2 -1
  36. package/vendor/docs/05-operations/uninstalling.md +1 -1
  37. package/vendor/docs/05-operations/upgrades.md +6 -6
  38. package/vendor/docs/06-reference/config-files.md +90 -85
  39. package/vendor/docs/06-reference/glossary.md +3 -3
  40. package/vendor/docs/06-reference/installer-flags.md +13 -13
  41. package/vendor/docs/06-reference/ports-and-services.md +1 -1
  42. package/vendor/docs/06-reference/troubleshooting.md +8 -8
  43. package/vendor/docs/gatekeeper-design.md +8 -8
  44. package/vendor/docs/identity-directory-design.md +2 -2
  45. package/vendor/docs/package.json +1 -1
  46. package/vendor/docs/todo/lib-cli-desktop-refactor.md +27 -27
  47. package/vendor/gatekeeper/package.json +2 -2
  48. package/vendor/server/bin/lamaste-server.js +4 -1
  49. package/vendor/server/package.json +4 -3
  50. package/vendor/server/src/commands/plugin-settings.js +541 -0
  51. package/vendor/server/src/commands/plugins.js +94 -27
  52. package/vendor/server/src/panel-api.js +36 -4
  53. package/vendor/server/src/plugin-approval.js +78 -0
  54. package/vendor/server/src/plugin-settings.js +699 -0
  55. package/vendor/server-ui/dist/assets/index-25wo_8av.css +1 -0
  56. package/vendor/server-ui/dist/assets/index-roDHz3dM.js +84 -0
  57. package/vendor/server-ui/dist/index.html +2 -2
  58. package/vendor/serverd/package.json +2 -2
  59. package/vendor/serverd/src/index.js +9 -0
  60. package/vendor/serverd/src/lib/agent-presence.js +106 -0
  61. package/vendor/serverd/src/lib/hook-pipelines.js +20 -4
  62. package/vendor/serverd/src/lib/migrations/state/0012_plugin_settings_and_presence.sql +62 -0
  63. package/vendor/serverd/src/lib/mtls.js +44 -4
  64. package/vendor/serverd/src/lib/plugin-hooks.js +120 -20
  65. package/vendor/serverd/src/lib/plugin-hosting.js +35 -14
  66. package/vendor/serverd/src/lib/plugin-lifecycle.js +267 -83
  67. package/vendor/serverd/src/lib/plugin-packages.js +30 -22
  68. package/vendor/serverd/src/lib/plugin-settings.js +1101 -0
  69. package/vendor/serverd/src/lib/plugins.js +108 -33
  70. package/vendor/serverd/src/lib/registry-credential.js +37 -0
  71. package/vendor/serverd/src/lib/tunnel-hooks.js +11 -0
  72. package/vendor/serverd/src/routes/management/plugins.js +166 -19
  73. package/vendor/serverd/src/routes/management/tunnels.js +21 -1
  74. package/vendor/server-ui/dist/assets/index-BTlBt_cD.js +0 -84
  75. package/vendor/server-ui/dist/assets/index-Bc5NCMSv.css +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamalibre/create-lamaste",
3
- "version": "4.3.1",
3
+ "version": "4.4.1",
4
4
  "description": "One-command setup for secure reverse tunnels with a management dashboard",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -43,7 +43,7 @@
43
43
  "mtls"
44
44
  ],
45
45
  "dependencies": {
46
- "@lamalibre/lamaste": "^4.3.1",
46
+ "@lamalibre/lamaste": "^4.4.1",
47
47
  "chalk": "^5.3.0",
48
48
  "execa": "^9.0.0",
49
49
  "listr2": "^8.0.0"
@@ -43,6 +43,8 @@ SyslogIdentifier=lamalibre-lamaste-serverd
43
43
  ProtectHome=true
44
44
  ReadWritePaths=${ctx.configDir} /var/www/lamaste
45
45
  PrivateTmp=true
46
+ # No core dumps: the panel holds the CA key and every plugin's installation secret.
47
+ LimitCORE=0
46
48
 
47
49
  [Install]
48
50
  WantedBy=multi-user.target
@@ -149,6 +151,8 @@ ProtectHome=true
149
151
  ReadWritePaths=${ctx.configDir}
150
152
  PrivateTmp=true
151
153
  NoNewPrivileges=true
154
+ # No core dumps: the gatekeeper holds its API secret and cached Authelia sessions.
155
+ LimitCORE=0
152
156
 
153
157
  [Install]
154
158
  WantedBy=multi-user.target
@@ -411,6 +415,8 @@ MemorySwapMax=0
411
415
  CPUQuota=50%
412
416
  TasksMax=32
413
417
  LimitNOFILE=1024
418
+ # No core dumps: a hook sees application data.
419
+ LimitCORE=0
414
420
  `;
415
421
  }
416
422
 
@@ -55,14 +55,14 @@ SSH into a fresh Ubuntu droplet and run one command:
55
55
 
56
56
  ```bash
57
57
  apt install -y npm
58
- npx @lamalibre/create-lamaste@4.3.1
58
+ npx @lamalibre/create-lamaste@4.4.1
59
59
  ```
60
60
 
61
61
  This installs everything the relay needs: nginx, Node.js, firewall rules, certificates, and the management panel. At the end, it prints a client certificate file and password. You download the certificate, import it into your browser, and disconnect SSH. You never SSH in again.
62
62
 
63
63
  **Option B: Desktop app (cloud provisioning)**
64
64
 
65
- Install the desktop app (`npx @lamalibre/create-lamaste-desktop@4.3.1`) and use the Servers tab to create a DigitalOcean droplet. The app handles everything — droplet creation, Lamaste installation, certificate download, and connection — without you ever touching SSH. Cloud API tokens are stored in your OS credential store (macOS Keychain or Linux libsecret), never in plaintext. See the [Cloud Provisioning guide](../02-guides/cloud-provisioning.md) for a step-by-step walkthrough.
65
+ Install the desktop app (`npx @lamalibre/create-lamaste-desktop@4.4.1`) and use the Servers tab to create a DigitalOcean droplet. The app handles everything — droplet creation, Lamaste installation, certificate download, and connection — without you ever touching SSH. Cloud API tokens are stored in your OS credential store (macOS Keychain or Linux libsecret), never in plaintext. See the [Cloud Provisioning guide](../02-guides/cloud-provisioning.md) for a step-by-step walkthrough.
66
66
 
67
67
  **Phase 2: Onboarding (10 minutes, browser)**
68
68
 
@@ -59,7 +59,7 @@ Once connected:
59
59
 
60
60
  ```bash
61
61
  apt install -y npm
62
- npx @lamalibre/create-lamaste@4.3.1
62
+ npx @lamalibre/create-lamaste@4.4.1
63
63
  ```
64
64
 
65
65
  The installer displays a confirmation banner showing what it will do:
@@ -253,7 +253,7 @@ Every tunnel is carried by one **agent** — the machine that runs the app. Enro
253
253
  Install the Lamaste Desktop app, which provides a GUI with automatic service discovery and one-click tunnel creation:
254
254
 
255
255
  ```bash
256
- npx @lamalibre/create-lamaste-desktop@4.3.1
256
+ npx @lamalibre/create-lamaste-desktop@4.4.1
257
257
  ```
258
258
 
259
259
  The app auto-detects local services (Ollama, ComfyUI, PostgreSQL, Docker containers, etc.) and lets you expose them with one click. See the [Desktop App Setup](../02-guides/desktop-app-setup.md) guide for details.
@@ -263,7 +263,7 @@ The app auto-detects local services (Ollama, ComfyUI, PostgreSQL, Docker contain
263
263
  In the panel, go to **Certificates → Enrollment Token** and create a token for a label such as `laptop`. Then, on the machine that runs your app, install the agent globally and run setup:
264
264
 
265
265
  ```bash
266
- npm install -g @lamalibre/lamaste-agent@4.3.1
266
+ npm install -g @lamalibre/lamaste-agent@4.4.1
267
267
  LAMALIBRE_LAMASTE_ENROLLMENT_TOKEN=<token> \
268
268
  lamaste-agent setup --label laptop --panel-url https://203.0.113.42:9292
269
269
  ```
@@ -345,7 +345,7 @@ Your Mac DigitalOcean Droplet Internet
345
345
  The installer accepts optional flags:
346
346
 
347
347
  ```bash
348
- npx @lamalibre/create-lamaste@4.3.1 [flags]
348
+ npx @lamalibre/create-lamaste@4.4.1 [flags]
349
349
  ```
350
350
 
351
351
  | Flag | Effect |
@@ -435,7 +435,7 @@ In development mode (`NODE_ENV=development` or `NODE_ENV` unset), the panel serv
435
435
  # 2. SSH in and install
436
436
  ssh root@203.0.113.42
437
437
  apt install -y npm
438
- npx @lamalibre/create-lamaste@4.3.1
438
+ npx @lamalibre/create-lamaste@4.4.1
439
439
 
440
440
  # 3. Download cert (from your local machine)
441
441
  scp root@203.0.113.42:/etc/lamalibre/lamaste/pki/client.p12 .
@@ -36,7 +36,7 @@ Lamaste solves the problem of exposing local services to the internet securely.
36
36
  **Option A: Manual setup (SSH)**
37
37
 
38
38
  1. Create a fresh Ubuntu 24.04 droplet on DigitalOcean
39
- 2. SSH in once and run `npx @lamalibre/create-lamaste@4.3.1`
39
+ 2. SSH in once and run `npx @lamalibre/create-lamaste@4.4.1`
40
40
  3. Download the client certificate it prints
41
41
  4. Import the certificate into your browser
42
42
  5. Open `https://<droplet-ip>:9292` — you are in the admin panel
@@ -46,7 +46,7 @@ Lamaste solves the problem of exposing local services to the internet securely.
46
46
 
47
47
  **Option B: Desktop app cloud provisioning**
48
48
 
49
- 1. Install the desktop app (`npx @lamalibre/create-lamaste-desktop@4.3.1`)
49
+ 1. Install the desktop app (`npx @lamalibre/create-lamaste-desktop@4.4.1`)
50
50
  2. Go to the Servers tab and click "Create a new server"
51
51
  3. Enter your DigitalOcean API token — the app validates scopes and stores it securely in your OS credential store
52
52
  4. Pick a region (the app measures latency to each) and a domain name
@@ -93,14 +93,14 @@ All backend services bind `127.0.0.1` only — nginx is the sole public-facing s
93
93
 
94
94
  State is stored in JSON files (`/etc/lamalibre/lamaste/panel.json`, `tunnels.json`) with atomic writes (write to temp → fsync → rename). No database is needed at this scale.
95
95
 
96
- The installer (`npx @lamalibre/create-lamaste@4.3.1`) is completely non-interactive — it detects the environment, provisions everything, and prints a summary. All configuration happens through the browser-based onboarding wizard after installation.
96
+ The installer (`npx @lamalibre/create-lamaste@4.4.1`) is completely non-interactive — it detects the environment, provisions everything, and prints a summary. All configuration happens through the browser-based onboarding wizard after installation.
97
97
 
98
98
  ## Quick Reference
99
99
 
100
100
  | Item | Value |
101
101
  | -------------------- | ------------------------------- |
102
102
  | **Minimum VPS** | 512MB RAM, Ubuntu 24.04 |
103
- | **Install command** | `npx @lamalibre/create-lamaste@4.3.1` |
103
+ | **Install command** | `npx @lamalibre/create-lamaste@4.4.1` |
104
104
  | **Admin panel** | `https://<ip>:9292` (mTLS) |
105
105
  | **Auth for admin** | Client certificate (zero-login) |
106
106
  | **Auth for apps** | TOTP 2FA via Authelia |
@@ -108,5 +108,5 @@ The installer (`npx @lamalibre/create-lamaste@4.3.1`) is completely non-interact
108
108
  | **TLS certificates** | Let's Encrypt (auto-renewing) |
109
109
  | **State storage** | JSON files (no database) |
110
110
  | **RAM usage** | ~245MB total (all services) |
111
- | **npm package** | `@lamalibre/create-lamaste@4.3.1` |
111
+ | **npm package** | `@lamalibre/create-lamaste@4.4.1` |
112
112
  | **License** | Polyform Noncommercial 1.0.0 |
@@ -29,7 +29,7 @@ For the IP-based admin panel (`https://<ip>:9292`), there is no domain to verify
29
29
 
30
30
  ### When certificates are issued
31
31
 
32
- - **Self-signed + mTLS certs** — created during `npx @lamalibre/create-lamaste@4.3.1` installation
32
+ - **Self-signed + mTLS certs** — created during `npx @lamalibre/create-lamaste@4.4.1` installation
33
33
  - **Core Let's Encrypt certs** — issued during onboarding for `panel`, `auth`, and `tunnel` subdomains
34
34
  - **App Let's Encrypt certs** — issued when you create a new tunnel or a managed static site
35
35
  - **Custom-domain site certs** — issued when a custom-domain site's DNS is verified: one certificate lineage, named after the site's domain, covering the domain and every redirect alias (re-issued when aliases change)
@@ -82,7 +82,7 @@ The most critical scenario is the mTLS CA expiring, but it has a 10-year validit
82
82
 
83
83
  ### Let's Encrypt implementation
84
84
 
85
- Lamaste uses certbot with the nginx plugin for certificate issuance. The implementation lives in `@lamalibre/lamaste@4.3.1/server` (`packages/core/lib/src/server/certbot.ts`), wrapped by `packages/server/daemon/src/lib/certbot.js`.
85
+ Lamaste uses certbot with the nginx plugin for certificate issuance. The implementation lives in `@lamalibre/lamaste@4.4.1/server` (`packages/core/lib/src/server/certbot.ts`), wrapped by `packages/server/daemon/src/lib/certbot.js`.
86
86
 
87
87
  The panel runs as the unprivileged `lamaste` user and never runs `certbot` or `openssl` on Let's Encrypt files directly. It calls two root-owned wrapper scripts through sudo:
88
88
 
@@ -193,7 +193,7 @@ This three-step check prevents unnecessary certificate issuance and respects rat
193
193
 
194
194
  #### Custom-domain site certificate issuance
195
195
 
196
- A custom-domain static site may have redirect aliases (e.g. `www.myblog.net`). `issueSiteCert(fqdn, aliases, email)` in `@lamalibre/lamaste@4.3.1/server` keeps them on **one** lineage named after the primary domain:
196
+ A custom-domain static site may have redirect aliases (e.g. `www.myblog.net`). `issueSiteCert(fqdn, aliases, email)` in `@lamalibre/lamaste@4.4.1/server` keeps them on **one** lineage named after the primary domain:
197
197
 
198
198
  ```bash
199
199
  sudo /usr/local/sbin/lamaste-certbot issue admin@example.com myblog.net myblog.net www.myblog.net
@@ -25,7 +25,7 @@ You encounter mTLS during two moments:
25
25
 
26
26
  ### Importing the certificate
27
27
 
28
- After running `npx @lamalibre/create-lamaste@4.3.1`, the installer prints something like:
28
+ After running `npx @lamalibre/create-lamaste@4.4.1`, the installer prints something like:
29
29
 
30
30
  ```
31
31
  ╔══════════════════════════════════════════════════════════════╗
@@ -101,7 +101,7 @@ When connecting a machine to Lamaste using `lamaste-agent`, you should **not** u
101
101
  2. Click "Generate" and enter a label (e.g., `macbook-pro`)
102
102
  3. Save the displayed password — it cannot be retrieved later
103
103
  4. Download the `.p12` file
104
- 5. Share the `.p12` file and password with the agent machine through a secure channel, then install the agent there (`npm install -g @lamalibre/lamaste-agent@4.3.1`) and run `lamaste-agent setup` (an enrollment token avoids moving the key at all — see [Agent Setup](../02-guides/agent-setup.md))
104
+ 5. Share the `.p12` file and password with the agent machine through a secure channel, then install the agent there (`npm install -g @lamalibre/lamaste-agent@4.4.1`) and run `lamaste-agent setup` (an enrollment token avoids moving the key at all — see [Agent Setup](../02-guides/agent-setup.md))
105
105
 
106
106
  Agent certificates have capability-based access. By default, a new agent can only read tunnel configuration. Admins can grant additional capabilities per-agent from the panel UI:
107
107
 
@@ -163,7 +163,7 @@ Agents hold only the public key. The daemon fetches it, with the label the relay
163
163
 
164
164
  The owner's token is as good as the owner: the desktop app hands it to curl on stdin, never in a process's arguments, which other local users can read.
165
165
 
166
- Headers that only claim a caller — `X-SSL-Client-*`, `Remote-*` and the assertion itself — are removed from every request before a route or plugin sees it; `Remote-*` are set again only from a verified user assertion, so a plugin reading identity headers (`@lamalibre/lamaste-identity@4.3.1`) reads the relay's word. Whether a request needs a caller follows the route the daemon matched, not the URL: every route does except the health check, the plugin bundles and the SPA's static files, and so does a path no route matches under an installed plugin's name (a plugin may answer it with its own not-found handler). The claim headers are removed from `rawHeaders` too.
166
+ Headers that only claim a caller — `X-SSL-Client-*`, `Remote-*` and the assertion itself — are removed from every request before a route or plugin sees it; `Remote-*` are set again only from a verified user assertion, so a plugin reading identity headers (`@lamalibre/lamaste-identity@4.4.1`) reads the relay's word. Whether a request needs a caller follows the route the daemon matched, not the URL: every route does except the health check, the plugin bundles and the SPA's static files, and so does a path no route matches under an installed plugin's name (a plugin may answer it with its own not-found handler). The claim headers are removed from `rawHeaders` too.
167
167
 
168
168
  **What remains.** The relay's loopback is still the relay's trust boundary: the panel itself trusts the `X-SSL-Client-*` headers nginx sends to `127.0.0.1:3100`, so a process on the relay that can forge those can obtain an assertion as well — what it could do to agents before 4.3. With panel 2FA on it reaches further into agents than into the panel: forged (or stolen) admin-certificate headers no longer pass the panel's own management routes, but the agent-panel authorization is exempt from 2FA (the browser on `agent-<label>.<domain>` carries no 2FA cookie), so they still mint admin assertions — full control of every agent with a panel tunnel. Agent panels are guarded by the client certificate alone, as before; authenticating nginx to the panel is the relay-wide fix. An assertion binds the agent, the port, the method and the target, not the request body: a process on the agent machine that holds the daemon's port while the daemon is down receives the relay's requests, and could replay one with another body if the daemon comes back within the assertion's 65 seconds.
169
169
 
@@ -183,6 +183,36 @@ An agent half Lamaste installs runs on its agent as a service of its own, so som
183
183
 
184
184
  **What a compromised agent account can still do:** read and rewrite the plugin configs it already holds (`config` is not signed) — breaking the admin API of that agent half; run `status`; run a signed job it received when it likes before the job expires, or not at all; report results that are not true (the relay's view of what runs on the agent is the agent's report); stop its tunnel and its sync. **What it cannot:** run anything as root beyond those fixed operations; install, switch or remove anything the relay did not sign, or anything other than exactly what it signed; replay a job; pin a key (root only); read or write an agent half's data directory (0700, another account); act on a route another label or package owns. **A compromised relay** can do on its agents what its signature allows: install any `@lamalibre/` package from its registry at any version, with system packages from the agent's configured apt sources, running as a service account — never plugin code as root — and remove or purge the agent halves it owns.
185
185
 
186
+ #### 5e. Plugin settings and secrets, and the internal tunnel
187
+
188
+ An agent-hosted plugin's settings may hold secrets — a data provider's API key, a token for another service. The agent half uses them, so the agent half keeps them; the relay never does. See [Settings](../04-api-reference/agent-hosted-plugins.md#settings) for the contract.
189
+
190
+ **Anything that takes a tunnel's loopback port gets nothing and serves nothing.** The internal tunnel ends on loopback ports that every process on the relay and on the agent can reach — and take: on the relay while the hosting agent is offline (chisel listens only while it is connected), on the agent while an agent half restarts. Up to 4.3, a process holding such a port received Lamaste's calls in clear and could answer them as the agent half: pass the health probe, take a settings change with its secrets, replay a caller assertion with another body, or serve the plugin's `panel.js` into the panel's own document. On the agent, systemd now holds the port of an agent half Lamaste installs (a socket unit beside its service, passed to it as descriptor 3), so the port stays bound while the agent half restarts, is updated or is stopped ([App Host](../04-api-reference/app-host.md)); an agent half installed by hand binds its port itself. Whoever holds a port, three mechanisms, all keyed with the hosting's installation secret, leave it nothing to receive and nothing to serve ([Authentication between the relay and the agent half](../04-api-reference/agent-hosted-plugins.md#authentication-between-the-relay-and-the-agent-half)):
191
+
192
+ - **Body-bound assertions.** Lamaste's calls with a body sign the SHA-256 of the exact bytes (`bodySha256`); the agent half's hook and settings handlers require it, so an assertion lifted onto another body is refused (`wrong_body`).
193
+ - **Authenticated answers.** Every answer the agent half gives a verified request carries `X-Lamalibre-Responder`, an HMAC with the secret that verified the request over its nonce, the status and — for Lamaste's own calls — the SHA-256 of the exact answer body. The relay believes nothing without it: a settings call or a hook call fails as `unauthenticated`, the health probe counts the plugin's application as down, and the forwarder answers `502` before a status, header or byte of the answer reaches the client. Every `/admin/*` response of an agent half must carry it; core's handlers, `createHealthHandler` and `responderHeaderFor` produce it.
194
+ - **Sealed secrets.** Each secret of a settings change crosses the tunnel encrypted (AES-256-GCM, key derived with HKDF-SHA256 from the installation secret per plugin) and bound to the plugin, the call's nonce, the field and the revision; the agent half opens it with the secret that verified the call.
195
+
196
+ Agent halves built against `@lamalibre/lamaste@4.4.1` 4.3 must be rebuilt: one that does not sign its answers is down to the relay.
197
+
198
+ **The secret's path.** An administrator types the secret into the panel's form — a masked text input, not a password input (browsers offer to save a password input's value in their password managers whatever its `autocomplete` says), whose value never enters the page's state or its query cache and is read once when the form submits — or gives it to `lamaste-server plugins configure` (a masked prompt, or a JSON object on stdin; `--set` refuses a secret, since a command line is readable by other local users, and says to rotate it) or to the desktop app; both clients hand the request body to curl on stdin. The panel's route takes the body off the request before anything else, checks it — with messages that never contain a value — and sends the change through the plugin's internal tunnel to the agent half, `PUT /admin/settings` with a caller assertion naming Lamaste itself, each secret sealed to that call. The agent half opens it, writes it to `secrets.json` in its data directory — `0600`, its own service account's, atomically, refusing a link in the file's place — and answers with its state, which names the secrets that are set and when, never their values. On the relay the secret existed in clear only in the memory of that request; nothing keeps a reference to it afterwards.
199
+
200
+ **What the relay keeps.** A cache per plugin in `state.db` (`plugin_settings`): the non-secret values, `{ key: setAt }` for each secret that is set, and whether the plugin still needs configuration. The table has no column for a secret's value, and the relay parses every answer of the agent half into a fresh object of the contract's fields — a `setAt` must be an ISO 8601 UTC timestamp — so nothing else the agent half sends reaches it. When an update changes the settings schema, the cache is pruned in the transaction that installs the new schema: a value whose field became a secret is dropped, and a secret whose field became a plain value is no longer reported set. The panel can therefore show the settings while the agent is offline, and a backup of the relay holds none of these secrets.
201
+
202
+ **Where a secret never appears:** a log line, an error or validation message, an API response (a secret reads as `{ "set": true, "setAt": … }`), the audit log (`plugin.settings.updated` names keys only), a notification, an operation step, a process argument, a relay hook's input (relay hooks get the non-secret values only), the tunnel in clear, or any file on the relay. Hosting takes no settings, so no secret waits in the panel's memory through an operation that can take minutes. A field an update retypes is dropped, never converted: a secret whose field becomes a string never lands in `settings.json` or in the relay's cache. Such an update always waits for an administrator's approval (`settings.secret-to-plain` in `pendingUpdate.approvalRequired`), whatever its code digest and whether or not auto-approve is on — what is typed into the field next is kept on the relay and shown in clear — and the panel and the CLI warn about it in the update's preview; a plain string field whose name looks like a credential carries a hint to use a secret field.
203
+
204
+ **Only Lamaste reads and writes settings.** The forwarder reserves every path whose segment after `/admin` — percent-decoded until it is stable (at most three rounds; anything that still decodes, or does not, is reserved), lower-cased and stripped to `a-z0-9` — starts with `settings` or `hooks`, so no spelling a framework's router might resolve (`/admin/Settings`, `/admin/%2573ettings`, `/admin/settings.json`) reaches the agent half; and the agent half's settings handler accepts only the caller `lamaste` (`401` for a bad assertion, `403` for an administrator or an agent). No forwarded caller, administrator or agent with the plugin's capability, can read the settings or change them past the panel's checks, and the relay's cache cannot drift from the agent half.
205
+
206
+ **Changes made outside Lamaste are reported.** Because only Lamaste writes settings, every revision of the agent half's should be one Lamaste wrote. The relay remembers the last revision it wrote or adopted; a read — on every live read, when the plugin comes up, and once when the panel starts — that finds another one records `plugin.settings.changed-outside-lamaste` in the audit log with the names of the settings that differ (never a value) and the revisions, warns the administrators, and adopts it, so each change is reported once. A change whose answer was lost (a timeout) is remembered by key names, so finding it stored is recorded as the administrator's change, not as an outside one. This is how a change made with the installation secret on the agent — see what remains, below — or files put back there becomes visible.
207
+
208
+ **The agent half's answers.** When the agent half refuses a change field by field (`422`), the relay passes on only messages Lamaste's own validation produces, matched exactly against its fixed and templated messages (`normalizeSettingsErrorMessage`), and only under keys of the installed schema; anything else reads `Invalid value`. Names a schema does not know are counted (`2 unknown settings`), never repeated, by the panel, the agent half and the CLI alike: a token pasted where a key belongs must not come back.
209
+
210
+ **A manifest's regular expressions and text.** A string field's `pattern` comes from the plugin's manifest. It runs in the administrator's browser and in the agent half — never in the panel process, and never in `lamaste-server`, which runs as root. The relay validates manifests at install, at update and at every start, so it only compiles a pattern and never tests even the field's own default against it (the agent half does, when it reads its manifest): a pathological expression can neither stall the panel nor run as root. Text a manifest shows an administrator — labels, descriptions, options, string defaults, patterns — refuses control characters and bidirectional overrides, and `lamaste-server` strips them from everything a manifest, an agent half or the panel supplies before printing it.
211
+
212
+ **Plugin admin bundles share the panel's document.** A plugin's `panel.js` comes from its agent half and runs in the panel's own page, with the panel's origin. The forwarder serves it only when the answer authenticates itself, strips `Set-Cookie`, `Service-Worker-Allowed` and `Clear-Site-Data` from every answer and refuses a request for a service worker's script, so an answer cannot install a service worker over the panel or wipe its storage. The bundle's own code is not confined, though: it can do in the page what the administrator can. That is acceptable while every plugin comes from the `@lamalibre/` scope; isolating plugin UIs in sandboxed frames is its own slice, before any third-party plugin is installable.
213
+
214
+ **What remains.** The installation secret is held by the relay's panel (`plugin-hostings.json`, `0600`, `lamaste`), by the hosting **agent's account** (its plugin config, `0600`) and by the **agent half's own account** (`/etc/lamalibre/apps/<route>/plugin-config.json`, `0600`). Whoever holds one of them can sign as Lamaste and answer as the agent half. The agent account runs the tunnel's client, so it can route the tunnel to a listener of its own and open the sealed secrets of a change sent then; any holder can read and change the settings through the agent half's handler — though never read a secret back from it, since no answer carries one, and a change made that way is reported as made outside Lamaste. Relay-signed assertions with a key the agent half holds alone would be the next step; until then the agent account and the agent half's account are inside the secrets' trust boundary. The agent half — the plugin's own code — holds its secrets in memory and in its file and uses them as it likes; its account and unit (5d above) keep them from other accounts on the agent, but root on the agent can read them, and they stay with the agent half's retained data when it is removed without purge. On the relay, a secret is readable in clear for the duration of a change by whoever can read the panel process's memory (root, or the `lamaste` account itself). None of the processes that hold these secrets writes a core dump: the units of the panel, Gatekeeper, the hook runner and every agent half set `LimitCORE=0`.
215
+
186
216
  #### 6. TOTP 2FA for app access
187
217
 
188
218
  Visitors to your tunneled apps authenticate through Authelia with a password and a TOTP code from their phone. See [Authentication](authentication.md) for full details.
@@ -442,6 +472,8 @@ Authelia is reachable from the internet (`auth.<domain>`), so it runs as neither
442
472
 
443
473
  The panel server binds to localhost in its Fastify configuration.
444
474
 
475
+ The units of the panel (`lamalibre-lamaste-serverd`), Gatekeeper and the hook runner (`lamalibre-lamaste-hooks@.service`) — like every agent half's unit on agents ([App Host](../04-api-reference/app-host.md)) — set `LimitCORE=0`, soft and hard: no core dump of a process that holds the CA and signing keys, sessions, installation secrets or a settings secret in transit — or, for a hook, the application data it inspects — and the process cannot raise the limit.
476
+
445
477
  nginx is the only service with a public-facing socket. It listens on:
446
478
 
447
479
  - `0.0.0.0:80`, which only redirects to HTTPS (and answers Let's Encrypt HTTP-01 challenges while certbot runs)
@@ -475,6 +507,7 @@ Sensitive files use restrictive permissions:
475
507
  | `/etc/sudoers.d/lamaste-apphost` | `440` | The app host rule (agent machine) |
476
508
  | `/etc/lamalibre/apps/<route>/plugin-config.json` | `600` | An agent half's port and secret; its account |
477
509
  | `/var/lib/lamalibre/apps/<route>/` | `700` | An agent half's data; its account |
510
+ | `/var/lib/lamalibre/apps/<route>/secrets.json`, `settings.json` | `600` | A plugin's settings and secrets; its account |
478
511
  | `/var/lib/lamalibre/apps/.jobs/`, `.trash/` | `700` | Signed jobs that ran; purged data (root) |
479
512
 
480
513
  Mode `600` means only the file owner can read or write. Mode `640` adds read access for the file's group, `660` also write access. Mode `700` means only the directory owner can list, read, or modify contents. See [Configuration Files](../06-reference/config-files.md#file-permissions-table) for the owner of every directory.
@@ -592,6 +625,9 @@ Configuration files that are read live by services (like Authelia's `users.yml`)
592
625
  | `packages/agent/cli/scripts/lamaste-apphost` | The app host helper (root, Node.js built-ins only) |
593
626
  | `packages/agent/cli/src/lib/apphost-setup.js` | Root-owned install check, sudoers rule, relay key pins |
594
627
  | `packages/server/daemon/src/lib/agent-jobs.js` | Agent jobs; app jobs signed when created |
628
+ | `packages/core/lib/src/plugin-settings.ts` | Settings schema, validation without values, wire types |
629
+ | `packages/core/lib/src/agent/plugin-settings-store.ts` | The agent half's settings files and `/admin/settings` |
630
+ | `packages/server/daemon/src/lib/plugin-settings.js` | Settings through the tunnel; the cache without secrets |
595
631
 
596
632
  ## Quick Reference
597
633
 
@@ -614,6 +650,7 @@ Configuration files that are read live by services (like Authelia's `users.yml`)
614
650
  | Agent daemon auth | Relay assertions (Ed25519), owner token | Callers forged on an agent's loopback |
615
651
  | Agent root helper | Relay-signed app jobs, pinned key | Root actions the relay did not sign |
616
652
  | Agent half sandbox | Own account, hardened systemd unit | Plugin code as root |
653
+ | Plugin secrets | Agent half only, through the tunnel | Plugin secrets at rest on the relay |
617
654
  | App auth | Authelia TOTP 2FA | Unauthorized app access |
618
655
  | Service isolation | `127.0.0.1` binding | Direct access to internal services |
619
656
  | File permissions | `chmod 600` | Unauthorized secret access |
@@ -264,9 +264,9 @@ The integration flow:
264
264
  }
265
265
  ```
266
266
 
267
- ### Client SDK (`@lamalibre/lamaste-tickets@4.3.1`)
267
+ ### Client SDK (`@lamalibre/lamaste-tickets@4.4.1`)
268
268
 
269
- The `@lamalibre/lamaste-tickets@4.3.1` package is a TypeScript SDK that provides the client-side ticket lifecycle for plugins and agents. It uses `undici` for HTTP with mTLS dispatcher support and has no other runtime dependencies.
269
+ The `@lamalibre/lamaste-tickets@4.4.1` package is a TypeScript SDK that provides the client-side ticket lifecycle for plugins and agents. It uses `undici` for HTTP with mTLS dispatcher support and has no other runtime dependencies.
270
270
 
271
271
  The SDK exports three main classes:
272
272
 
@@ -144,7 +144,7 @@ On the API side the same rule holds: `GET /api/tunnels/agent-config` returns onl
144
144
 
145
145
  ### Client configuration
146
146
 
147
- The Chisel client runs as a user-level service managed by `lamaste-agent` (and `lamaste-agentd`): a LaunchAgent plist on macOS, a systemd **user** unit on Linux. Both are generated by one implementation in `@lamalibre/lamaste@4.3.1/agent`. The client command looks like:
147
+ The Chisel client runs as a user-level service managed by `lamaste-agent` (and `lamaste-agentd`): a LaunchAgent plist on macOS, a systemd **user** unit on Linux. Both are generated by one implementation in `@lamalibre/lamaste@4.4.1/agent`. The client command looks like:
148
148
 
149
149
  ```bash
150
150
  chisel client \
@@ -208,7 +208,7 @@ location / {
208
208
 
209
209
  ### Concurrency and locking
210
210
 
211
- Every tunnel workflow — create, delete, toggle, assign, reconfigure, the combined `PATCH`, releasing a revoked agent's tunnels, and startup reconciliation — runs under one tunnel lock (`withTunnelLock` in `@lamalibre/lamaste@4.3.1/server`'s `tunnels.ts`), with its validation inside the lock. Two concurrent requests therefore cannot both pass a uniqueness check for the same subdomain or port. Authfile renders are additionally serialized with a keyed promise-chain mutex in `chisel-users.ts`, so enrollments and credential rotations never interleave authfile writes with tunnel changes.
211
+ Every tunnel workflow — create, delete, toggle, assign, reconfigure, the combined `PATCH`, releasing a revoked agent's tunnels, and startup reconciliation — runs under one tunnel lock (`withTunnelLock` in `@lamalibre/lamaste@4.4.1/server`'s `tunnels.ts`), with its validation inside the lock. Two concurrent requests therefore cannot both pass a uniqueness check for the same subdomain or port. Authfile renders are additionally serialized with a keyed promise-chain mutex in `chisel-users.ts`, so enrollments and credential rotations never interleave authfile writes with tunnel changes.
212
212
 
213
213
  ### Startup reconciliation
214
214
 
@@ -223,7 +223,7 @@ It **fails closed**: if the authfile cannot be established, Chisel is stopped **
223
223
 
224
224
  ### Installation
225
225
 
226
- On the server, Chisel is installed by `npx @lamalibre/create-lamaste@4.3.1` — as root, together with its hardened systemd unit (`User=nobody`, `Group=lamaste-chisel`, `NoNewPrivileges`, `ProtectSystem=strict`, empty `CapabilityBoundingSet`) — and kept at the pinned release by every redeploy. The panel never installs a binary or writes the unit; onboarding only checks the binary exists, creates the server key and authfile, and starts the service. Both the server installer and the agents download the pinned release (`CHISEL_RELEASE` in `@lamalibre/lamaste@4.3.1`'s `constants.ts`) from its fixed URL, with no GitHub API lookup and no "latest":
226
+ On the server, Chisel is installed by `npx @lamalibre/create-lamaste@4.4.1` — as root, together with its hardened systemd unit (`User=nobody`, `Group=lamaste-chisel`, `NoNewPrivileges`, `ProtectSystem=strict`, empty `CapabilityBoundingSet`) — and kept at the pinned release by every redeploy. The panel never installs a binary or writes the unit; onboarding only checks the binary exists, creates the server key and authfile, and starts the service. Both the server installer and the agents download the pinned release (`CHISEL_RELEASE` in `@lamalibre/lamaste@4.4.1`'s `constants.ts`) from its fixed URL, with no GitHub API lookup and no "latest":
227
227
 
228
228
  ```
229
229
  https://github.com/jpillora/chisel/releases/download/v1.12.0/chisel_1.12.0_<os>_<arch>.gz
@@ -320,7 +320,7 @@ sudo systemctl restart chisel
320
320
 
321
321
  ```bash
322
322
  # Install globally, then set up the agent (interactive)
323
- npm install -g @lamalibre/lamaste-agent@4.3.1
323
+ npm install -g @lamalibre/lamaste-agent@4.4.1
324
324
  lamaste-agent setup --label <label>
325
325
 
326
326
  # Apply tunnel changes now (the sync timer does it within 30 s anyway)
@@ -59,7 +59,7 @@ The token is single-use and expires after 10 minutes. `tunnels:read` is enough f
59
59
  Install the agent **globally** first:
60
60
 
61
61
  ```bash
62
- npm install -g @lamalibre/lamaste-agent@4.3.1
62
+ npm install -g @lamalibre/lamaste-agent@4.4.1
63
63
  ```
64
64
 
65
65
  A global install is required, not a convenience. Setup installs a sync timer (see [How tunnel changes reach the agent](#how-tunnel-changes-reach-the-agent)) that runs the installed `lamaste-agent` every 30 seconds for as long as the agent exists. An `npx` copy lives in npm's cache, which npm may clear at any time — the timer would silently stop. `setup` and `update` therefore refuse to run from `npx`, and they check this **before** an enrollment token is spent. For an installation npm does not manage, set `LAMALIBRE_LAMASTE_AGENT_CLI_PATH` to the absolute path of the `lamaste-agent` script the timer should run.
@@ -117,7 +117,7 @@ The relay only lets an agent open the ports of the enabled tunnels it carries, a
117
117
  4. The service definition lists exactly the tunnels the relay grants this agent.
118
118
  5. The client runs when there is something to carry, and is stopped when the agent carries no tunnel or the operator stopped it.
119
119
 
120
- When everything already matches, a run costs one panel request and changes nothing. After converging, a run also reports the agent's host facts when they changed and runs the jobs the relay listed for the plugins this agent hosts — lifecycle hook calls, and installing, switching or removing an agent half ([App Host](../04-api-reference/app-host.md)); an install may take up to 10 minutes, so systemd allows a run 20 (`TimeoutStartSec=20min`). The timer runs it:
120
+ When everything already matches, a run costs one panel request and changes nothing. After converging, a run also reports the agent's host facts when they changed or the relay does not hold them (the agent-config answer's `hostFactsHash`, see [Host facts](../04-api-reference/agent-hosted-plugins.md#host-facts)) and runs the jobs the relay listed for the plugins this agent hosts — lifecycle hook calls, and installing, switching or removing an agent half ([App Host](../04-api-reference/app-host.md)); an install may take up to 10 minutes, so systemd allows a run 20 (`TimeoutStartSec=20min`). The timer runs it:
121
121
 
122
122
  | Platform | Units | Schedule |
123
123
  | -------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
@@ -148,7 +148,7 @@ Each agent authenticates to the relay with its own chisel credential, stored in
148
148
  Upgrade agents **before** the server. Agents from before this version reject the new shape of the relay's Chisel arguments; a current agent works against an older server, keeping its credential until the server offers rotation.
149
149
 
150
150
  ```bash
151
- npm install -g @lamalibre/lamaste-agent@4.3.1
151
+ npm install -g @lamalibre/lamaste-agent@4.4.1
152
152
  lamaste-agent update
153
153
  ```
154
154
 
@@ -172,7 +172,7 @@ lamaste-agent uninstall --label <l> # stop and remove one agent, including its
172
172
  To let the panel install the agent halves of app plugins on this machine — their accounts, units and directories — enable the app host helper once, from a root-owned install:
173
173
 
174
174
  ```bash
175
- sudo npm install -g @lamalibre/lamaste-agent@4.3.1
175
+ sudo npm install -g @lamalibre/lamaste-agent@4.4.1
176
176
  sudo lamaste-agent apphost enable # the agent runs as the user who ran sudo
177
177
  lamaste-agent apphost status # helper, pinned relay keys, installed agent halves
178
178
  sudo lamaste-agent apphost pin # after the relay rotated its signing key
@@ -184,7 +184,7 @@ The agent reports it on its next sync, and the panel can then host plugins whose
184
184
 
185
185
  | Symptom | Cause and fix |
186
186
  | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
187
- | `setup` says the agent must be installed globally | It was run through `npx`. Run `npm install -g @lamalibre/lamaste-agent@4.3.1`, then `lamaste-agent setup ...` again. The enrollment token was not spent. |
187
+ | `setup` says the agent must be installed globally | It was run through `npx`. Run `npm install -g @lamalibre/lamaste-agent@4.4.1`, then `lamaste-agent setup ...` again. The enrollment token was not spent. |
188
188
  | Log shows a TLS / x509 error | `tunnel.<domain>` does not present a valid certificate for its name. Check the relay's certificate (`Certificates` page) and that the agent's clock is correct. |
189
189
  | Log shows authentication failed | The credential was rotated on the panel. The next sync picks it up; `lamaste-agent chisel refresh-credential` applies it now. |
190
190
  | Log shows `access denied` for a remote | The relay no longer grants this agent that port: the tunnel was disabled, deleted, or moved to another agent. The next sync drops it. If it persists, check `lamaste-agent status` — the sync timer may not be running. |
@@ -196,7 +196,7 @@ The agent reports it on its next sync, and the panel can then host plugins whose
196
196
  | New tunnel returns 502 | The agent has not synced yet (up to ~30 s), or nothing listens on `127.0.0.1:<port>` on the agent. Run `lamaste-agent update` to apply at once. |
197
197
  | Upload fails with 413 | The request is larger than the tunnel's body limit. Raise **Largest request body** on the tunnel (`maxBodySizeMb`). |
198
198
  | `uninstall` refuses: agent halves are installed | Agent halves run here for this agent. Unhost or uninstall those plugins on the panel (the next sync removes them), or `sudo lamaste-agent apphost disable --force` (data is kept). |
199
- | `apphost enable` says the install is not root-owned | Root installs the helper only from code no other user can change: `sudo npm install -g @lamalibre/lamaste-agent@4.3.1`, then `sudo lamaste-agent apphost enable` from that install. |
199
+ | `apphost enable` says the install is not root-owned | Root installs the helper only from code no other user can change: `sudo npm install -g @lamalibre/lamaste-agent@4.4.1`, then `sudo lamaste-agent apphost enable` from that install. |
200
200
  | `apphost enable` says the helper serves another user | App hosting serves one OS user per machine. Unhost or uninstall the plugins that user's agents host (`sudo lamaste-agent apphost status` lists their agent halves), then `sudo lamaste-agent apphost enable --user <name> --force`. |
201
201
  | `apphost pin` says a label is not an agent of the user | Root pins only labels the agent user's registry lists. Pin as the user the agent runs as (`--user <name>`; `--user root` for an agent running as root). |
202
202
  | Hosting refused: the helper trusts another relay key | The relay's signing key was replaced, or the agent enrolled again. Run `sudo lamaste-agent apphost pin`; compare the key id with the relay's ([App Host](../04-api-reference/app-host.md#pinning-the-relay-key)). |
@@ -196,7 +196,7 @@ The admin certificate (`CN=admin`) has unrestricted access to all panel endpoint
196
196
 
197
197
  ### Distribute to the Agent Machine
198
198
 
199
- Send the `.p12` file and password to the agent machine (macOS or Linux) securely, and install the agent there with `npm install -g @lamalibre/lamaste-agent@4.3.1` and run `lamaste-agent setup --label <label>` — or import it into the Desktop App. An enrollment token is preferable where possible, because the private key is then generated on the agent and never travels. See [Agent Setup](agent-setup.md) for details.
199
+ Send the `.p12` file and password to the agent machine (macOS or Linux) securely, and install the agent there with `npm install -g @lamalibre/lamaste-agent@4.4.1` and run `lamaste-agent setup --label <label>` — or import it into the Desktop App. An enrollment token is preferable where possible, because the private key is then generated on the agent and never travels. See [Agent Setup](agent-setup.md) for details.
200
200
 
201
201
  ### Update Capabilities
202
202
 
@@ -293,7 +293,7 @@ Revocation is immediate — the certificate serial is added to a revocation list
293
293
 
294
294
  ### mTLS Rotation Internals
295
295
 
296
- Admin certificate rotation lives only in `lamaste-server reset-admin` (`packages/server/cli/src/commands/reset-admin.js`), run as root on the server. The panel's `rotateClientCert()` in `lib/mtls.js` is a stub that returns `503` with that instruction; `@lamalibre/lamaste@4.3.1/server` no longer exports a rotation function. The PKI directory belongs to `lamaste`, so `reset-admin` runs every file operation inside it (`openssl genrsa`/`req`/`x509 -req`/`pkcs12`, `cp`, `chmod`) as `lamaste`, and writes `panel.json` and `revoked.json` as fresh files renamed into place — root never writes through a path the panel could have replaced with a symlink.
296
+ Admin certificate rotation lives only in `lamaste-server reset-admin` (`packages/server/cli/src/commands/reset-admin.js`), run as root on the server. The panel's `rotateClientCert()` in `lib/mtls.js` is a stub that returns `503` with that instruction; `@lamalibre/lamaste@4.4.1/server` no longer exports a rotation function. The PKI directory belongs to `lamaste`, so `reset-admin` runs every file operation inside it (`openssl genrsa`/`req`/`x509 -req`/`pkcs12`, `cp`, `chmod`) as `lamaste`, and writes `panel.json` and `revoked.json` as fresh files renamed into place — root never writes through a path the panel could have replaced with a symlink.
297
297
 
298
298
  The PKCS12 bundle uses legacy encryption settings (`-keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg sha1`) because newer OpenSSL defaults produce files that macOS Keychain Access cannot import.
299
299
 
@@ -14,7 +14,7 @@ Before you start, make sure you have:
14
14
 
15
15
  | Requirement | Details |
16
16
  | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
17
- | **Desktop app installed** | `npx @lamalibre/create-lamaste-desktop@4.3.1` ([setup guide](desktop-app-setup.md)) |
17
+ | **Desktop app installed** | `npx @lamalibre/create-lamaste-desktop@4.4.1` ([setup guide](desktop-app-setup.md)) |
18
18
  | **DigitalOcean account** | A free account at [cloud.digitalocean.com](https://cloud.digitalocean.com). **If you have other infrastructure on DO, create a dedicated team first** (see below) |
19
19
  | **Payment method** | A credit card or PayPal on file in DigitalOcean (required to create droplets) |
20
20
  | **Domain name** | Optional for initial setup — you can add a domain later through the panel |
@@ -221,7 +221,7 @@ The wizard shows up to 12 steps with live progress indicators. Each step shows a
221
221
  | **Waiting for boot** | Polls DigitalOcean until the droplet has a public IP and is ready (up to 5 minutes) |
222
222
  | **Setting up DNS records** | Creates A and wildcard A records in DigitalOcean DNS (only if a domain was selected in the Domain step) |
223
223
  | **Connecting via SSH** | Establishes an SSH connection using the temporary key |
224
- | **Installing Lamaste** | Runs `npx @lamalibre/create-lamaste@4.3.1` on the droplet (up to 10 minutes) |
224
+ | **Installing Lamaste** | Runs `npx @lamalibre/create-lamaste@4.4.1` on the droplet (up to 10 minutes) |
225
225
  | **Retrieving credentials** | Downloads the admin certificate (`.p12` file) and reads the panel's TLS key pin from the droplet |
226
226
  | **Enrolling admin certificate** | Imports the certificate into your OS credential store |
227
227
  | **Saving configuration** | Writes the server entry to `~/.lamalibre/lamaste/servers.json` |
@@ -315,7 +315,7 @@ If you already have a Lamaste server set up (via the manual SSH method), you can
315
315
 
316
316
  The app checks that the panel is reachable before adding it. The server is added with `active: false` — click **Set Active** on its card to start using it.
317
317
 
318
- > **Note:** Adding an existing server registers it in the app but does not configure authentication. You will still need to set up your agent certificate separately using `lamaste-agent setup` (after `npm install -g @lamalibre/lamaste-agent@4.3.1`) or by importing a certificate manually.
318
+ > **Note:** Adding an existing server registers it in the app but does not configure authentication. You will still need to set up your agent certificate separately using `lamaste-agent setup` (after `npm install -g @lamalibre/lamaste-agent@4.4.1`) or by importing a certificate manually.
319
319
 
320
320
  ---
321
321
 
@@ -26,7 +26,7 @@ The Lamaste Desktop app is a native application (built with Tauri) that wraps th
26
26
  Run the installer:
27
27
 
28
28
  ```bash
29
- npx @lamalibre/create-lamaste-desktop@4.3.1
29
+ npx @lamalibre/create-lamaste-desktop@4.4.1
30
30
  ```
31
31
 
32
32
  The installer:
@@ -56,11 +56,11 @@ After the app launches, it shows a setup screen with two options:
56
56
  Install the agent globally and run its setup command:
57
57
 
58
58
  ```bash
59
- npm install -g @lamalibre/lamaste-agent@4.3.1
59
+ npm install -g @lamalibre/lamaste-agent@4.4.1
60
60
  lamaste-agent setup --label my-server
61
61
  ```
62
62
 
63
- The agent must be a global install — setup installs a sync timer that runs it every 30 seconds to pick up tunnel changes, and refuses to run from `npx`. (When the app sets up an agent itself, it installs `@lamalibre/lamaste-agent@4.3.1` globally for you.) The `--label` flag names this agent connection (used for multi-agent support). This command connects to your VPS panel using the agent certificate and configures the local Chisel client. During setup, the client certificate and key are extracted from the P12 bundle for mTLS client authentication. Once setup completes, the app detects the configuration and switches to the main interface.
63
+ The agent must be a global install — setup installs a sync timer that runs it every 30 seconds to pick up tunnel changes, and refuses to run from `npx`. (When the app sets up an agent itself, it installs `@lamalibre/lamaste-agent@4.4.1` globally for you.) The `--label` flag names this agent connection (used for multi-agent support). This command connects to your VPS panel using the agent certificate and configures the local Chisel client. During setup, the client certificate and key are extracted from the P12 bundle for mTLS client authentication. Once setup completes, the app detects the configuration and switches to the main interface.
64
64
 
65
65
  **Option B: Create a new server**
66
66
 
@@ -72,7 +72,7 @@ The desktop app has two modes, toggled via a pill switch in the sidebar header.
72
72
 
73
73
  ### Agent Mode (default)
74
74
 
75
- Agent mode provides local agent management. The agent-mode pages (Dashboard, Tunnels, Services, Plugins, Logs, Settings) are imported from the shared `@lamalibre/lamaste-agent-ui@4.3.1` package. The landing page is the **Agents** list, showing all configured agents with their connection status. Click an agent to drill into its management pages:
75
+ Agent mode provides local agent management. The agent-mode pages (Dashboard, Tunnels, Services, Plugins, Logs, Settings) are imported from the shared `@lamalibre/lamaste-agent-ui@4.4.1` package. The landing page is the **Agents** list, showing all configured agents with their connection status. Click an agent to drill into its management pages:
76
76
 
77
77
  - **Agents** (landing) — list of all configured agents with start/stop controls and status
78
78
  - **Dashboard** — per-agent connection status, Chisel version, start/stop/restart controls
@@ -84,7 +84,7 @@ Agent mode provides local agent management. The agent-mode pages (Dashboard, Tun
84
84
 
85
85
  ### Server Mode
86
86
 
87
- Server mode provides the full admin panel — the same management pages available in the browser-based panel UI. These pages are imported from the shared `@lamalibre/lamaste-server-ui@4.3.1` package:
87
+ Server mode provides the full admin panel — the same management pages available in the browser-based panel UI. These pages are imported from the shared `@lamalibre/lamaste-server-ui@4.4.1` package:
88
88
 
89
89
  - **Dashboard** — system stats (CPU, RAM, disk, uptime) + service health
90
90
  - **Tunnels** — tunnel CRUD, carrying agent, access mode, body limit
@@ -93,7 +93,7 @@ Server mode provides the full admin panel — the same management pages availabl
93
93
  - **Users** — Authelia user CRUD + TOTP enrollment
94
94
  - **Certificates** — Let's Encrypt + mTLS cert listing + renewal + rotation
95
95
  - **Tickets** — agent-to-agent authorization scope and session management
96
- - **Plugins** — plugin management + push install UI
96
+ - **Plugins** — plugin management + push install UI + agent-hosted plugins' hosting, retained data and settings (secrets are sent to the panel in the request body on curl's stdin, never as arguments)
97
97
  - **Logs** — live journald log streaming
98
98
  - **Settings** — panel configuration, 2FA, admin auth mode
99
99
 
@@ -170,7 +170,7 @@ Stopping an agent's tunnels from the app is remembered: the agent's sync timer k
170
170
  Run the installer again to get the latest version:
171
171
 
172
172
  ```bash
173
- npx @lamalibre/create-lamaste-desktop@4.3.1
173
+ npx @lamalibre/create-lamaste-desktop@4.4.1
174
174
  ```
175
175
 
176
176
  If a new release is available, it downloads and installs the update. The previous version is replaced.
@@ -203,9 +203,9 @@ Deleting `~/.lamalibre/lamaste/` by hand instead would leave the agents' service
203
203
 
204
204
  | Action | Command / Location |
205
205
  | -------------------- | ------------------------------------------------------------------------------------ |
206
- | **Install** | `npx @lamalibre/create-lamaste-desktop@4.3.1` |
207
- | **Update** | `npx @lamalibre/create-lamaste-desktop@4.3.1` |
208
- | **Agent setup** | `npm install -g @lamalibre/lamaste-agent@4.3.1`, then `lamaste-agent setup --label <name>` |
206
+ | **Install** | `npx @lamalibre/create-lamaste-desktop@4.4.1` |
207
+ | **Update** | `npx @lamalibre/create-lamaste-desktop@4.4.1` |
208
+ | **Agent setup** | `npm install -g @lamalibre/lamaste-agent@4.4.1`, then `lamaste-agent setup --label <name>` |
209
209
  | **App location** | `/Applications/Lamaste.app` (macOS) |
210
210
  | **Agent registry** | `~/.lamalibre/lamaste/agents.json` |
211
211
  | **Per-agent data** | `~/.lamalibre/lamaste/agents/<label>/` |
@@ -216,7 +216,7 @@ Deleting `~/.lamalibre/lamaste/` by hand instead would leave the agents' service
216
216
  | **Chisel logs** | `~/.lamalibre/lamaste/agents/<label>/logs/chisel.log` |
217
217
  | **Cloud tokens** | OS credential store (`com.lamalibre.cloud`) |
218
218
  | **P12 passwords** | OS credential store (`com.lamalibre.lamaste.server`) |
219
- | **npm package** | `@lamalibre/create-lamaste-desktop@4.3.1` |
219
+ | **npm package** | `@lamalibre/create-lamaste-desktop@4.4.1` |
220
220
 
221
221
  ### Related Documentation
222
222
 
@@ -62,7 +62,7 @@ Execute the Lamaste installer:
62
62
 
63
63
  ```bash
64
64
  apt install -y npm
65
- npx @lamalibre/create-lamaste@4.3.1
65
+ npx @lamalibre/create-lamaste@4.4.1
66
66
  ```
67
67
 
68
68
  The installer displays a confirmation banner before making any changes:
@@ -90,7 +90,7 @@ The installer displays a confirmation banner before making any changes:
90
90
  Press Enter to continue or Ctrl+C to abort...
91
91
  ```
92
92
 
93
- Press **Enter** to proceed. To skip the confirmation prompt, use `npx @lamalibre/create-lamaste@4.3.1 --yes`.
93
+ Press **Enter** to proceed. To skip the confirmation prompt, use `npx @lamalibre/create-lamaste@4.4.1 --yes`.
94
94
 
95
95
  ### 4. What the Installer Does
96
96
 
@@ -380,7 +380,7 @@ The service includes security hardening: `ProtectHome=true`, `PrivateTmp=true`,
380
380
 
381
381
  | Item | Value |
382
382
  | ------------------------ | ------------------------------------------------------------ |
383
- | **Install command** | `npx @lamalibre/create-lamaste@4.3.1` |
383
+ | **Install command** | `npx @lamalibre/create-lamaste@4.4.1` |
384
384
  | **Minimum VPS** | Ubuntu 24.04, 512 MB RAM |
385
385
  | **Required ports** | 22 (SSH), 80 (HTTP/Let's Encrypt), 443 (HTTPS), 9292 (panel) |
386
386
  | **Certificate location** | `/etc/lamalibre/lamaste/pki/client.p12` |
@@ -113,7 +113,7 @@ Chisel is the tunneling engine. The installer already put the pinned Chisel rele
113
113
 
114
114
  Authelia provides two-factor authentication for your tunneled apps. The installer already put the pinned Authelia release, its systemd unit and its `lamaste-authelia` service account in place; the provisioner checks the binary is there, writes the configuration file (using your domain), creates the initial admin user with a random password, and starts the service. Authelia listens on `127.0.0.1:9091`.
115
115
 
116
- Onboarding downloads nothing. If either task fails with "… is not installed. Run `npx @lamalibre/create-lamaste@4.3.1` on the server to repair the installation.", re-run the installer on the server (it is idempotent) and start provisioning again.
116
+ Onboarding downloads nothing. If either task fails with "… is not installed. Run `npx @lamalibre/create-lamaste@4.4.1` on the server to repair the installation.", re-run the installer on the server (it is idempotent) and start provisioning again.
117
117
 
118
118
  Authelia uses **bcrypt** for password hashing (not argon2id) because argon2id uses approximately 93 MB per hash, which causes out-of-memory kills on a 512 MB droplet.
119
119
 
@@ -213,7 +213,7 @@ Each provisioning task calls library functions in `packages/lamaste-serverd/src/
213
213
 
214
214
  The DNS check resolves these hostnames using Node's `dns.resolve4()`:
215
215
 
216
- 1. `panel.example.com`, `auth.example.com`, `tunnel.example.com` — must resolve to the server IP (required; `CORE_SUBDOMAINS` in `@lamalibre/lamaste@4.3.1`)
216
+ 1. `panel.example.com`, `auth.example.com`, `tunnel.example.com` — must resolve to the server IP (required; `CORE_SUBDOMAINS` in `@lamalibre/lamaste@4.4.1`)
217
217
  2. `test-lamaste-check.example.com` — tests wildcard resolution (optional)
218
218
  3. `example.com` — reported, not required
219
219
 
@@ -27,7 +27,7 @@ Using the desktop app's cloud provisioning wizard:
27
27
 
28
28
  - Enter your DigitalOcean API token
29
29
  - Select a region and droplet size
30
- - The wizard calls `@lamalibre/lamaste-cloud@4.3.1` to create the droplet
30
+ - The wizard calls `@lamalibre/lamaste-cloud@4.4.1` to create the droplet
31
31
  - Progress streams back as NDJSON events in the desktop UI
32
32
  - Complete onboarding in the browser panel
33
33
 
@@ -96,7 +96,7 @@ The Sync server now runs as a local service on the Mac. It operates independentl
96
96
 
97
97
  ### 5. Register Sync Scopes and Instance on Lamaste
98
98
 
99
- The Sync server detects that the Mac has a Lamaste agent certificate. Using that cert (mTLS), it registers a ticket scope and instance with the Lamaste panel. This is handled automatically by `TicketInstanceManager` from `@lamalibre/lamaste-tickets@4.3.1` — the admin does not need to do anything.
99
+ The Sync server detects that the Mac has a Lamaste agent certificate. Using that cert (mTLS), it registers a ticket scope and instance with the Lamaste panel. This is handled automatically by `TicketInstanceManager` from `@lamalibre/lamaste-tickets@4.4.1` — the admin does not need to do anything.
100
100
 
101
101
  ```mermaid
102
102
  sequenceDiagram