@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.
- package/package.json +2 -2
- package/src/lib/service-config.js +6 -0
- package/vendor/docs/00-introduction/how-it-works.md +2 -2
- package/vendor/docs/00-introduction/quickstart.md +5 -5
- package/vendor/docs/00-introduction/what-is-lamaste.md +5 -5
- package/vendor/docs/01-concepts/certificates.md +3 -3
- package/vendor/docs/01-concepts/mtls.md +2 -2
- package/vendor/docs/01-concepts/security-model.md +38 -1
- package/vendor/docs/01-concepts/tickets.md +2 -2
- package/vendor/docs/01-concepts/tunneling.md +4 -4
- package/vendor/docs/02-guides/agent-setup.md +6 -6
- package/vendor/docs/02-guides/certificate-management.md +2 -2
- package/vendor/docs/02-guides/cloud-provisioning.md +3 -3
- package/vendor/docs/02-guides/desktop-app-setup.md +11 -11
- package/vendor/docs/02-guides/installation.md +3 -3
- package/vendor/docs/02-guides/onboarding.md +2 -2
- package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +2 -2
- package/vendor/docs/03-architecture/installer-flow.md +2 -2
- package/vendor/docs/03-architecture/installer.md +4 -4
- package/vendor/docs/03-architecture/management-flow.md +1 -1
- package/vendor/docs/03-architecture/overview.md +5 -5
- package/vendor/docs/03-architecture/panel-client.md +7 -7
- package/vendor/docs/03-architecture/panel-server.md +2 -2
- package/vendor/docs/03-architecture/state-management.md +2 -2
- package/vendor/docs/03-architecture/system-overview.md +1 -1
- package/vendor/docs/04-api-reference/agent-hosted-plugins.md +394 -34
- package/vendor/docs/04-api-reference/app-host.md +87 -38
- package/vendor/docs/04-api-reference/audit-and-notifications.md +10 -10
- package/vendor/docs/04-api-reference/certificates.md +22 -19
- package/vendor/docs/04-api-reference/lifecycle-hooks.md +34 -12
- package/vendor/docs/04-api-reference/onboarding.md +1 -1
- package/vendor/docs/04-api-reference/overview.md +137 -135
- package/vendor/docs/04-api-reference/registry-and-oidc.md +3 -1
- package/vendor/docs/04-api-reference/tunnels.md +14 -10
- package/vendor/docs/05-operations/backup-and-restore.md +2 -1
- package/vendor/docs/05-operations/uninstalling.md +1 -1
- package/vendor/docs/05-operations/upgrades.md +6 -6
- package/vendor/docs/06-reference/config-files.md +90 -85
- package/vendor/docs/06-reference/glossary.md +3 -3
- package/vendor/docs/06-reference/installer-flags.md +13 -13
- package/vendor/docs/06-reference/ports-and-services.md +1 -1
- package/vendor/docs/06-reference/troubleshooting.md +8 -8
- package/vendor/docs/gatekeeper-design.md +8 -8
- package/vendor/docs/identity-directory-design.md +2 -2
- package/vendor/docs/package.json +1 -1
- package/vendor/docs/todo/lib-cli-desktop-refactor.md +27 -27
- package/vendor/gatekeeper/package.json +2 -2
- package/vendor/server/bin/lamaste-server.js +4 -1
- package/vendor/server/package.json +4 -3
- package/vendor/server/src/commands/plugin-settings.js +541 -0
- package/vendor/server/src/commands/plugins.js +94 -27
- package/vendor/server/src/panel-api.js +36 -4
- package/vendor/server/src/plugin-approval.js +78 -0
- package/vendor/server/src/plugin-settings.js +699 -0
- package/vendor/server-ui/dist/assets/index-25wo_8av.css +1 -0
- package/vendor/server-ui/dist/assets/index-roDHz3dM.js +84 -0
- package/vendor/server-ui/dist/index.html +2 -2
- package/vendor/serverd/package.json +2 -2
- package/vendor/serverd/src/index.js +9 -0
- package/vendor/serverd/src/lib/agent-presence.js +106 -0
- package/vendor/serverd/src/lib/hook-pipelines.js +20 -4
- package/vendor/serverd/src/lib/migrations/state/0012_plugin_settings_and_presence.sql +62 -0
- package/vendor/serverd/src/lib/mtls.js +44 -4
- package/vendor/serverd/src/lib/plugin-hooks.js +120 -20
- package/vendor/serverd/src/lib/plugin-hosting.js +35 -14
- package/vendor/serverd/src/lib/plugin-lifecycle.js +267 -83
- package/vendor/serverd/src/lib/plugin-packages.js +30 -22
- package/vendor/serverd/src/lib/plugin-settings.js +1101 -0
- package/vendor/serverd/src/lib/plugins.js +108 -33
- package/vendor/serverd/src/lib/registry-credential.js +37 -0
- package/vendor/serverd/src/lib/tunnel-hooks.js +11 -0
- package/vendor/serverd/src/routes/management/plugins.js +166 -19
- package/vendor/serverd/src/routes/management/tunnels.js +21 -1
- package/vendor/server-ui/dist/assets/index-BTlBt_cD.js +0 -84
- 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
|
+
"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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
267
|
+
### Client SDK (`@lamalibre/lamaste-tickets@4.4.1`)
|
|
268
268
|
|
|
269
|
-
The `@lamalibre/lamaste-tickets@4.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
207
|
-
| **Update** | `npx @lamalibre/create-lamaste-desktop@4.
|
|
208
|
-
| **Agent setup** | `npm install -g @lamalibre/lamaste-agent@4.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|