@lamalibre/create-lamaste 4.5.0 → 4.7.0
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/scripts/bundle-vendor.js +20 -3
- package/scripts/lamaste-priv +56 -5
- package/scripts/pin-release.js +98 -0
- package/src/index.js +8 -1
- package/src/lib/env.js +19 -0
- package/src/lib/service-config.js +7 -0
- package/src/tasks/redeploy.js +8 -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/authentication.md +6 -2
- package/vendor/docs/01-concepts/authorization.md +4 -0
- package/vendor/docs/01-concepts/certificates.md +3 -3
- package/vendor/docs/01-concepts/dns-and-domains.md +9 -0
- package/vendor/docs/01-concepts/mtls.md +2 -2
- package/vendor/docs/01-concepts/security-model.md +28 -3
- 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 +5 -5
- 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 +10 -10
- package/vendor/docs/02-guides/installation.md +3 -3
- package/vendor/docs/02-guides/managing-users.md +5 -11
- package/vendor/docs/02-guides/onboarding.md +2 -2
- package/vendor/docs/02-guides/second-domain.md +82 -0
- package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +2 -2
- package/vendor/docs/02-guides/static-sites.md +4 -0
- 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/nginx-configuration.md +80 -12
- package/vendor/docs/03-architecture/overview.md +5 -5
- package/vendor/docs/03-architecture/panel-client.md +6 -6
- package/vendor/docs/03-architecture/panel-server.md +2 -2
- package/vendor/docs/03-architecture/state-management.md +3 -3
- package/vendor/docs/03-architecture/system-overview.md +1 -1
- package/vendor/docs/04-api-reference/agent-hosted-plugins.md +116 -37
- package/vendor/docs/04-api-reference/app-host.md +3 -3
- package/vendor/docs/04-api-reference/domains.md +192 -0
- package/vendor/docs/04-api-reference/gatekeeper.md +54 -8
- package/vendor/docs/04-api-reference/lifecycle-hooks.md +4 -4
- package/vendor/docs/04-api-reference/onboarding.md +1 -1
- package/vendor/docs/04-api-reference/overview.md +9 -0
- package/vendor/docs/04-api-reference/registry-and-oidc.md +26 -13
- package/vendor/docs/04-api-reference/sites.md +9 -0
- package/vendor/docs/04-api-reference/tunnels.md +35 -28
- package/vendor/docs/04-api-reference/users.md +41 -29
- package/vendor/docs/05-operations/backup-and-restore.md +1 -1
- package/vendor/docs/05-operations/uninstalling.md +1 -1
- package/vendor/docs/05-operations/upgrades.md +15 -6
- package/vendor/docs/06-reference/config-files.md +19 -15
- 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/_index.json +105 -19
- package/vendor/docs/external-members-design.md +816 -0
- package/vendor/docs/gatekeeper-design.md +8 -8
- package/vendor/docs/identity-directory-design.md +3 -3
- package/vendor/docs/multi-domain-relay-design.md +836 -0
- package/vendor/docs/package.json +1 -1
- package/vendor/docs/todo/lib-cli-desktop-refactor.md +27 -27
- package/vendor/gatekeeper/dist/index.d.ts +3 -3
- package/vendor/gatekeeper/dist/index.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/index.js +2 -2
- package/vendor/gatekeeper/dist/index.js.map +1 -1
- package/vendor/gatekeeper/dist/lib/authz.d.ts +9 -0
- package/vendor/gatekeeper/dist/lib/authz.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/lib/authz.js +31 -0
- package/vendor/gatekeeper/dist/lib/authz.js.map +1 -1
- package/vendor/gatekeeper/dist/lib/constants.d.ts +5 -2
- package/vendor/gatekeeper/dist/lib/constants.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/lib/constants.js +5 -2
- package/vendor/gatekeeper/dist/lib/constants.js.map +1 -1
- package/vendor/gatekeeper/dist/lib/grants.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/lib/grants.js +20 -13
- package/vendor/gatekeeper/dist/lib/grants.js.map +1 -1
- package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0004_unconsume_access_grants.sql +8 -0
- package/vendor/gatekeeper/dist/lib/secret.d.ts +6 -0
- package/vendor/gatekeeper/dist/lib/secret.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/secret.js +12 -0
- package/vendor/gatekeeper/dist/lib/secret.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/templates.d.ts +20 -0
- package/vendor/gatekeeper/dist/lib/templates.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/lib/templates.js +80 -14
- package/vendor/gatekeeper/dist/lib/templates.js.map +1 -1
- package/vendor/gatekeeper/dist/lib/tunnels.d.ts +3 -6
- package/vendor/gatekeeper/dist/lib/tunnels.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/lib/tunnels.js +4 -16
- package/vendor/gatekeeper/dist/lib/tunnels.js.map +1 -1
- package/vendor/gatekeeper/dist/lib/types.d.ts +0 -19
- package/vendor/gatekeeper/dist/lib/types.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/index.d.ts +6 -1
- package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/index.js +56 -11
- package/vendor/gatekeeper/dist/server/index.js.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/authz.js +325 -55
- package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/diagnostic.js +5 -2
- package/vendor/gatekeeper/dist/server/routes/diagnostic.js.map +1 -1
- package/vendor/gatekeeper/package.json +2 -2
- package/vendor/server/bin/lamaste-server.js +7 -0
- package/vendor/server/package.json +2 -2
- package/vendor/server/src/commands/domains.js +214 -0
- package/vendor/server/src/commands/plugin-identity.js +2 -16
- package/vendor/server/src/commands/plugin-web-surface.js +269 -0
- package/vendor/server/src/commands/plugins.js +175 -14
- package/vendor/server/src/commands/registry-credential.js +10 -3
- package/vendor/server/src/commands/sites.js +18 -1
- package/vendor/server/src/commands/status.js +19 -0
- package/vendor/server/src/commands/tunnels.js +4 -1
- package/vendor/server/src/commands/users.js +8 -19
- package/vendor/server/src/domains.js +92 -0
- package/vendor/server/src/fail.js +21 -0
- package/vendor/server/src/oidc-client-grants.js +63 -0
- package/vendor/server/src/panel-api.js +15 -0
- package/vendor/server/src/plugin-approval.js +80 -1
- package/vendor/server/src/plugin-web-surface.js +307 -0
- package/vendor/server-ui/dist/assets/index-B8Tv_ocF.js +84 -0
- package/vendor/server-ui/dist/assets/index-Cb-ADsbB.css +1 -0
- package/vendor/server-ui/dist/index.html +2 -2
- package/vendor/serverd/package.json +2 -2
- package/vendor/serverd/src/index.js +50 -19
- package/vendor/serverd/src/lib/app-error.js +24 -0
- package/vendor/serverd/src/lib/audience.js +12 -3
- package/vendor/serverd/src/lib/authelia.js +341 -35
- package/vendor/serverd/src/lib/chisel-runtime.js +18 -6
- package/vendor/serverd/src/lib/chisel.js +10 -2
- package/vendor/serverd/src/lib/directory.js +67 -52
- package/vendor/serverd/src/lib/domains.js +1792 -0
- package/vendor/serverd/src/lib/gatekeeper-client.js +34 -7
- package/vendor/serverd/src/lib/hook-pipelines.js +8 -3
- package/vendor/serverd/src/lib/identity-sync.js +35 -0
- package/vendor/serverd/src/lib/migrations/state/0015_plugin_web_surface.sql +14 -0
- package/vendor/serverd/src/lib/migrations/state/0016_domains.sql +53 -0
- package/vendor/serverd/src/lib/migrations/state/0017_membership_kind.sql +15 -0
- package/vendor/serverd/src/lib/migrations/state/0018_domain_group_keys.sql +23 -0
- package/vendor/serverd/src/lib/nginx.js +576 -131
- package/vendor/serverd/src/lib/owned-groups.js +326 -0
- package/vendor/serverd/src/lib/plugin-domain.js +86 -0
- package/vendor/serverd/src/lib/plugin-hooks.js +40 -11
- package/vendor/serverd/src/lib/plugin-lifecycle.js +129 -5
- package/vendor/serverd/src/lib/plugin-oidc.js +144 -42
- package/vendor/serverd/src/lib/plugin-packages.js +74 -2
- package/vendor/serverd/src/lib/plugins.js +82 -9
- package/vendor/serverd/src/lib/registry-credential.js +39 -6
- package/vendor/serverd/src/lib/services.js +9 -1
- package/vendor/serverd/src/lib/state.js +29 -0
- package/vendor/serverd/src/lib/tunnel-deps.js +2 -4
- package/vendor/serverd/src/lib/user-surface.js +77 -31
- package/vendor/serverd/src/lib/users-lock.js +23 -0
- package/vendor/serverd/src/lib/vhost-reconcile.js +151 -41
- package/vendor/serverd/src/lib/web-surface.js +783 -0
- package/vendor/serverd/src/middleware/user-access-session.js +11 -4
- package/vendor/serverd/src/routes/invite.js +15 -5
- package/vendor/serverd/src/routes/management/domains.js +154 -0
- package/vendor/serverd/src/routes/management/gatekeeper-proxy.js +44 -8
- package/vendor/serverd/src/routes/management/identity.js +21 -7
- package/vendor/serverd/src/routes/management/invitations.js +33 -4
- package/vendor/serverd/src/routes/management/plugin-web-surface.js +151 -0
- package/vendor/serverd/src/routes/management/plugins.js +6 -2
- package/vendor/serverd/src/routes/management/registry-credential.js +86 -57
- package/vendor/serverd/src/routes/management/sites.js +188 -71
- package/vendor/serverd/src/routes/management/tunnels.js +37 -22
- package/vendor/serverd/src/routes/management/users.js +184 -64
- package/vendor/serverd/src/routes/management.js +4 -0
- package/vendor/serverd/src/routes/onboarding/dns.js +3 -17
- package/vendor/serverd/src/routes/onboarding/provision.js +22 -13
- package/vendor/serverd/src/routes/user-access.js +13 -1
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0001_groups.sql +0 -7
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0002_access_grants.sql +0 -14
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0003_access_request_log.sql +0 -9
- package/vendor/server-ui/dist/assets/index-D-fer5ef.css +0 -1
- package/vendor/server-ui/dist/assets/index-DSaDPJaw.js +0 -84
|
@@ -204,7 +204,7 @@ Identical to the IP vhost except:
|
|
|
204
204
|
- `server_name` is `panel.<domain>`
|
|
205
205
|
- Requires the `map $http_upgrade $connection_upgrade` block from the IP vhost (or a shared config) to be present
|
|
206
206
|
|
|
207
|
-
### 3. Auth Vhost (`lamalibre-lamaste-auth
|
|
207
|
+
### 3. Auth Vhost (`lamalibre-lamaste-auth-<domain>`)
|
|
208
208
|
|
|
209
209
|
Created during onboarding provisioning. Serves the Authelia authentication portal.
|
|
210
210
|
|
|
@@ -282,7 +282,7 @@ Key characteristics:
|
|
|
282
282
|
- 24-hour read/send timeouts to keep tunnel connections alive without nginx closing them
|
|
283
283
|
- No mTLS and no Authelia — Chisel handles its own authentication
|
|
284
284
|
|
|
285
|
-
### 5. App Vhost (`lamalibre-lamaste-app-<
|
|
285
|
+
### 5. App Vhost (`lamalibre-lamaste-app-<fqdn>`)
|
|
286
286
|
|
|
287
287
|
Created when a tunnel is added via the management UI or `POST /api/tunnels`. Each tunnel gets its own vhost, rendered by one of three writers according to the tunnel's `accessMode`:
|
|
288
288
|
|
|
@@ -410,7 +410,65 @@ Optional Authelia protection is controlled by the `autheliaProtected` flag on th
|
|
|
410
410
|
|
|
411
411
|
A custom-domain site may list `aliases` (e.g. `www.myblog.net`). They are served by a second server block that answers with a 301 to the primary host. One certificate lineage, named after the site's domain (`certbot certonly --nginx --cert-name <fqdn> -d <fqdn> -d <alias> ...`), covers the primary name and every alias, so both blocks point at the same `live/<fqdn>/` directory.
|
|
412
412
|
|
|
413
|
-
###
|
|
413
|
+
### Web-surface vhosts
|
|
414
|
+
|
|
415
|
+
A site a plugin owns for its [web surface](../04-api-reference/agent-hosted-plugins.md#web-surface) has a vhost of its own kind under the site name (`lamalibre-lamaste-site-<id>`), rendered by the panel from the plugin's state (`renderWebSurfaceVhost`) — never by the static-site generator. While the surface is served:
|
|
416
|
+
|
|
417
|
+
```nginx
|
|
418
|
+
server {
|
|
419
|
+
listen 443 ssl;
|
|
420
|
+
server_name piyasa.example.com;
|
|
421
|
+
ssl_certificate /etc/letsencrypt/live/piyasa.example.com/fullchain.pem;
|
|
422
|
+
ssl_certificate_key /etc/letsencrypt/live/piyasa.example.com/privkey.pem;
|
|
423
|
+
|
|
424
|
+
root /var/www/lamaste/apps/market-indicators/current;
|
|
425
|
+
index index.html;
|
|
426
|
+
|
|
427
|
+
# Every path of the shell: Gatekeeper first (the API's locations ask on their own)
|
|
428
|
+
auth_request /internal/lamaste/shell-authz;
|
|
429
|
+
error_page 401 =302 https://auth.example.com/?rd=https://piyasa.example.com$request_uri;
|
|
430
|
+
error_page 403 = /internal/lamaste/shell-authz;
|
|
431
|
+
|
|
432
|
+
location = /internal/lamaste/shell-authz {
|
|
433
|
+
internal;
|
|
434
|
+
auth_request off;
|
|
435
|
+
proxy_pass http://127.0.0.1:9294/authz/user-surface-shell/piyasa.example.com;
|
|
436
|
+
# ... as every Gatekeeper subrequest
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
# /internal/lamaste/user-surface-authz, -401 and the /api/market-indicators/app
|
|
440
|
+
# locations — exactly the user-surface locations of a bound tunnel
|
|
441
|
+
|
|
442
|
+
# A script, style, font or image the current tree lacks: the previous
|
|
443
|
+
# tree's (a page still running the old shell), else 404
|
|
444
|
+
location ~* [.](?:js|mjs|css|woff2?|ttf|otf|png|jpe?g|gif|webp|avif|ico)$ {
|
|
445
|
+
if ($request_method !~ ^(GET|HEAD)$) { return 405; }
|
|
446
|
+
if ($http_service_worker) { return 404; }
|
|
447
|
+
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; ..." always;
|
|
448
|
+
# X-Content-Type-Options, X-Frame-Options DENY, Referrer-Policy, COOP, CORP, Cache-Control no-cache
|
|
449
|
+
types { text/javascript js mjs; text/css css; ... } # core WEB_TREE_CONTENT_TYPES
|
|
450
|
+
try_files $uri @previous;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
# Everything else: the current tree's file, else the shell
|
|
454
|
+
location / {
|
|
455
|
+
# the same method check, worker refusal, headers and types
|
|
456
|
+
try_files $uri /index.html;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
location @previous {
|
|
460
|
+
# the same headers and types
|
|
461
|
+
root /var/www/lamaste/apps/market-indicators/previous;
|
|
462
|
+
try_files $uri =404;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
`auth_request` sits at server level so every location of the shell asks Gatekeeper — the API's locations name their own subrequest, and the internal ones turn it `off`. The API's prefix location is `^~`, so the subresource regex never takes an API path. The shell's headers are set in its locations only: the API's answers are the panel's to head. A document, an SVG or a manifest is never served from the previous tree, and a service worker's script (`Service-Worker: script`) is always `404` — a worker would outlive the tree that installed it. The `types` block names each extension's content type from core's list (`lamaste-priv` accepts a `types` block in a location — `media/type ext…` entries only, no `include`) rather than trust the host's `mime.types`, which differs between nginx versions. `current` and `previous` are links the panel switches with a rename (see [Serving the tree](../04-api-reference/agent-hosted-plugins.md#serving-the-tree)); nginx follows them per request. While the surface is not served, the vhost answers everything with `503` (`Cache-Control: no-store`, a worker's script `404`) — and, once the plugin is uninstalled, `Clear-Site-Data: "storage"`.
|
|
468
|
+
|
|
469
|
+
Moving a bound tunnel's host to a web surface hands the hostname over in **one reload**: the tunnel's vhost is unlinked, the site's written and linked, `nginx -t` run, nginx reloaded once; the tunnel's file stays installed, unlinked, so the tunnel can be enabled again once the site is deleted. On a failed test both are put back.
|
|
470
|
+
|
|
471
|
+
### 7. Public Tunnel Vhost (`lamalibre-lamaste-app-<fqdn>`, access mode: public)
|
|
414
472
|
|
|
415
473
|
Created when a tunnel is configured with public access. Direct proxy with no authentication.
|
|
416
474
|
|
|
@@ -447,7 +505,7 @@ server {
|
|
|
447
505
|
|
|
448
506
|
No `auth_request`, no Authelia, no Gatekeeper. Traffic is proxied directly to the tunneled app. Use only for services that handle their own authentication or are intentionally public.
|
|
449
507
|
|
|
450
|
-
### 8. Authenticated Tunnel Vhost (`lamalibre-lamaste-app-<
|
|
508
|
+
### 8. Authenticated Tunnel Vhost (`lamalibre-lamaste-app-<fqdn>`, access mode: authenticated)
|
|
451
509
|
|
|
452
510
|
Created when a tunnel requires Authelia login but no per-user grant checking. Any authenticated Authelia user can access the tunnel.
|
|
453
511
|
|
|
@@ -524,7 +582,7 @@ Key characteristics:
|
|
|
524
582
|
|
|
525
583
|
> **Note:** The `lamalibre-lamaste-authz-cache.conf` nginx snippet is installed by the Gatekeeper installer task, but the generated vhosts do not currently include `proxy_cache` directives. Authorization caching relies on the Gatekeeper's in-memory session cache (30-second TTL) rather than nginx-level proxy caching.
|
|
526
584
|
|
|
527
|
-
### 9. Restricted Tunnel Vhost (`lamalibre-lamaste-app-<
|
|
585
|
+
### 9. Restricted Tunnel Vhost (`lamalibre-lamaste-app-<fqdn>`, access mode: restricted)
|
|
528
586
|
|
|
529
587
|
Created when a tunnel requires both Authelia login and an explicit access grant. Only users with a matching grant in Gatekeeper (`gatekeeper.db`) can access the tunnel.
|
|
530
588
|
|
|
@@ -642,7 +700,7 @@ An `authenticated` or `restricted` app tunnel bound as the user surface of agent
|
|
|
642
700
|
# The user surface of plugin "market-indicators"
|
|
643
701
|
location = /api/market-indicators/app { ... } # the same block as below
|
|
644
702
|
|
|
645
|
-
location /api/market-indicators/app/ {
|
|
703
|
+
location ^~ /api/market-indicators/app/ {
|
|
646
704
|
auth_request /internal/lamaste/user-surface-authz;
|
|
647
705
|
auth_request_set $relay_assertion $upstream_http_x_lamalibre_relay_assertion;
|
|
648
706
|
|
|
@@ -699,6 +757,16 @@ Gatekeeper authorizes the tunnel named in the path, and refuses a check whose `X
|
|
|
699
757
|
|
|
700
758
|
Authelia evaluates the raw `$request_uri`, while nginx serves the normalized `$uri` (`/a/../b` is `/b`, `%2e` is `.`). Lamaste writes no path (`resources`) rules into Authelia's `access_control`, only hostname rules; a path rule added by hand would see a different path than nginx serves.
|
|
701
759
|
|
|
760
|
+
## Vhosts on several domains
|
|
761
|
+
|
|
762
|
+
A relay may serve several base domains ([Domains API](../04-api-reference/domains.md)). Vhost files are therefore named by full hostname — `lamalibre-lamaste-app-<fqdn>`, `lamalibre-lamaste-agent-panel-<fqdn>`, `lamalibre-lamaste-auth-<domain>` — so the same subdomain on two domains never shares a file. At start the panel renames vhosts written under the earlier names (`lamalibre-lamaste-app-<subdomain>`, `lamalibre-lamaste-agent-panel-<subdomain>`, `lamalibre-lamaste-auth`): the new file is written with the old one's link state, the old file and link removed, then one `nginx -t` and reload, with the old files restored if the test fails. `lamaste-priv` accepts the hostname names for every action and the legacy names for everything but `write`.
|
|
763
|
+
|
|
764
|
+
- **One auth vhost per active domain** (`auth.<domain>`, its own certificate). Only the primary's carries `/api/user-access/authorize` and the `user_access_auth` rate-limit zone (desktop user access is primary-only); every domain's serves `/`, `/invite/` and `/api/invite/`.
|
|
765
|
+
- **The 401 redirect** of tunnel and web-surface vhosts goes to `https://auth.<the host's domain>/?rd=…`; static sites follow Authelia's `$redirection_url`, which Authelia builds for the host's cookie domain.
|
|
766
|
+
- **A 403** from Gatekeeper (a signed-in non-member, or a missing grant) is served inline; Authelia-protected static sites route `error_page 403` to Gatekeeper's `/authz/refusal/<fqdn>`.
|
|
767
|
+
- **Authenticated and restricted tunnels share one vhost** (`writeGatekeeperVhost`): Gatekeeper decides by the access mode in `tunnels.json`.
|
|
768
|
+
- **Certificates** stay HTTP-01 per hostname; a wildcard is used when one for the host's domain is already present.
|
|
769
|
+
|
|
702
770
|
## The backend cookie map
|
|
703
771
|
|
|
704
772
|
Authelia's session cookie (`authelia_session`, the name core configures in `server/authelia.ts` and exports as `AUTHELIA_SESSION_COOKIE`) is scoped to the base domain, so a browser sends it to every host under it. No tunnel or agent backend may receive it: every location that proxies to one sends
|
|
@@ -852,12 +920,12 @@ nginx's master process runs as root and opens the files a configuration names
|
|
|
852
920
|
- its **name** is one the panel manages: `lamalibre-lamaste-panel-domain`, `-auth`, `-tunnel`, `-app-<subdomain>`, `-agent-panel-<label>` or `-site-<uuid>`. `lamalibre-lamaste-panel-ip` (written by the installer) may only be enabled or disabled — which is how panel 2FA turns the IP vhost off;
|
|
853
921
|
- every **directive** is on the allow-list for its context, with arguments that cannot name a file outside what Lamaste serves:
|
|
854
922
|
|
|
855
|
-
| Context | Allowed
|
|
856
|
-
| ---------- |
|
|
857
|
-
| top level | `server`, `map` (plain `key value;` entries, no `include`), `limit_req_zone`
|
|
858
|
-
| `server` | `listen 443` / `[::]:443` with optional `ssl` / `http2`; `server_name` (hostnames); `ssl_certificate(_key)` only `/etc/letsencrypt/live/<name>/{fullchain,privkey}.pem`; `include` only `/etc/nginx/snippets/lamalibre-lamaste-*.conf`; `root` only under `/var/www/lamaste/`; `ssl_protocols`, `ssl_ciphers`, `ssl_prefer_server_ciphers`, `client_max_body_size`, `index`, `add_header`, `proxy_set_header`, `error_page`, `return`, `rewrite`, `location` |
|
|
859
|
-
| `location` | `proxy_pass` only `http://127.0.0.1:<port>[/path]`; `root` / `alias` only under `/var/www/lamaste/`; `proxy_set_header`, `proxy_http_version`, `proxy_read_timeout`, `proxy_send_timeout`, `proxy_buffers`, `proxy_next_upstream`, `proxy_pass_request_body`, `auth_request`, `auth_request_set`, `limit_req`, `try_files
|
|
860
|
-
| `if` | `return`, `rewrite`
|
|
923
|
+
| Context | Allowed |
|
|
924
|
+
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
925
|
+
| top level | `server`, `map` (plain `key value;` entries, no `include`), `limit_req_zone` |
|
|
926
|
+
| `server` | `listen 443` / `[::]:443` with optional `ssl` / `http2`; `server_name` (hostnames); `ssl_certificate(_key)` only `/etc/letsencrypt/live/<name>/{fullchain,privkey}.pem`; `include` only `/etc/nginx/snippets/lamalibre-lamaste-*.conf`; `root` only under `/var/www/lamaste/`; `auth_request` only a URI of the server or `off`; `ssl_protocols`, `ssl_ciphers`, `ssl_prefer_server_ciphers`, `client_max_body_size`, `index`, `add_header`, `proxy_set_header`, `error_page`, `return`, `rewrite`, `location` (a path, or a named location `@name`) |
|
|
927
|
+
| `location` | `proxy_pass` only `http://127.0.0.1:<port>[/path]`; `root` / `alias` only under `/var/www/lamaste/`; `proxy_set_header`, `proxy_http_version`, `proxy_read_timeout`, `proxy_send_timeout`, `proxy_buffers`, `proxy_next_upstream`, `proxy_pass_request_body`, `auth_request`, `auth_request_set`, `limit_req`, `try_files` (the last argument may name a location, `@name`), `index`, `add_header`, `error_page`, `client_max_body_size`, `internal`, `return`, `rewrite`, `if`, nested `location` |
|
|
928
|
+
| `if` | `return`, `rewrite` |
|
|
861
929
|
|
|
862
930
|
Port 80 is not allowed: it belongs to the installer's HTTPS redirect and to certbot's HTTP-01 challenges. Backslashes, `${`, control characters and non-ASCII text outside comments are refused rather than interpreted, as is any directive not listed — including ones nginx would accept (`access_log`, `log_format`, `ssl_*` files elsewhere, `proxy_pass` to another host, ...). A refused `write` fails with `nginx site write failed for <name>: lamaste-priv: vhost line <n>: ...` and leaves the previous vhost in place.
|
|
863
931
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Lamaste has three main pieces:
|
|
8
8
|
|
|
9
|
-
1. **The Installer** (`npx @lamalibre/create-lamaste@4.
|
|
9
|
+
1. **The Installer** (`npx @lamalibre/create-lamaste@4.7.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.
|
|
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
|
|
|
@@ -318,7 +318,7 @@ lamaste/
|
|
|
318
318
|
│ │ ├── files.js ← Static site file operations (upload, delete, list)
|
|
319
319
|
│ │ └── app-error.js ← Operational error class (AppError)
|
|
320
320
|
│ │
|
|
321
|
-
│ ├── lamaste-server-ui/ ← React 18 + Vite + Tailwind SPA + shared admin components (@lamalibre/lamaste-server-ui@4.
|
|
321
|
+
│ ├── lamaste-server-ui/ ← React 18 + Vite + Tailwind SPA + shared admin components (@lamalibre/lamaste-server-ui@4.7.0)
|
|
322
322
|
│ │ └── src/
|
|
323
323
|
│ │ ├── index.js ← Package exports (pages, context, utilities)
|
|
324
324
|
│ │ ├── context/
|
|
@@ -334,7 +334,7 @@ lamaste/
|
|
|
334
334
|
│ │ │ └── formatters.js ← Byte, uptime, relative time formatters
|
|
335
335
|
│ │ └── pages/ ← Admin pages (Dashboard, Tunnels, Sites, Users, Certs, Services, Plugins, Tickets, Settings)
|
|
336
336
|
│ │
|
|
337
|
-
│ ├── lamaste-agent-ui/ ← Shared React agent UI (pages, context, components) (@lamalibre/lamaste-agent-ui@4.
|
|
337
|
+
│ ├── lamaste-agent-ui/ ← Shared React agent UI (pages, context, components) (@lamalibre/lamaste-agent-ui@4.7.0)
|
|
338
338
|
│ │
|
|
339
339
|
│ ├── lamaste-tickets/ ← Agent-to-agent authorization SDK (mTLS, undici)
|
|
340
340
|
│ │ └── src/
|
|
@@ -374,7 +374,7 @@ lamaste/
|
|
|
374
374
|
│ │ │ └── CompleteStep.jsx ← Credentials + TOTP QR + next steps
|
|
375
375
|
│ │ ├── management/ ← Legacy standalone implementations (kept for reference)
|
|
376
376
|
│ │ │ ├── Certificates.jsx ← Standalone certificates page (dead code)
|
|
377
|
-
│ │ │ ├── Dashboard.jsx ← Standalone dashboard (not imported — App.jsx uses @lamalibre/lamaste-server-ui@4.
|
|
377
|
+
│ │ │ ├── Dashboard.jsx ← Standalone dashboard (not imported — App.jsx uses @lamalibre/lamaste-server-ui@4.7.0)
|
|
378
378
|
│ │ │ ├── Plugins.jsx ← Standalone plugins page (dead code)
|
|
379
379
|
│ │ │ ├── Services.jsx ← Standalone services page (dead code)
|
|
380
380
|
│ │ │ ├── Settings.jsx ← Standalone settings page (dead code)
|
|
@@ -483,7 +483,7 @@ The Panel Server runs as the `lamaste` user with minimal privileges and cannot b
|
|
|
483
483
|
The full lifecycle of a Lamaste installation:
|
|
484
484
|
|
|
485
485
|
```
|
|
486
|
-
Phase 1: Installation (npx @lamalibre/create-lamaste@4.
|
|
486
|
+
Phase 1: Installation (npx @lamalibre/create-lamaste@4.7.0)
|
|
487
487
|
└─ OS hardening, Node.js, mTLS certs, nginx, panel deploy
|
|
488
488
|
└─ Result: Panel accessible at https://<ip>:9292
|
|
489
489
|
|
|
@@ -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.
|
|
13
|
+
The management-mode admin pages (Dashboard, Tunnels, Sites, Users, Certificates, Services, Plugins, Tickets, Logs, Settings) live in `@lamalibre/lamaste-server-ui@4.7.0`. 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.
|
|
15
|
+
The agent-mode pages (Dashboard, Tunnels, Services, Plugins, Logs, Settings) are extracted into a separate shared package: `@lamalibre/lamaste-agent-ui@4.7.0`. 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.
|
|
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.7.0` 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.
|
|
354
|
-
3. **ToastProvider** — from `@lamalibre/lamaste-server-ui@4.
|
|
355
|
-
4. **TwoFaProvider** — from `@lamalibre/lamaste-server-ui@4.
|
|
353
|
+
2. **AdminClientProvider** — from `@lamalibre/lamaste-server-ui@4.7.0`, supplies the host-specific data client (`webAdminClient` for browser fetch, Tauri `invoke` for desktop)
|
|
354
|
+
3. **ToastProvider** — from `@lamalibre/lamaste-server-ui@4.7.0`, notification toast system
|
|
355
|
+
4. **TwoFaProvider** — from `@lamalibre/lamaste-server-ui@4.7.0`, 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.
|
|
456
|
+
- Thin shim over `@lamalibre/lamaste@4.7.0/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
|
|
@@ -536,7 +536,7 @@ Agent-to-agent authorization with scopes, instances, tickets, and sessions. Prov
|
|
|
536
536
|
- **Periodic cleanup** — stale/dead instances, expired tickets, dead sessions
|
|
537
537
|
- **Concurrency** — promise-chain mutex with atomic file writes (temp → fsync → rename)
|
|
538
538
|
|
|
539
|
-
Client SDK: `@lamalibre/lamaste-tickets@4.
|
|
539
|
+
Client SDK: `@lamalibre/lamaste-tickets@4.7.0` (TypeScript, undici) provides `TicketClient`, `TicketInstanceManager` (source side), and `TicketSessionManager` (target side) for plugin integration.
|
|
540
540
|
|
|
541
541
|
State files: `/etc/lamalibre/lamaste/ticket-scopes.json` (scopes, instances, assignments) and `/etc/lamalibre/lamaste/tickets.json` (tickets, sessions).
|
|
542
542
|
|
|
@@ -329,7 +329,7 @@ Read returns `[]` for missing files (ENOENT), enabling the system to start with
|
|
|
329
329
|
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
|
|
330
330
|
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
|
|
331
331
|
|
|
332
|
-
Every one of these workflows runs under the single tunnel lock (`withTunnelLock` in `@lamalibre/lamaste@4.
|
|
332
|
+
Every one of these workflows runs under the single tunnel lock (`withTunnelLock` in `@lamalibre/lamaste@4.7.0/server`), with its validation inside the lock.
|
|
333
333
|
|
|
334
334
|
## Site State (`sites.json`)
|
|
335
335
|
|
|
@@ -391,7 +391,7 @@ The Panel Server writes Authelia's files itself, without sudo (`writeAutheliaFil
|
|
|
391
391
|
2. `rename()`s it over the destination — atomic on the same filesystem, so Authelia never reads a partial file
|
|
392
392
|
3. The mode decides Authelia's access: `users.yml` `0660` (Authelia rewrites it when a user changes a password), `configuration.yml` `0640`, `.secrets.json` `0600` (the panel only)
|
|
393
393
|
|
|
394
|
-
**Critical invariant:**
|
|
394
|
+
**Critical invariant:** Authelia must see every write of `users.yml`. Authelia watches `users.yml` (`authentication_backend.file.watch: true`) and reloads it in place; with the watch it re-reads a user's details at each of their requests, so a change applies at the user's next request without a restart and without ending anyone else's session. It skips a reload within 0.5 s of the previous one, so the panel writes the file once more 0.6 s after its last write. Every write goes through one file lock in the panel (`lib/authelia.js`), which also keeps the groups Lamaste owns as the last rendering decided.
|
|
395
395
|
|
|
396
396
|
**Safety rule:** The Panel Server prevents deleting the last user in the Authelia database. Without at least one user, no one could authenticate to access tunneled apps.
|
|
397
397
|
|
|
@@ -482,7 +482,7 @@ The PKI directory belongs to `lamaste` because the panel is the CA (it signs age
|
|
|
482
482
|
|
|
483
483
|
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:
|
|
484
484
|
|
|
485
|
-
**Tunnel state** is guarded by one promise-chain lock, `withTunnelLock` in `@lamalibre/lamaste@4.
|
|
485
|
+
**Tunnel state** is guarded by one promise-chain lock, `withTunnelLock` in `@lamalibre/lamaste@4.7.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.
|
|
486
486
|
|
|
487
487
|
**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.
|
|
488
488
|
|
|
@@ -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.
|
|
61
|
+
│ │ │ (pages from @lamalibre/lamaste-agent-ui@4.7.0) │ │
|
|
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) │ │
|