@lamalibre/create-lamaste 4.3.0 → 4.3.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 (55) hide show
  1. package/package.json +2 -2
  2. package/scripts/bundle-vendor.js +13 -8
  3. package/src/index.js +4 -0
  4. package/src/lib/panel-pin.js +41 -0
  5. package/vendor/docs/00-introduction/how-it-works.md +2 -2
  6. package/vendor/docs/00-introduction/quickstart.md +5 -5
  7. package/vendor/docs/00-introduction/what-is-lamaste.md +5 -5
  8. package/vendor/docs/01-concepts/certificates.md +3 -3
  9. package/vendor/docs/01-concepts/mtls.md +2 -2
  10. package/vendor/docs/01-concepts/security-model.md +13 -2
  11. package/vendor/docs/01-concepts/tickets.md +2 -2
  12. package/vendor/docs/01-concepts/tunneling.md +4 -4
  13. package/vendor/docs/02-guides/agent-setup.md +5 -5
  14. package/vendor/docs/02-guides/certificate-management.md +2 -2
  15. package/vendor/docs/02-guides/cloud-provisioning.md +4 -4
  16. package/vendor/docs/02-guides/desktop-app-setup.md +11 -10
  17. package/vendor/docs/02-guides/installation.md +3 -3
  18. package/vendor/docs/02-guides/onboarding.md +2 -2
  19. package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +2 -2
  20. package/vendor/docs/03-architecture/installer-flow.md +2 -2
  21. package/vendor/docs/03-architecture/installer.md +4 -4
  22. package/vendor/docs/03-architecture/management-flow.md +1 -1
  23. package/vendor/docs/03-architecture/overview.md +5 -5
  24. package/vendor/docs/03-architecture/panel-client.md +6 -6
  25. package/vendor/docs/03-architecture/panel-server.md +2 -2
  26. package/vendor/docs/03-architecture/state-management.md +2 -2
  27. package/vendor/docs/03-architecture/system-overview.md +1 -1
  28. package/vendor/docs/04-api-reference/agent-hosted-plugins.md +2 -2
  29. package/vendor/docs/04-api-reference/app-host.md +3 -3
  30. package/vendor/docs/04-api-reference/lifecycle-hooks.md +4 -4
  31. package/vendor/docs/04-api-reference/onboarding.md +1 -1
  32. package/vendor/docs/04-api-reference/registry-and-oidc.md +1 -1
  33. package/vendor/docs/05-operations/backup-and-restore.md +3 -1
  34. package/vendor/docs/05-operations/uninstalling.md +1 -1
  35. package/vendor/docs/05-operations/upgrades.md +5 -5
  36. package/vendor/docs/06-reference/config-files.md +6 -1
  37. package/vendor/docs/06-reference/glossary.md +3 -3
  38. package/vendor/docs/06-reference/installer-flags.md +13 -13
  39. package/vendor/docs/06-reference/ports-and-services.md +1 -1
  40. package/vendor/docs/06-reference/troubleshooting.md +8 -8
  41. package/vendor/docs/gatekeeper-design.md +8 -8
  42. package/vendor/docs/identity-directory-design.md +2 -2
  43. package/vendor/docs/package.json +1 -1
  44. package/vendor/docs/todo/lib-cli-desktop-refactor.md +27 -27
  45. package/vendor/gatekeeper/dist/cli/index.js +0 -0
  46. package/vendor/gatekeeper/package.json +2 -2
  47. package/vendor/server/bin/lamaste-server.js +7 -0
  48. package/vendor/server/package.json +2 -2
  49. package/vendor/server/src/commands/panel-pin.js +40 -0
  50. package/vendor/server/src/panel-api.js +247 -32
  51. package/vendor/server/src/panel-identity.js +165 -0
  52. package/vendor/server-ui/dist/assets/index-BTlBt_cD.js +84 -0
  53. package/vendor/server-ui/dist/index.html +1 -1
  54. package/vendor/serverd/package.json +2 -2
  55. package/vendor/server-ui/dist/assets/index-DBp3cmaU.js +0 -84
@@ -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.0` 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.3.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.0`)
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`)
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.0` to create the droplet
30
+ - The wizard calls `@lamalibre/lamaste-cloud@4.3.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.0` — 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.3.1` — the admin does not need to do anything.
100
100
 
101
101
  ```mermaid
102
102
  sequenceDiagram
@@ -1,6 +1,6 @@
1
1
  # Installer Flow
2
2
 
3
- ## What `npx @lamalibre/create-lamaste@4.3.0` Does
3
+ ## What `npx @lamalibre/create-lamaste@4.3.1` Does
4
4
 
5
5
  The installer is a **zero-prompt, fire-and-forget** command. It assumes:
6
6
 
@@ -13,7 +13,7 @@ It requires **no user input**. All configuration happens later through the brows
13
13
  ## Execution Flow
14
14
 
15
15
  ```
16
- $ npx @lamalibre/create-lamaste@4.3.0
16
+ $ npx @lamalibre/create-lamaste@4.3.1
17
17
 
18
18
  Lamaste Installer v1.0.0
19
19
 
@@ -4,14 +4,14 @@
4
4
 
5
5
  ## In Plain English
6
6
 
7
- When you run `npx @lamalibre/create-lamaste@4.3.0` on a fresh VPS, the installer takes over and does everything automatically: hardens the OS, installs dependencies, generates security certificates, configures nginx, deploys the panel, and starts the service. It prints a summary with instructions for downloading your client certificate and accessing the panel. No prompts, no questions, no configuration files to edit.
7
+ When you run `npx @lamalibre/create-lamaste@4.3.1` on a fresh VPS, the installer takes over and does everything automatically: hardens the OS, installs dependencies, generates security certificates, configures nginx, deploys the panel, and starts the service. It prints a summary with instructions for downloading your client certificate and accessing the panel. No prompts, no questions, no configuration files to edit.
8
8
 
9
9
  The installer is deliberately limited in scope. It sets up just enough to serve the panel UI over a secure connection. Everything else — domain configuration, tunnel setup, user management — happens through the browser-based onboarding wizard after the installer finishes.
10
10
 
11
11
  ## Overview
12
12
 
13
13
  ```
14
- npx @lamalibre/create-lamaste@4.3.0
14
+ npx @lamalibre/create-lamaste@4.3.1
15
15
  │
16
16
  ├── bin/create-lamaste.js ← CLI entry point
17
17
  │ └── calls main() from src/index.js
@@ -181,7 +181,7 @@ Six task groups run sequentially through Listr2:
181
181
  **Chisel and Authelia** (`lib/relay-services.js`, run on install and on every redeploy):
182
182
 
183
183
  - Creates the `lamaste-chisel` group (and adds `lamaste` to it) and the `lamaste-authelia` system account (no login shell, no home)
184
- - Installs Chisel 1.12.0 and Authelia 4.39.28 to `/usr/local/bin` (`lib/binaries.js`): downloaded from fixed release URLs, verified against the SHA-256 digests pinned in `@lamalibre/lamaste@4.3.0` (`CHISEL_RELEASE`, `AUTHELIA_RELEASE`) before anything is unpacked, staged in a `mkdtemp` directory and renamed into place. A binary already at the pinned version is left alone; an Authelia **newer** than the pin is kept, never downgraded (its database may use a schema the pinned release cannot read)
184
+ - Installs Chisel 1.12.0 and Authelia 4.39.28 to `/usr/local/bin` (`lib/binaries.js`): downloaded from fixed release URLs, verified against the SHA-256 digests pinned in `@lamalibre/lamaste@4.3.1` (`CHISEL_RELEASE`, `AUTHELIA_RELEASE`) before anything is unpacked, staged in a `mkdtemp` directory and renamed into place. A binary already at the pinned version is left alone; an Authelia **newer** than the pin is kept, never downgraded (its database may use a schema the pinned release cannot read)
185
185
  - Writes `/etc/systemd/system/chisel.service` (`User=nobody`, `Group=lamaste-chisel`) and `/etc/systemd/system/authelia.service` (`User=lamaste-authelia`, `UMask=027`, `Environment=X_AUTHELIA_CONFIG_FILTERS=template`, `ProtectSystem=strict` with `ReadWritePaths=/etc/authelia /var/log/authelia`, `SystemCallFilter=@system-service`, empty `CapabilityBoundingSet`, `NoNewPrivileges`); both are enabled and started later by onboarding
186
186
  - Generates the OpenID Connect issuer key `/etc/authelia/oidc-issuer.pem` if it is missing (`lib/oidc-issuer-key.js`): RSA 4096 generated in the installer process, written by a child process running as `lamaste-authelia` (`wx`, 0600, renamed into place) so root never writes through `/etc/authelia`. The panel references it from Authelia's configuration with a `{{ secret "…" }}` template expression — which is why the unit and `lamaste-priv authelia-totp` set the `template` configuration filter — and can never read it. A key owned by anyone else is replaced; one owned by the Authelia account is kept (its mode fixed through a descriptor if it drifted)
187
187
  - Sets ownership (`lib/ownership.js`): `/var/www/lamaste` `lamaste:www-data 2750`; `/etc/authelia` `lamaste:lamaste-authelia 2770` (setgid) with `configuration.yml` `0640`, `users.yml` `0660`, `.secrets.json` `0600` (lamaste), `db.sqlite3*` and `notifications.txt` `lamaste-authelia 0600`; `/var/log/authelia` `lamaste-authelia 0750`; `chisel-server.key` (if present) `lamaste:lamaste-chisel 0640`; the PKI directory `lamaste:lamaste` (the panel is the CA)
@@ -253,7 +253,7 @@ When the installer detects an existing Lamaste installation (`/etc/lamalibre/lam
253
253
 
254
254
  Redeploy mode stops the panel and gatekeeper, secures the install directory (a non-root-owned tree is moved aside and removed at the end), redeploys the panel server, `lamaste-server` CLI, UI, docs, gatekeeper and cert help page, merges `panel.json`, runs the same Chisel/Authelia step as a fresh install (stopping a running Authelia while its files change hands), rewrites the panel's systemd unit, the root-owned programs and the sudoers rules, ensures the port-80 redirect, then restarts Chisel if its binary or unit changed, starts Authelia and the gatekeeper if they were running, and restarts the panel. It does not touch OS hardening, mTLS certificates or the panel's vhosts. The panel's self-update (`sudo lamaste-priv self-update <version>`) runs this path as root, so it never writes through a path the `lamaste` user controls.
255
255
 
256
- This provides a fast upgrade path: re-running `npx @lamalibre/create-lamaste@4.3.0` on an existing installation updates the code and the pinned services while preserving all configuration and certificates. Use `--force-full` to bypass this and run the complete installer.
256
+ This provides a fast upgrade path: re-running `npx @lamalibre/create-lamaste@4.3.1` on an existing installation updates the code and the pinned services while preserving all configuration and certificates. Use `--force-full` to bypass this and run the complete installer.
257
257
 
258
258
  The redeploy logic lives in `tasks/redeploy.js`, with shared systemd unit and sudoers content generators in `lib/service-config.js`.
259
259
 
@@ -276,7 +276,7 @@ Everything else the panel does needs no rule: the PKI directory (agent CSR signi
276
276
 
277
277
  The certbot wrappers accept only lowercase DNS hostnames (no wildcards or path characters, at most 100 per certificate) and a syntactically valid email address. Renewals the panel triggers pass `--no-random-sleep-on-renew`, because certbot otherwise sleeps up to about 8 minutes before a non-interactive renewal (a delay meant for `certbot.timer`) while an operator waits.
278
278
 
279
- Redeploying (`npx @lamalibre/create-lamaste@4.3.0` on an existing install) reinstalls the programs, removes retired ones (`lamaste-sign-csr`, `lamaste-pki-rename`), and replaces this file atomically after `visudo -c` accepts it, so upgrades pick up new rules.
279
+ Redeploying (`npx @lamalibre/create-lamaste@4.3.1` on an existing install) reinstalls the programs, removes retired ones (`lamaste-sign-csr`, `lamaste-pki-rename`), and replaces this file atomically after `visudo -c` accepts it, so upgrades pick up new rules.
280
280
 
281
281
  ## File Operation Safety
282
282
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  Lamaste has three main pieces:
8
8
 
9
- 1. **The Installer** (`npx @lamalibre/create-lamaste@4.3.0`) — a one-shot script you run once on a fresh VPS. It sets up nginx, generates security certificates, and deploys a web-based control panel. After it finishes, you never SSH into the server again.
9
+ 1. **The Installer** (`npx @lamalibre/create-lamaste@4.3.1`) — a one-shot script you run once on a fresh VPS. It sets up nginx, generates security certificates, and deploys a web-based control panel. After it finishes, you never SSH into the server again.
10
10
 
11
11
  2. **The Panel** (browser UI + backend API) — a management interface protected by a client certificate. Through it, you configure your domain, create tunnels, manage users, and monitor services.
12
12
 
@@ -321,7 +321,7 @@ lamaste/
321
321
  │ │ ├── files.js ← Static site file operations (upload, delete, list)
322
322
  │ │ └── app-error.js ← Operational error class (AppError)
323
323
  │ │
324
- │ ├── lamaste-server-ui/ ← React 18 + Vite + Tailwind SPA + shared admin components (@lamalibre/lamaste-server-ui@4.3.0)
324
+ │ ├── lamaste-server-ui/ ← React 18 + Vite + Tailwind SPA + shared admin components (@lamalibre/lamaste-server-ui@4.3.1)
325
325
  │ │ └── src/
326
326
  │ │ ├── index.js ← Package exports (pages, context, utilities)
327
327
  │ │ ├── context/
@@ -337,7 +337,7 @@ lamaste/
337
337
  │ │ │ └── formatters.js ← Byte, uptime, relative time formatters
338
338
  │ │ └── pages/ ← Admin pages (Dashboard, Tunnels, Sites, Users, Certs, Services, Plugins, Tickets, Settings)
339
339
  │ │
340
- │ ├── lamaste-agent-ui/ ← Shared React agent UI (pages, context, components) (@lamalibre/lamaste-agent-ui@4.3.0)
340
+ │ ├── lamaste-agent-ui/ ← Shared React agent UI (pages, context, components) (@lamalibre/lamaste-agent-ui@4.3.1)
341
341
  │ │
342
342
  │ ├── lamaste-tickets/ ← Agent-to-agent authorization SDK (mTLS, undici)
343
343
  │ │ └── src/
@@ -377,7 +377,7 @@ lamaste/
377
377
  │ │ │ └── CompleteStep.jsx ← Credentials + TOTP QR + next steps
378
378
  │ │ ├── management/ ← Legacy standalone implementations (kept for reference)
379
379
  │ │ │ ├── Certificates.jsx ← Standalone certificates page (dead code)
380
- │ │ │ ├── Dashboard.jsx ← Standalone dashboard (not imported — App.jsx uses @lamalibre/lamaste-server-ui@4.3.0)
380
+ │ │ │ ├── Dashboard.jsx ← Standalone dashboard (not imported — App.jsx uses @lamalibre/lamaste-server-ui@4.3.1)
381
381
  │ │ │ ├── Plugins.jsx ← Standalone plugins page (dead code)
382
382
  │ │ │ ├── Services.jsx ← Standalone services page (dead code)
383
383
  │ │ │ ├── Settings.jsx ← Standalone settings page (dead code)
@@ -486,7 +486,7 @@ The Panel Server runs as the `lamaste` user with minimal privileges and cannot b
486
486
  The full lifecycle of a Lamaste installation:
487
487
 
488
488
  ```
489
- Phase 1: Installation (npx @lamalibre/create-lamaste@4.3.0)
489
+ Phase 1: Installation (npx @lamalibre/create-lamaste@4.3.1)
490
490
  └─ OS hardening, Node.js, mTLS certs, nginx, panel deploy
491
491
  └─ Result: Panel accessible at https://<ip>:9292
492
492
 
@@ -10,9 +10,9 @@ The client has two modes. On first visit, it shows an onboarding wizard that wal
10
10
 
11
11
  ## Shared Panel Packages
12
12
 
13
- The management-mode admin pages (Dashboard, Tunnels, Sites, Users, Certificates, Services, Plugins, Tickets, Logs, Settings) live in `@lamalibre/lamaste-server-ui@4.3.0`. This package provides both the browser SPA build and the shared admin components consumed by `lamaste-desktop` (Tauri app).
13
+ The management-mode admin pages (Dashboard, Tunnels, Sites, Users, Certificates, Services, Plugins, Tickets, Logs, Settings) live in `@lamalibre/lamaste-server-ui@4.3.1`. This package provides both the browser SPA build and the shared admin components consumed by `lamaste-desktop` (Tauri app).
14
14
 
15
- The agent-mode pages (Dashboard, Tunnels, Services, Plugins, Logs, Settings) are extracted into a separate shared package: `@lamalibre/lamaste-agent-ui@4.3.0`. This package is consumed by `lamaste-desktop` for agent mode.
15
+ The agent-mode pages (Dashboard, Tunnels, Services, Plugins, Logs, Settings) are extracted into a separate shared package: `@lamalibre/lamaste-agent-ui@4.3.1`. This package is consumed by `lamaste-desktop` for agent mode.
16
16
 
17
17
  The shared package exposes an `AdminClientContext` abstraction that decouples admin UI pages from their data transport. Each host provides its own client implementation:
18
18
 
@@ -118,7 +118,7 @@ The shell renders the appropriate step component and shows a progress indicator
118
118
 
119
119
  ### Management Mode
120
120
 
121
- React Router handles navigation within the `Layout` component (sidebar + content area). Management page components are imported from the shared `@lamalibre/lamaste-server-ui@4.3.0` package and wrapped with the `AdminClientProvider` (which supplies the web-specific data client):
121
+ React Router handles navigation within the `Layout` component (sidebar + content area). Management page components are imported from the shared `@lamalibre/lamaste-server-ui@4.3.1` package and wrapped with the `AdminClientProvider` (which supplies the web-specific data client):
122
122
 
123
123
  | Path | Component | Description |
124
124
  | ------------------------ | ------------------- | ------------------------------------------------------------------- |
@@ -350,9 +350,9 @@ The app root wraps all content in five providers:
350
350
  ```
351
351
 
352
352
  1. **QueryClientProvider** — react-query cache with global defaults (`retry: 1`, `refetchOnWindowFocus: false`)
353
- 2. **AdminClientProvider** — from `@lamalibre/lamaste-server-ui@4.3.0`, supplies the host-specific data client (`webAdminClient` for browser fetch, Tauri `invoke` for desktop)
354
- 3. **ToastProvider** — from `@lamalibre/lamaste-server-ui@4.3.0`, notification toast system
355
- 4. **TwoFaProvider** — from `@lamalibre/lamaste-server-ui@4.3.0`, handles 2FA verification prompts when the panel has 2FA enabled
353
+ 2. **AdminClientProvider** — from `@lamalibre/lamaste-server-ui@4.3.1`, supplies the host-specific data client (`webAdminClient` for browser fetch, Tauri `invoke` for desktop)
354
+ 3. **ToastProvider** — from `@lamalibre/lamaste-server-ui@4.3.1`, notification toast system
355
+ 4. **TwoFaProvider** — from `@lamalibre/lamaste-server-ui@4.3.1`, handles 2FA verification prompts when the panel has 2FA enabled
356
356
  5. **BrowserRouter** — React Router for client-side navigation
357
357
 
358
358
  ## Documentation Viewer
@@ -453,7 +453,7 @@ See [nginx-configuration.md](./nginx-configuration.md) for detailed coverage.
453
453
 
454
454
  ### chisel-users.js — Chisel Credentials and Grants
455
455
 
456
- - Thin shim over `@lamalibre/lamaste@4.3.0/server`: per-agent credentials in `chisel-credentials.json` (0600)
456
+ - Thin shim over `@lamalibre/lamaste@4.3.1/server`: per-agent credentials in `chisel-credentials.json` (0600)
457
457
  - Renders the authfile `chisel-users` from the credentials and `tunnels.json`: each `agent-<label>` may bind exactly `^R:127\.0\.0\.1:<port>$` for its enabled tunnels
458
458
  - Adds the `lamaste-no-grants` sentinel user (password in `chisel-sentinel`, 0600) so the authfile is never empty — Chisel disables authentication on an empty authfile
459
459
  - Never grants a reserved port (3100, 9090, 9091, 9292, 9294) or a port claimed by two tunnels
@@ -535,7 +535,7 @@ Agent-to-agent authorization with scopes, instances, tickets, and sessions. Prov
535
535
  - **Periodic cleanup** — stale/dead instances, expired tickets, dead sessions
536
536
  - **Concurrency** — promise-chain mutex with atomic file writes (temp → fsync → rename)
537
537
 
538
- Client SDK: `@lamalibre/lamaste-tickets@4.3.0` (TypeScript, undici) provides `TicketClient`, `TicketInstanceManager` (source side), and `TicketSessionManager` (target side) for plugin integration.
538
+ Client SDK: `@lamalibre/lamaste-tickets@4.3.1` (TypeScript, undici) provides `TicketClient`, `TicketInstanceManager` (source side), and `TicketSessionManager` (target side) for plugin integration.
539
539
 
540
540
  State files: `/etc/lamalibre/lamaste/ticket-scopes.json` (scopes, instances, assignments) and `/etc/lamalibre/lamaste/tickets.json` (tickets, sessions).
541
541
 
@@ -331,7 +331,7 @@ Read returns `[]` for missing files (ENOENT), enabling the system to start with
331
331
  5. `DELETE /api/certs/agent/:label` (revocation) — the agent's app and plugin tunnels lose their `agentLabel` (unassigned), and its `agent-<label>` panel tunnel is removed
332
332
  6. At startup (background, fail closed): an ownerless `agent-<label>` panel tunnel is bound to the agent it names when that agent is active; other ownerless tunnels (from versions before tunnel ownership) are bound to the sole active agent, or left unassigned when there are several. Then the pinned Chisel binary, the unit and the authfile are re-established — and Chisel is stopped if they cannot be
333
333
 
334
- Every one of these workflows runs under the single tunnel lock (`withTunnelLock` in `@lamalibre/lamaste@4.3.0/server`), with its validation inside the lock.
334
+ Every one of these workflows runs under the single tunnel lock (`withTunnelLock` in `@lamalibre/lamaste@4.3.1/server`), with its validation inside the lock.
335
335
 
336
336
  ## Site State (`sites.json`)
337
337
 
@@ -486,7 +486,7 @@ The PKI directory belongs to `lamaste` because the panel is the CA (it signs age
486
486
 
487
487
  The Panel Server is a single-process Node.js application, but a single-threaded event loop does not serialize asynchronous workflows: two requests that each read `tunnels.json`, await a certificate or an nginx test, and then write it back would interleave, and both could pass the same uniqueness check. Serialization is therefore explicit:
488
488
 
489
- **Tunnel state** is guarded by one promise-chain lock, `withTunnelLock` in `@lamalibre/lamaste@4.3.0/server`'s `tunnels.ts`. Every tunnel workflow — create, delete, toggle, assign, reconfigure, the combined `PATCH /api/tunnels/:id`, releasing a revoked agent's tunnels, and startup reconciliation — takes it for its whole duration, and does its validation (subdomain and port uniqueness, reserved ports, agent checks, authorization against the current entry) inside it.
489
+ **Tunnel state** is guarded by one promise-chain lock, `withTunnelLock` in `@lamalibre/lamaste@4.3.1/server`'s `tunnels.ts`. Every tunnel workflow — create, delete, toggle, assign, reconfigure, the combined `PATCH /api/tunnels/:id`, releasing a revoked agent's tunnels, and startup reconciliation — takes it for its whole duration, and does its validation (subdomain and port uniqueness, reserved ports, agent checks, authorization against the current entry) inside it.
490
490
 
491
491
  **Chisel authfile renders** are serialized by a promise-chain mutex in `chisel-users.ts`, keyed by the credentials file, around every render (enroll, revoke, rotate, tunnel change). The daemon's `syncChisel()` renders after the tunnel state is written and restarts Chisel (`systemctl try-restart`) only when the render withdrew something.
492
492
 
@@ -58,7 +58,7 @@
58
58
  │ │ │ │
59
59
  │ │ Lamaste Desktop (Tauri v2) — dual mode │ │
60
60
  │ │ ├─ Agent mode: service discovery + tunnel management │ │
61
- │ │ │ (pages from @lamalibre/lamaste-agent-ui@4.3.0) │ │
61
+ │ │ │ (pages from @lamalibre/lamaste-agent-ui@4.3.1) │ │
62
62
  │ │ ├─ Server mode: full admin panel (via lamaste-server-ui) │ │
63
63
  │ │ ├─ Multi-server registry (~/.lamalibre/lamaste/servers.json) │ │
64
64
  │ │ ├─ Cloud provisioning (DigitalOcean via lamaste-cloud) │ │
@@ -333,10 +333,10 @@ What the agent's host offers — see [Host facts](#host-facts).
333
333
 
334
334
  `lamaste-agent sync` (the 30-second timer) fetches a plugin's config when it does not hold the secret issued at `secretIssuedAt`, writes `~/.lamalibre/lamaste/agents/<label>/app-plugins/<route>.json` (0600, atomic), acknowledges it, and removes the file of a plugin the relay no longer lists. For an agent half Lamaste installed it first writes the service's own copy, `/etc/lamalibre/apps/<route>/plugin-config.json`, and acknowledges only once both are written. `sync.log` records `plugin config fetched: <route>` and `plugin config delivered to its service: <route>`.
335
335
 
336
- The agent half reads that file — `LAMALIBRE_LAMASTE_APP_PLUGIN_CONFIG` by convention — for its port and verifies every request on `/admin/*` with `createCallerAssertionVerifier` from `@lamalibre/lamaste@4.3.0/agent`, which re-reads the file when a signature does not verify, so a rotation needs no restart:
336
+ The agent half reads that file — `LAMALIBRE_LAMASTE_APP_PLUGIN_CONFIG` by convention — for its port and verifies every request on `/admin/*` with `createCallerAssertionVerifier` from `@lamalibre/lamaste@4.3.1/agent`, which re-reads the file when a signature does not verify, so a rotation needs no restart:
337
337
 
338
338
  ```js
339
- import { createCallerAssertionVerifier } from '@lamalibre/lamaste@4.3.0/agent';
339
+ import { createCallerAssertionVerifier } from '@lamalibre/lamaste@4.3.1/agent';
340
340
 
341
341
  const verifier = createCallerAssertionVerifier({ configPath, plugin: 'market-indicators' });
342
342
  const port = await verifier.port();
@@ -15,12 +15,12 @@ The helper does only what the relay **signed**. When it is enabled it remembers
15
15
  Once per agent machine (Linux with systemd; macOS agents cannot host an agent half Lamaste installs):
16
16
 
17
17
  ```bash
18
- sudo npm install -g @lamalibre/lamaste-agent@4.3.0 # a root-owned install
18
+ sudo npm install -g @lamalibre/lamaste-agent@4.3.1 # a root-owned install
19
19
  sudo lamaste-agent apphost enable # the agent runs as the user who ran sudo
20
20
  sudo lamaste-agent apphost enable --user root # the agent runs as root: no sudoers rule
21
21
  ```
22
22
 
23
- `enable` refuses to act from an install another user could have changed: the package, the helper it ships and the core library it loads — and every directory above them — must be root-owned and writable by no group or other user. A user-level install (`nvm`, a home-directory prefix) is not; install it root-owned with `sudo npm install -g @lamalibre/lamaste-agent@4.3.0` and run `enable` from that install. It also needs `/usr/bin/node` (the helper's interpreter and the Node.js every agent half runs on — from the distribution or NodeSource), systemd as the system manager (`/run/systemd/system`), and `sudo` and `visudo` unless the agent runs as root.
23
+ `enable` refuses to act from an install another user could have changed: the package, the helper it ships and the core library it loads — and every directory above them — must be root-owned and writable by no group or other user. A user-level install (`nvm`, a home-directory prefix) is not; install it root-owned with `sudo npm install -g @lamalibre/lamaste-agent@4.3.1` and run `enable` from that install. It also needs `/usr/bin/node` (the helper's interpreter and the Node.js every agent half runs on — from the distribution or NodeSource), systemd as the system manager (`/run/systemd/system`), and `sudo` and `visudo` unless the agent runs as root.
24
24
 
25
25
  What `enable` does:
26
26
 
@@ -313,7 +313,7 @@ The contract:
313
313
  - **Its config** is `LAMASTE_APP_CONFIG` (0600): `{ plugin, port, secret, issuedAt, previousSecret?, previousIssuedAt?, fetchedAt, acknowledged }`. Listen on `127.0.0.1:<port>` and verify every `/admin/*` request:
314
314
 
315
315
  ```js
316
- import { createCallerAssertionVerifier } from '@lamalibre/lamaste@4.3.0/agent'; // bundled
316
+ import { createCallerAssertionVerifier } from '@lamalibre/lamaste@4.3.1/agent'; // bundled
317
317
 
318
318
  const verifier = createCallerAssertionVerifier({
319
319
  configPath: process.env.LAMASTE_APP_CONFIG,
@@ -233,13 +233,13 @@ Relay hooks run in `lamalibre-lamaste-hooks@<route>.service`, started by its soc
233
233
 
234
234
  `lamaste-priv hooks install <route> <sha256|none>` (module on stdin, checked against the approved digest) writes the module root-owned to `/opt/lamalibre/lamaste/hooks/<route>/<sha256>.mjs` and enables the socket; `hooks activate` points back at the previous module (an update's revert); `hooks restart` stops a stuck runner; `hooks remove` disables it and deletes its modules. The panel reinstalls an approved runner at start-up if it is missing.
235
235
 
236
- The protocol between the panel and the runner is one length-prefixed JSON frame each way per connection (`@lamalibre/lamaste@4.3.0/hooks`, `protocol.ts`).
236
+ The protocol between the panel and the runner is one length-prefixed JSON frame each way per connection (`@lamalibre/lamaste@4.3.1/hooks`, `protocol.ts`).
237
237
 
238
238
  ## Writing hooks
239
239
 
240
240
  ```js
241
241
  // hooks/relay.mjs — bundled into one file (esbuild), Node built-ins only
242
- import { defineRelayHooks } from '@lamalibre/lamaste@4.3.0/hooks';
242
+ import { defineRelayHooks } from '@lamalibre/lamaste@4.3.1/hooks';
243
243
 
244
244
  export default defineRelayHooks({
245
245
  'install:pre-tunnel': async (input) =>
@@ -266,10 +266,10 @@ Every decision may carry `effects` (at most 10): `{ type: 'audit', event, data?
266
266
 
267
267
  ### Agent hooks
268
268
 
269
- The agent half answers `POST /admin/hooks/<stage>` (body `{ stage, input }`, answer `{ ok: true, output? }` or `{ ok: false, reason }`). `createAgentHookHandler` from `@lamalibre/lamaste@4.3.0/agent` does the checking — the caller assertion must name Lamaste itself (`{ type: 'lamaste' }`), which no forwarded caller can, and the forwarder never reaches `/admin/hooks`:
269
+ The agent half answers `POST /admin/hooks/<stage>` (body `{ stage, input }`, answer `{ ok: true, output? }` or `{ ok: false, reason }`). `createAgentHookHandler` from `@lamalibre/lamaste@4.3.1/agent` does the checking — the caller assertion must name Lamaste itself (`{ type: 'lamaste' }`), which no forwarded caller can, and the forwarder never reaches `/admin/hooks`:
270
270
 
271
271
  ```js
272
- import { createAgentHookHandler, createCallerAssertionVerifier } from '@lamalibre/lamaste@4.3.0/agent';
272
+ import { createAgentHookHandler, createCallerAssertionVerifier } from '@lamalibre/lamaste@4.3.1/agent';
273
273
 
274
274
  const hooks = createAgentHookHandler({
275
275
  verifier: createCallerAssertionVerifier({ configPath, plugin: 'fx' }),
@@ -255,7 +255,7 @@ The wildcard check probes `test-lamaste-check.<domain>`. Wildcard DNS is optiona
255
255
 
256
256
  ### `POST /api/onboarding/provision`
257
257
 
258
- Starts the full stack provisioning process in the background. This configures and starts Chisel and Authelia, issues certbot certificates, and writes nginx vhosts. The Chisel and Authelia binaries and units are installed by `create-lamaste`, not here: if one is missing, the task fails with the error "Chisel is not installed. Run `npx @lamalibre/create-lamaste@4.3.0` on the server to repair the installation." (likewise for Authelia). Task IDs are unchanged from earlier versions; only the titles changed.
258
+ Starts the full stack provisioning process in the background. This configures and starts Chisel and Authelia, issues certbot certificates, and writes nginx vhosts. The Chisel and Authelia binaries and units are installed by `create-lamaste`, not here: if one is missing, the task fails with the error "Chisel is not installed. Run `npx @lamalibre/create-lamaste@4.3.1` on the server to repair the installation." (likewise for Authelia). Task IDs are unchanged from earlier versions; only the titles changed.
259
259
 
260
260
  Provisioning runs asynchronously. This endpoint returns immediately with a 202 status. Use the WebSocket stream endpoint to follow progress in real time.
261
261
 
@@ -198,7 +198,7 @@ Agent certificates only; identity is the certificate label, never a parameter. R
198
198
  - An agent may be issued at most **ten new tokens per hour**; beyond that the route answers `429` with `Retry-After` (seconds) and `retryAfterSeconds`. The per-IP limit (30 per minute) remains as a backstop.
199
199
  - `403` for any other certificate — an admin certificate has no agent identity to broker for (plugin-agent certificates get `400`); `404` when no registry credential is configured (the agent installs from the public registry as before); `502` when the registry refuses.
200
200
 
201
- CLI: `lamaste-server registry-credential show | set --url <registry> (--oidc | --token-stdin) | clear`. The token for `--token-stdin` is read from stdin (or `LAMASTE_REGISTRY_TOKEN`), never from an argument.
201
+ CLI: `lamaste-server registry-credential show | set --url <registry> (--oidc | --token-stdin) | clear`. The token for `--token-stdin` is read from stdin (or `LAMASTE_REGISTRY_TOKEN`), never from an argument, and the CLI hands the request body to curl on stdin, so the token is not in curl's arguments either.
202
202
 
203
203
  ### Group changes
204
204
 
@@ -197,7 +197,7 @@ sudo chown lamaste-authelia:lamaste-authelia /etc/authelia/db.sqlite3* /etc/auth
197
197
  sudo chmod 600 /etc/authelia/db.sqlite3* /etc/authelia/notifications.txt
198
198
  ```
199
199
 
200
- A backup taken on a version before the privilege boundary holds root-owned Authelia files and older unit files. After restoring one, re-run `npx @lamalibre/create-lamaste@4.3.0 --yes`: the redeploy rewrites the `chisel` and `authelia` units and converts the ownership of `/etc/authelia`, the Chisel key and the PKI directory (see [Upgrades](upgrades.md)).
200
+ A backup taken on a version before the privilege boundary holds root-owned Authelia files and older unit files. After restoring one, re-run `npx @lamalibre/create-lamaste@4.3.1 --yes`: the redeploy rewrites the `chisel` and `authelia` units and converts the ownership of `/etc/authelia`, the Chisel key and the PKI directory (see [Upgrades](upgrades.md)).
201
201
 
202
202
  The panel re-applies the authfile's group and mode itself on every start, so a Chisel that fails to read it before the panel is up is started again by the panel's reconciliation.
203
203
 
@@ -273,6 +273,8 @@ sudo openssl req -x509 -nodes -days 3650 \
273
273
  -addext "subjectAltName=IP:NEW_IP"
274
274
  ```
275
275
 
276
+ The new certificate has a new key. Agents re-pin it with `lamaste-agent panel reset-pin`, the desktop app with **Re-pin** on the server's card; compare both with `sudo lamaste-server panel-pin` on the new server. Until then they refuse the panel at its IP address.
277
+
276
278
  **Step 7: Update DNS records** to point to the new IP
277
279
 
278
280
  **Step 8: Fix permissions (same as Step 3 above)**
@@ -29,7 +29,7 @@ It stops and disables the panel, gatekeeper, Chisel and Authelia; removes their
29
29
  The manual guide is also available from the CLI:
30
30
 
31
31
  ```bash
32
- npx @lamalibre/create-lamaste@4.3.0 --uninstall
32
+ npx @lamalibre/create-lamaste@4.3.1 --uninstall
33
33
  ```
34
34
 
35
35
  This prints the same steps listed below.
@@ -27,7 +27,7 @@ Coming from 3.x, upgrade the **agents first**, as 4.0 required: agents from befo
27
27
  On each agent machine, after the server:
28
28
 
29
29
  ```bash
30
- sudo npm install -g @lamalibre/lamaste-agent@4.3.0
30
+ sudo npm install -g @lamalibre/lamaste-agent@4.3.1
31
31
  lamaste-agent update
32
32
  ```
33
33
 
@@ -84,7 +84,7 @@ exit
84
84
 
85
85
  ### Updating Chisel
86
86
 
87
- Chisel is the tunnel server binary at `/usr/local/bin/chisel`. Lamaste pins it: server and agents run Chisel 1.12.0 (`CHISEL_RELEASE` in `@lamalibre/lamaste@4.3.0`), downloaded from the fixed release URL and verified against a pinned SHA-256 before it is unpacked. **Do not replace the binary by hand.** On the server, `create-lamaste` installs it (as root) and replaces a binary that reports any other version; the panel cannot install binaries, and only logs an error at startup when the installed Chisel is not the pinned release (it then restarts Chisel on every authfile change). Each agent's sync replaces its own copy.
87
+ Chisel is the tunnel server binary at `/usr/local/bin/chisel`. Lamaste pins it: server and agents run Chisel 1.12.0 (`CHISEL_RELEASE` in `@lamalibre/lamaste@4.3.1`), downloaded from the fixed release URL and verified against a pinned SHA-256 before it is unpacked. **Do not replace the binary by hand.** On the server, `create-lamaste` installs it (as root) and replaces a binary that reports any other version; the panel cannot install binaries, and only logs an error at startup when the installed Chisel is not the pinned release (it then restarts Chisel on every authfile change). Each agent's sync replaces its own copy.
88
88
 
89
89
  A new Chisel version therefore arrives with a Lamaste release that changes the pin: re-run the installer, which installs it and restarts Chisel. To check what is running:
90
90
 
@@ -98,7 +98,7 @@ Tunnel clients reconnect on their own after the brief interruption (they retry a
98
98
 
99
99
  ### Updating Authelia
100
100
 
101
- Authelia is the authentication server binary at `/usr/local/bin/authelia`. Lamaste pins it too: Authelia 4.39.28 (`AUTHELIA_RELEASE` in `@lamalibre/lamaste@4.3.0`), downloaded by `create-lamaste` from its fixed release URL and verified against a pinned SHA-256 per architecture. A new Authelia version arrives with a Lamaste release that changes the pin — re-run the installer. It stops Authelia while it replaces the binary and starts it again.
101
+ Authelia is the authentication server binary at `/usr/local/bin/authelia`. Lamaste pins it too: Authelia 4.39.28 (`AUTHELIA_RELEASE` in `@lamalibre/lamaste@4.3.1`), downloaded by `create-lamaste` from its fixed release URL and verified against a pinned SHA-256 per architecture. A new Authelia version arrives with a Lamaste release that changes the pin — re-run the installer. It stops Authelia while it replaces the binary and starts it again.
102
102
 
103
103
  An installed Authelia **newer** than the pin is kept, never downgraded: its database may already use a schema the pinned release cannot read, and Authelia refuses to start on a database newer than itself. If you install a newer release by hand, stop the service, replace the binary as root with a `root:root 0755` file, and start it again; check the [Authelia changelog](https://github.com/authelia/authelia/blob/master/CHANGELOG.md) first, since the configuration format may change between versions.
104
104
 
@@ -237,7 +237,7 @@ The panel server, CLI, client, docs and gatekeeper are always redeployed (files
237
237
 
238
238
  ### Version Pinning
239
239
 
240
- Chisel and Authelia are pinned by version and SHA-256 in `packages/core/lib/src/constants.ts` (`CHISEL_RELEASE`, `AUTHELIA_RELEASE`); changing a pin means updating the version and every digest there. The downloads are verified by `downloadVerifiedChisel` / `downloadVerifiedAuthelia` (exported from `@lamalibre/lamaste@4.3.0`) before anything is unpacked; the server installer uses them in `packages/provisioners/server/src/lib/binaries.js`. The configuration the panel writes needs Authelia 4.38 or later.
240
+ Chisel and Authelia are pinned by version and SHA-256 in `packages/core/lib/src/constants.ts` (`CHISEL_RELEASE`, `AUTHELIA_RELEASE`); changing a pin means updating the version and every digest there. The downloads are verified by `downloadVerifiedChisel` / `downloadVerifiedAuthelia` (exported from `@lamalibre/lamaste@4.3.1`) before anything is unpacked; the server installer uses them in `packages/provisioners/server/src/lib/binaries.js`. The configuration the panel writes needs Authelia 4.38 or later.
241
241
 
242
242
  ### Automated Updates
243
243
 
@@ -259,7 +259,7 @@ sudo dpkg-reconfigure -plow unattended-upgrades
259
259
  | Panel server | `/opt/lamalibre/lamaste/lamaste-serverd/` | Re-run `npx @lamalibre/create-lamaste@latest` |
260
260
  | Panel client | `/opt/lamalibre/lamaste/lamaste-server-ui/` | Re-run `npx @lamalibre/create-lamaste@latest` |
261
261
  | Chisel | `/usr/local/bin/chisel` | Pinned; installed by `create-lamaste` |
262
- | Agents | `sudo npm install -g @lamalibre/lamaste-agent@4.3.0` | Upgrade after the server, then `lamaste-agent update` |
262
+ | Agents | `sudo npm install -g @lamalibre/lamaste-agent@4.3.1` | Upgrade after the server, then `lamaste-agent update` |
263
263
  | Authelia | `/usr/local/bin/authelia` | Pinned; installed by `create-lamaste` (newer is kept) |
264
264
  | nginx | System package | `sudo apt-get update && sudo apt-get upgrade` |
265
265
  | certbot | System package | `sudo apt-get update && sudo apt-get upgrade` |
@@ -823,6 +823,9 @@ Stores the server registry for the desktop app's multi-server support. Created b
823
823
  | `adminAuth.method` | string | `"p12"` or `"keychain"` — how the admin cert is stored |
824
824
  | `adminAuth.p12Path` | string \| null | Path to admin P12 file (when method is `"p12"`) |
825
825
  | `adminAuth.keychainIdentity` | string \| null | Keychain identity for admin cert (when method is `"keychain"`) |
826
+ | `panelServerPubkeySha256` | string | The pin of the panel's TLS key for a panel reached at its IP address (see below) |
827
+ | `panelServerPinnedAt` | string | ISO 8601 timestamp of the pin |
828
+ | `panelServerPinSource` | string | `ssh`, `installer`, `local`, `agent`, `first-use` or `re-pin` (see below) |
826
829
 
827
830
  **Example:**
828
831
 
@@ -853,6 +856,8 @@ Stores the server registry for the desktop app's multi-server support. Created b
853
856
 
854
857
  **Notes on `adminAuth`:** When `adminAuth` is present and valid, the desktop app shows the Agents/Servers mode toggle in the sidebar. Cloud-provisioned servers populate `adminAuth` automatically (the admin certificate is downloaded during provisioning). For manually added servers, the user must import an admin certificate to enable Server mode.
855
858
 
859
+ **Panel key pin:** At its IP address (`https://<ip>:9292`) the panel serves a self-signed certificate, so the app verifies every call to it by `panelServerPubkeySha256` — the base64 SHA-256 of the certificate's public key (SubjectPublicKeyInfo), curl's `--pinnedpubkey sha256//…` form and the same value an agent's config holds. `panelServerPinSource` says where it came from: `ssh` (read from the server over SSH by cloud provisioning or an admin recovery), `installer` (a local install, from the installer's report), `local` (a local install imported, or installed by an older installer: read from the certificate file through `pkexec`), `agent` (migrated from the agent's `agent.json`), `first-use` (taken from the first connection) or `re-pin` (the user replaced it on the Servers page, the only way it changes). A panel reached at its domain has no pin: its Let's Encrypt certificate is verified normally. `sudo lamaste-server panel-pin` on the relay prints the value to compare with.
860
+
856
861
  **P12 password:** Not stored in the JSON file. Retrieved from the OS credential store (`com.lamalibre.lamaste.server` service, keyed by server UUID).
857
862
 
858
863
  **Cloud API token:** Not stored in this file. Retrieved from the OS credential store (`com.lamalibre.cloud` service).
@@ -920,7 +925,7 @@ Service files use per-agent names:
920
925
  - macOS: `com.lamalibre.lamaste.chisel-<label>` (plist label), `~/Library/LaunchAgents/com.lamalibre.lamaste.chisel-<label>.plist` — mode 0600, because it carries `AUTH` in `EnvironmentVariables`
921
926
  - Linux: `lamalibre-lamaste-chisel-<label>` (unit name), `~/.config/systemd/user/lamalibre-lamaste-chisel-<label>.service` — a systemd **user** unit with `EnvironmentFile=` pointing at `chisel.env`; enable lingering (`sudo loginctl enable-linger <user>`) for it to start at boot without a login
922
927
 
923
- Both run `chisel client --max-retry-interval 30s https://tunnel.<domain>:443 R:127.0.0.1:<port>:127.0.0.1:<port> ...` with TLS verification and no credential in argv. They are generated by `@lamalibre/lamaste@4.3.0/agent` (`chisel-service.ts`) and rewritten by `lamaste-agent setup`, `update` and `sync` — do not edit them by hand. An agent carrying no tunnels has its service unloaded (Chisel cannot run without a remote).
928
+ Both run `chisel client --max-retry-interval 30s https://tunnel.<domain>:443 R:127.0.0.1:<port>:127.0.0.1:<port> ...` with TLS verification and no credential in argv. They are generated by `@lamalibre/lamaste@4.3.1/agent` (`chisel-service.ts`) and rewritten by `lamaste-agent setup`, `update` and `sync` — do not edit them by hand. An agent carrying no tunnels has its service unloaded (Chisel cannot run without a remote).
924
929
 
925
930
  The sync timer, which runs `<node> <installed lamaste-agent> sync --label <label> --quiet` (`<node>` is a stable path such as `/opt/homebrew/bin/node` when one on `PATH` resolves to the running binary, so a Node.js upgrade does not break it):
926
931
 
@@ -24,7 +24,7 @@ If you are reading documentation and hit an unfamiliar term, this is the place t
24
24
 
25
25
  **Where it appears:**
26
26
 
27
- - Enrolled from the panel (**Certificates → Enrollment Token**) and `lamaste-agent setup` (installed globally with `npm install -g @lamalibre/lamaste-agent@4.3.0`)
27
+ - Enrolled from the panel (**Certificates → Enrollment Token**) and `lamaste-agent setup` (installed globally with `npm install -g @lamalibre/lamaste-agent@4.3.1`)
28
28
  - Agent registry: `/etc/lamalibre/lamaste/agents.json` on the server; `~/.lamalibre/lamaste/agents/<label>/` on the agent
29
29
  - The **Agent** column and field on the panel's Tunnels page
30
30
 
@@ -242,7 +242,7 @@ See also: [mTLS](#mtls-mutual-tls), [CA](#ca-certificate-authority), [PKCS12](#p
242
242
 
243
243
  **Where it appears:**
244
244
 
245
- - Generated by `lamaste-agent setup` / `update` (implementation in `@lamalibre/lamaste@4.3.0/agent`)
245
+ - Generated by `lamaste-agent setup` / `update` (implementation in `@lamalibre/lamaste@4.3.1/agent`)
246
246
  - Installed to `~/Library/LaunchAgents/com.lamalibre.lamaste.chisel-<label>.plist` on the agent
247
247
  - Manages the Chisel client process lifecycle
248
248
 
@@ -373,7 +373,7 @@ See also: [Client Certificate](#client-certificate), [CA](#ca-certificate-author
373
373
 
374
374
  **Plain English:** A small scheduled job on every agent that checks with the panel every 30 seconds and adjusts the tunnel client when the agent's tunnels changed — so tunnels created, disabled or moved in the panel reach the agent without anyone running a command on it.
375
375
 
376
- **Technical:** Runs `lamaste-agent sync --label <label>`, which fetches `GET /api/tunnels/agent-config` and converges the agent's Chisel client with it (relay URL, credential, pinned binary, granted remotes, running or stopped). It exists because Chisel rejects a client's whole session when one requested remote is not granted: an agent must drop a revoked tunnel promptly or all its other tunnels go dark. Requires a global install of `@lamalibre/lamaste-agent@4.3.0`.
376
+ **Technical:** Runs `lamaste-agent sync --label <label>`, which fetches `GET /api/tunnels/agent-config` and converges the agent's Chisel client with it (relay URL, credential, pinned binary, granted remotes, running or stopped). It exists because Chisel rejects a client's whole session when one requested remote is not granted: an agent must drop a revoked tunnel promptly or all its other tunnels go dark. Requires a global install of `@lamalibre/lamaste-agent@4.3.1`.
377
377
 
378
378
  **Where it appears:**
379
379
 
@@ -1,11 +1,11 @@
1
1
  # Installer Flags
2
2
 
3
- > CLI flags, environment variables, and exit codes for `npx @lamalibre/create-lamaste@4.3.0`.
3
+ > CLI flags, environment variables, and exit codes for `npx @lamalibre/create-lamaste@4.3.1`.
4
4
 
5
5
  ## Usage
6
6
 
7
7
  ```bash
8
- npx @lamalibre/create-lamaste@4.3.0 [flags]
8
+ npx @lamalibre/create-lamaste@4.3.1 [flags]
9
9
  ```
10
10
 
11
11
  The installer runs as root on a fresh Ubuntu 24.04 server. It is completely non-interactive by default — all configuration happens later through the browser-based onboarding wizard.
@@ -26,7 +26,7 @@ The installer runs as root on a fresh Ubuntu 24.04 server. It is completely non-
26
26
  Prints a description of what the installer does, lists all flags, and exits with code 0. Does not modify anything on the system.
27
27
 
28
28
  ```bash
29
- npx @lamalibre/create-lamaste@4.3.0 --help
29
+ npx @lamalibre/create-lamaste@4.3.1 --help
30
30
  ```
31
31
 
32
32
  ### `--yes`, `-y`
@@ -34,7 +34,7 @@ npx @lamalibre/create-lamaste@4.3.0 --help
34
34
  Skips the interactive confirmation prompt that appears before installation begins. Useful for automated deployments or scripts where you cannot press Enter.
35
35
 
36
36
  ```bash
37
- npx @lamalibre/create-lamaste@4.3.0 --yes
37
+ npx @lamalibre/create-lamaste@4.3.1 --yes
38
38
  ```
39
39
 
40
40
  Without this flag, the installer displays a banner listing all changes it will make and waits for the user to press Enter or Ctrl+C.
@@ -51,7 +51,7 @@ Skips all OS hardening tasks:
51
51
  Everything else (Node.js, nginx, mTLS, panel deployment) still runs.
52
52
 
53
53
  ```bash
54
- npx @lamalibre/create-lamaste@4.3.0 --skip-harden
54
+ npx @lamalibre/create-lamaste@4.3.1 --skip-harden
55
55
  ```
56
56
 
57
57
  Use this if you manage your own firewall rules, already have fail2ban configured, or are running on a platform that handles security at a different layer.
@@ -61,7 +61,7 @@ Use this if you manage your own firewall rules, already have fail2ban configured
61
61
  Allows the installer to run on a machine with a private or non-routable IP address (e.g., `192.168.x.x`, `10.x.x.x`). By default, the installer requires a public IP.
62
62
 
63
63
  ```bash
64
- npx @lamalibre/create-lamaste@4.3.0 --dev
64
+ npx @lamalibre/create-lamaste@4.3.1 --dev
65
65
  ```
66
66
 
67
67
  This is useful for:
@@ -76,7 +76,7 @@ When `--dev` is active, the installer prints the detected IP with a note: `(dev
76
76
  Forces the installer to run the complete installation pipeline, ignoring skip guards that would normally detect an existing installation. This is useful when an installation is in an inconsistent state and you want to ensure all components are fully deployed.
77
77
 
78
78
  ```bash
79
- npx @lamalibre/create-lamaste@4.3.0 --force-full
79
+ npx @lamalibre/create-lamaste@4.3.1 --force-full
80
80
  ```
81
81
 
82
82
  Use this if:
@@ -90,7 +90,7 @@ Use this if:
90
90
  Prints a step-by-step guide for manually removing Lamaste from the server, then exits with code 0. Does not modify anything on the system.
91
91
 
92
92
  ```bash
93
- npx @lamalibre/create-lamaste@4.3.0 --uninstall
93
+ npx @lamalibre/create-lamaste@4.3.1 --uninstall
94
94
  ```
95
95
 
96
96
  The printed guide first points to the automated removal, `sudo lamaste-server uninstall`, then covers:
@@ -207,25 +207,25 @@ Components that are always redeployed on re-run:
207
207
 
208
208
  ```bash
209
209
  ssh root@203.0.113.42
210
- npx @lamalibre/create-lamaste@4.3.0
210
+ npx @lamalibre/create-lamaste@4.3.1
211
211
  ```
212
212
 
213
213
  **Automated install (no confirmation prompt):**
214
214
 
215
215
  ```bash
216
- npx @lamalibre/create-lamaste@4.3.0 --yes
216
+ npx @lamalibre/create-lamaste@4.3.1 --yes
217
217
  ```
218
218
 
219
219
  **Install without OS hardening:**
220
220
 
221
221
  ```bash
222
- npx @lamalibre/create-lamaste@4.3.0 --yes --skip-harden
222
+ npx @lamalibre/create-lamaste@4.3.1 --yes --skip-harden
223
223
  ```
224
224
 
225
225
  **Test in a local VM:**
226
226
 
227
227
  ```bash
228
- npx @lamalibre/create-lamaste@4.3.0 --dev
228
+ npx @lamalibre/create-lamaste@4.3.1 --dev
229
229
  ```
230
230
 
231
231
  **Update an existing installation:**
@@ -237,7 +237,7 @@ npx @lamalibre/create-lamaste@latest --yes
237
237
  **View the uninstall guide:**
238
238
 
239
239
  ```bash
240
- npx @lamalibre/create-lamaste@4.3.0 --uninstall
240
+ npx @lamalibre/create-lamaste@4.3.1 --uninstall
241
241
  ```
242
242
 
243
243
  ## Quick Reference
@@ -34,7 +34,7 @@ A tunnel's port is also a loopback port on the relay: its vhost proxies to `127.
34
34
  | 9292 | IP-based panel listener |
35
35
  | 9294 | Gatekeeper |
36
36
 
37
- A tunnel on one of them would publish that internal service on a public hostname. For the panel that is an administrator takeover, not a leak: the panel trusts the client-certificate headers nginx sets. `RESERVED_TUNNEL_PORTS` in `@lamalibre/lamaste@4.3.0` is enforced by the request schema, inside the tunnel workflow, and again when the Chisel grants are rendered. Tunnel ports must also be 1024–65535.
37
+ A tunnel on one of them would publish that internal service on a public hostname. For the panel that is an administrator takeover, not a leak: the panel trusts the client-certificate headers nginx sets. `RESERVED_TUNNEL_PORTS` in `@lamalibre/lamaste@4.3.1` is enforced by the request schema, inside the tunnel workflow, and again when the Chisel grants are rendered. Tunnel ports must also be 1024–65535.
38
38
 
39
39
  ## Systemd Units
40
40