@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
|
@@ -164,7 +164,7 @@ Agents hold only the public key. The daemon fetches it, with the label the relay
|
|
|
164
164
|
|
|
165
165
|
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.
|
|
166
166
|
|
|
167
|
-
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.
|
|
167
|
+
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.7.0`) 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.
|
|
168
168
|
|
|
169
169
|
**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.
|
|
170
170
|
|
|
@@ -194,7 +194,7 @@ An agent-hosted plugin's settings may hold secrets — a data provider's API key
|
|
|
194
194
|
- **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.
|
|
195
195
|
- **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.
|
|
196
196
|
|
|
197
|
-
Agent halves built against `@lamalibre/lamaste@4.
|
|
197
|
+
Agent halves built against `@lamalibre/lamaste@4.7.0` 4.3 must be rebuilt: one that does not sign its answers is down to the relay.
|
|
198
198
|
|
|
199
199
|
**What a port's squatter still receives.** These mechanisms authenticate answers and seal secrets; they do not keep the relay from _sending_. A squatter cannot pass a single health probe (it holds no installation secret), so the health monitor marks the hosting down after three failed probes in a row, 10 s apart. From then on **neither forwarder sends anything to the port**: a user's request is answered `503` by the panel, and an administrator's or agent's request on the admin API is answered as a request into a dead tunnel is — the plugin's `tunnel:down` fallback, or `502` with the reason (`tunnel` or `app`) — without a connection being made. So a forwarded request — its method, path, query and body, and the caller assertion with an administrator, an agent, or a user's `userId`, username and roles — can reach a relay-loopback squatter only in the window before the hosting is marked down, about 30 seconds after the agent went away (and, when the agent comes back, a squatter that still holds the port is what the probes find: the hosting stays down). Lamaste's own calls do not go through the forwarders and keep reaching the port — the health probe has to, to see the agent half come back: their bodies are bound to their assertions and a settings change's secrets are sealed, so a squatter learns their non-secret content and nothing it can replay.
|
|
200
200
|
|
|
@@ -242,7 +242,7 @@ Gatekeeper attests the session; the panel issues the identity. Gatekeeper never
|
|
|
242
242
|
|
|
243
243
|
**Data minimisation.** A plugin always receives a user's `userId` and **username** — in the caller assertion of every request and in every member and last-known record of its feed — and of the other attributes only those its manifest declares (`displayName`, `email`); widening them waits for an administrator's approval that auto-approve never gives (`identity.changed`). Nothing identity is ever sent to a plugin that does not declare `identity`. A user who leaves keeps, on the plugin's side, only what it last received. The feed's batches travel **sealed**: their changes are encrypted (AES-256-GCM) with a key derived from the hosting's installation secret — domain-separated from the settings secrets' — and bound to the caller assertion's nonce and the batch envelope, so the chisel server and whatever holds a loopback end of the internal tunnel never see a member in clear. Audit entries name users by `userId` alone, and the feed's wire parsers never echo a received value. The panel and Gatekeeper log one metadata line per request — method, **route pattern** (never the URL or its query), status, duration, certificate role, and the client address only for certificate holders, never for a person — instead of Fastify's own request lines; the panel's log lines name users by `userId`; Gatekeeper's principal removal and access-log purge take the username in a request body, never a URL. `users.yml`'s content never reaches a log, even when it cannot be parsed. What nginx's access log, journald and Authelia's log keep, and for how long: [Monitoring](../05-operations/monitoring.md#logs-and-personal-data).
|
|
244
244
|
|
|
245
|
-
**Offboarding and erasure.** One offboarding function, keyed by `userId`, runs for every user who stops being one — disabled or deleted through the users API, or disabled or removed in `users.yml` outside it (adopted by the minute's reconcile): their desktop sessions end (an epoch keyed by `userId`; sessions are bound to the `userId`, so a username given to someone else revives none), their registry tokens are revoked, Gatekeeper drops its cached session verdicts, and for a removal their legacy plugin-access grants, Gatekeeper principal (every grant and group membership under the username) and Authelia second factors (TOTP configuration, WebAuthn credentials) go. Disabling is effective at once: the directory is written
|
|
245
|
+
**Offboarding and erasure.** One offboarding function, keyed by `userId`, runs for every user who stops being one — disabled or deleted through the users API, or disabled or removed in `users.yml` outside it (adopted by the minute's reconcile): their desktop sessions end (an epoch keyed by `userId`; sessions are bound to the `userId`, so a username given to someone else revives none), their registry tokens are revoked, Gatekeeper drops its cached session verdicts, and for a removal their legacy plugin-access grants, Gatekeeper principal (every grant and group membership under the username) and Authelia second factors (TOTP configuration, WebAuthn credentials) go. Disabling is effective at once: the directory is written in the same step, so the user surface refuses them (`403`), Authelia ends their session at their next request, and every audience shows them disabled; a disable that Authelia's own rewrite of `users.yml` undoes is made again, and reported when it does not stick. Deleting keeps a tombstone (the `userId` and the last known name and address, `removed`) so history stays readable. **A re-created username is a new user with a new `userId` and inherits no grant, group, role, second factor or session**: at every creation over a tombstone Gatekeeper drops everything under the username and Authelia its second factors (refused while either cannot), a username a deleted user held and nobody holds takes no grant or membership (`409 username_deleted`), and grants are given under the users lock so none races a deletion. The one exception Lamaste cannot remove is the **OpenID Connect identity**: Authelia's opaque identifier (`sub`) for a username cannot be deleted, so a username Authelia holds one for is never given to a new user (`409 username_has_oidc_identity`). **Erasing** scrubs the tombstone, the user's invitations, Gatekeeper's access-request log rows and Authelia's second factors, and rewrites the user's row to `remove/erased` in every plugin that ever had them — uninstalled plugins whose data an agent keeps and plugins that no longer declare identity included (a plugin's audience is its erasure ledger, dropped only when no agent keeps its data); its agent half scrubs its row and anonymises its own data in one transaction, never takes the user back afterwards (erasure is sticky in its projection), and the panel shows the erasure as pending until each plugin's data has it. Outside Lamaste's reach: Authelia's opaque identifier and authentication log, nginx's access logs, journald's older entries, and backups taken before ([Backup and Restore](../05-operations/backup-and-restore.md) on restoring a relay).
|
|
246
246
|
|
|
247
247
|
**What remains.** Plain `authenticated` and `restricted` app tunnels still pass the user to their backend as **unsigned** `Remote-User`, `Remote-Groups`, `Remote-Name` and `Remote-Email` headers set from Gatekeeper's answer: nginx replaces whatever the client sent, but the backend's port is reachable on the relay's and the agent's loopback by any local process, which can send any `Remote-*` it likes. Only plugin tunnels (a relay assertion for lamaste-agentd, 5c) and plugin user surfaces carry a signed identity; Gatekeeper-signed identity for plain tunnels is future work. A backend never receives the session cookie (5a), but it answers on a host under the relay's domain and can set cookies there — a second `authelia_session` with another path, which Gatekeeper refuses rather than guess. Until the hosting is marked down, a forwarded request — a user's or an administrator's — can reach a relay-loopback squatter (5e). The relay's loopback stays the relay's trust boundary: a process on the relay that can read the relay signing key can mint assertions for the panel, as it could for agents before.
|
|
248
248
|
|
|
@@ -664,6 +664,31 @@ Configuration files that are read live by services (like Authelia's `users.yml`)
|
|
|
664
664
|
| `packages/core/lib/src/agent/plugin-settings-store.ts` | The agent half's settings files and `/admin/settings` |
|
|
665
665
|
| `packages/server/daemon/src/lib/plugin-settings.js` | Settings through the tunnel; the cache without secrets |
|
|
666
666
|
|
|
667
|
+
## Several domains on one relay
|
|
668
|
+
|
|
669
|
+
A relay may serve several base domains with one user directory and an explicit member list per domain ([Domains API](../04-api-reference/domains.md)).
|
|
670
|
+
|
|
671
|
+
- **Membership is enforced twice, from one source** (the panel's `state.db`, and Gatekeeper's grants for external members): Authelia (groups Lamaste owns in `users.yml`, named by `access_control` rules with deny last and `default_policy: deny`, and by one OIDC authorization policy per user-facing client) and Gatekeeper (the `domains.json` projection, fail closed; read again on every cache bust and every minute, whatever its file watcher saw). Either alone keeps a non-member out of tunnels and plugin surfaces; static sites rely on Authelia, OIDC sign-ins on the clients' authorization policies. One lock (`withDomainRendering`) serializes everything that writes what members may do. Both are always rendered — one failing never keeps the other at older members — and a failing rendering is audited (`domain.render.failed`) and raised to the administrators until it succeeds.
|
|
672
|
+
- **A protected site is never served open:** a protected static site whose hostname is under none of the relay's domains (possible since 4.6) answers `403` to everyone, and editing or re-verifying it is refused until it is unprotected or its domain is added.
|
|
673
|
+
- **A user-facing OIDC client is always gated by membership:** a client is either a service (`client_credentials` alone) or user-facing, never both — Authelia gives a `client_credentials` client `one_factor`, never a domain's member policy.
|
|
674
|
+
- **Cookies never cross domains:** domains may not overlap **and may not share a registrable domain** (eTLD+1 by the Public Suffix List; a public suffix is never a domain) — otherwise an application on `cust1.example.net` could set an `authelia_session` on `example.net` that the browser sends to `cust2.example.net` (a planted session, a forced sign-in, a lock-out) and both would be one site for `SameSite`. So one domain's session cookie never reaches another's hosts; the backend cookie map strips `authelia_session` on every domain. Each `auth.<domain>` passes Authelia its own name as `X-Forwarded-Host` / `-Proto` — a client cannot make one domain's portal act as another's issuer or cookie domain.
|
|
675
|
+
- **Nothing lands on a domain as it changes:** adding, activating and removing a domain hold the tunnel and sites locks under which tunnels, sites and plugin moves resolve their domain and sites take hostnames; the registry credential is written under the domains lock. The relay's own hostnames (`auth.`, `panel.`, `tunnel.`, `agent-*`) of a pending domain are kept free, and a domain is added and activated only while no tunnel, site or alias holds one. An invitation grants, at acceptance, only the domains it names that existed when it was made — a domain removed and added again is not one of them.
|
|
676
|
+
- **Registry tokens follow the registry's sign-in**: a user whom none of the registry's own sign-in clients (the user-facing clients whose audience is the registry) admits any more — whatever narrowed them, a revocation with Gatekeeper's own CLI included — loses their Feria tokens (best effort; they sign in again); none such client, or one that cannot be read, revokes (fail closed). Changing the credential's domains revokes those of everyone outside the new ones. Every narrowing is audited (`directory.access.narrowed`, by id).
|
|
677
|
+
- **One issuer per domain:** a token carries the issuer it was obtained at; a relying party trusting one issuer refuses the others.
|
|
678
|
+
- **External members reach only what names them** — `restricted` tunnels and surfaces that grant them, static sites that list them, OIDC clients granted to them — checked by Authelia (an external member's rule admits them only on a host whose name is one of their groups, and the panel gives them a host's group only for a grant on it; an `authenticated` host has none, so it is closed to them from its first request) and again by Gatekeeper (the projection carries the kind). They hold no Authelia group (`admins`, `feria-*`), so no group grants them anything by membership; Lamaste (Gatekeeper) groups in grants apply to them. Making a member external takes effect at their next request.
|
|
679
|
+
- **Who is let in changes without a restart.** Memberships, kinds, grants, users and sites' listed users are groups Lamaste owns in `users.yml`, which Authelia watches and re-reads at each request (`refresh_interval: always`, rendered); if its configuration could not be brought to that, a change of the file restarts it. The panel touches the file 0.6 s after its last write — read again, Lamaste's groups applied again, written — because Authelia skips a reload within 0.5 s of the previous one; the start and the identity tick touch it too. Authelia's own password change and reset, which would write the file from an older copy, are disabled. A write never drops a user it was not told to delete, never gives a user the rendering did not know (a reused username) any of Lamaste's groups, and only narrows after a rendering failed; when the grants cannot be read, external members hold no granted host or client until they can (fail closed). The names of those groups are reserved: an administrator assigns only `[A-Za-z0-9_-]` names, and the panel removes any owned-looking group it did not render — compared folded as Authelia compares (`ſ` is `s`), under every domain and every removed one.
|
|
680
|
+
- **Grants are access, kept until revoked**: Gatekeeper consumes only a local plugin grant (its desktop enrolment), and sweeps only those; tunnel, site, agent-plugin and OIDC-client grants were swept 90 days after creation before 4.7. Uninstalling a plugin revokes the grants on its OIDC clients.
|
|
681
|
+
- **The accepted shared blast radius:** one droplet, nginx, panel, Gatekeeper and Authelia serve every domain, and the admin certificate manages all of them. A compromise of the relay reaches every domain it serves — the normal hosting trade-off, documented rather than engineered around. A customer who must keep its users off the relay needs a relay of its own (or, later, an external identity provider for its domain).
|
|
682
|
+
- **Same-site:** applications on one domain share its registrable domain as before; a customer's applications on their own domain are now a separate site from Code Lama's.
|
|
683
|
+
|
|
684
|
+
**What remains.**
|
|
685
|
+
|
|
686
|
+
- **OIDC access tokens already issued.** Authelia checks a client's authorization policy — membership of its domain, or an external member's grant — when a user authorizes it, not afterwards. Plugin clients therefore get no refresh tokens (the manifest refuses the `refresh_token` grant and the `offline` / `offline_access` scopes; a plugin installed before is served without them), and the access and ID tokens of user-facing clients live 15 minutes: a user removed from a domain, or whose grant was revoked, keeps at most those, until they expire. Feria's own tokens are revoked (above).
|
|
687
|
+
- **One session store.** Authelia keeps every domain's sessions in one store; the separation between domains is the browser's cookie scoping plus membership by username — a session value moved to another domain's cookie would be accepted there for a member. The backend cookie map keeps session values away from every backend.
|
|
688
|
+
- **Structural changes restart Authelia** — a domain added, activated or removed, a static site protected, unprotected, created or removed, the set of OIDC clients or a plugin's domain changed — which ends every session on every domain (Authelia keeps sessions in memory): an availability cost, not an access one, and an administrator's action (R3, narrowed in 4.7).
|
|
689
|
+
- **Authelia's device-code flow reads a session's groups as they were** (R5): unlike the authorization-code flow, it checks a client's policy against the groups the session last refreshed. So a change that takes a device-code client (`feria login`) away from someone — a membership ended or made external on a domain serving one, a grant on one revoked — restarts Authelia, ending every session on every domain. External members without such a grant (corral's) never cause it. To be reported upstream.
|
|
690
|
+
- **Lamaste's groups reach an OIDC client that asks for `groups`** (R4): Authelia's standard `groups` claim cannot be filtered, so such a client — one the administrator installed, Feria's `feria login` — sees the user's groups. They are opaque — a random key per domain (`lamaste:m:<key>`, `lamaste:x:<key>`), a site's id — so no domain or site is named; what remains is that two users sharing a key share a domain, the client ids granted to an external member, and an external member's granted hostnames on their own domain. Gatekeeper keeps them from every tunnel backend.
|
|
691
|
+
|
|
667
692
|
## Quick Reference
|
|
668
693
|
|
|
669
694
|
### Security layers
|
|
@@ -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.7.0`)
|
|
268
268
|
|
|
269
|
-
The `@lamalibre/lamaste-tickets@4.
|
|
269
|
+
The `@lamalibre/lamaste-tickets@4.7.0` 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.7.0/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.7.0/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.7.0` — 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.7.0`'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.7.0
|
|
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.7.0
|
|
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.
|
|
@@ -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.7.0
|
|
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.7.0
|
|
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.7.0`, 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.7.0`, 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.7.0` 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.7.0/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.7.0` ([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.7.0` 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.7.0`) 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.7.0
|
|
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.7.0
|
|
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.7.0` 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.7.0` 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.7.0` 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
|
|
@@ -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.7.0
|
|
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.7.0` |
|
|
207
|
+
| **Update** | `npx @lamalibre/create-lamaste-desktop@4.7.0` |
|
|
208
|
+
| **Agent setup** | `npm install -g @lamalibre/lamaste-agent@4.7.0`, 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.7.0` |
|
|
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.7.0
|
|
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.7.0 --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.7.0` |
|
|
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` |
|
|
@@ -117,13 +117,13 @@ When someone leaves, **disable** them first — it is immediate and reversible:
|
|
|
117
117
|
The user's status turns **disabled**. From that moment:
|
|
118
118
|
|
|
119
119
|
- they can no longer sign in to Authelia (Authelia's `disabled: true`);
|
|
120
|
-
- every agent-hosted plugin's user surface refuses them (`403`) — the panel's directory is updated
|
|
120
|
+
- every agent-hosted plugin's user surface refuses them (`403`) — the panel's directory is updated in the same step;
|
|
121
121
|
- every plugin they use sees them as `disabled` in its audience (its agent half is told within seconds while it is online);
|
|
122
122
|
- their desktop app sessions end and their registry (Feria) tokens are revoked.
|
|
123
123
|
|
|
124
124
|
Their `userId`, grants and group memberships stay, so **Enable** brings everything back as it was (their desktop app signs in again). The last enabled member of the `admins` group cannot be disabled — the panel refuses with "Cannot disable the last enabled administrator". A user disabled by editing `users.yml` directly is offboarded the same way within a minute, when the panel notices.
|
|
125
125
|
|
|
126
|
-
If Authelia rewrites `users.yml` at the very moment you disable someone (a password reset it handles writes the whole file), the panel notices
|
|
126
|
+
If Authelia rewrites `users.yml` at the very moment you disable someone (a password reset it handles writes the whole file), the panel notices when it reads the file back and disables the user again; should that not stick either, the panel says the change did not persist instead of reporting success — check the user and disable them again.
|
|
127
127
|
|
|
128
128
|
```bash
|
|
129
129
|
lamaste-server users disable alice
|
|
@@ -141,7 +141,7 @@ lamaste-server users enable alice
|
|
|
141
141
|
|
|
142
142
|
**What happens behind the scenes:**
|
|
143
143
|
|
|
144
|
-
1. The panel removes the user from `users.yml` (atomic write, under the panel's one lock for user changes) and
|
|
144
|
+
1. The panel removes the user from `users.yml` (atomic write, under the panel's one lock for user changes); Authelia reloads it and ends the user's session at their next request.
|
|
145
145
|
2. The user directory keeps a **tombstone**: the user's `userId` and their last username, display name and email, marked `removed`. Plugins that had the user as a member are told the user was deleted and keep what they last received, so a plugin's history — "approved by Alice Smith" — stays readable.
|
|
146
146
|
3. Gatekeeper drops every grant naming the username and its membership of every Lamaste group. If Gatekeeper is unreachable, the panel says so and retries every minute; until it succeeds, the username holds no role in any plugin and cannot be given to a new user.
|
|
147
147
|
4. Authelia deletes the user's second factors — their TOTP configuration and WebAuthn security keys.
|
|
@@ -227,7 +227,7 @@ Details: [Users API](../04-api-reference/users.md).
|
|
|
227
227
|
|
|
228
228
|
### The User Directory
|
|
229
229
|
|
|
230
|
-
Authelia's `users.yml` stays Authelia's credential file; the panel's `state.db` holds the **directory** beside it: a `userId` per user, the status, and the tombstones of deleted users. Every write of `users.yml` the panel makes goes through one lock that brings the directory in line
|
|
230
|
+
Authelia's `users.yml` stays Authelia's credential file; the panel's `state.db` holds the **directory** beside it: a `userId` per user, the status, and the tombstones of deleted users. Every write of `users.yml` the panel makes goes through one lock that brings the directory in line in the same step. The panel also reads `users.yml` at start and every minute — never writing it — and adopts what changed outside Lamaste (Authelia's own password reset rewrites the file): a new username gets a new `userId`, a changed name, address or `disabled` flag is taken over, and a user gone from the file (seen in two reads) becomes a tombstone marked `deleted-outside`. Audit entries name users by `userId` only.
|
|
231
231
|
|
|
232
232
|
### The CLI
|
|
233
233
|
|
|
@@ -310,13 +310,7 @@ Passwords are hashed with bcrypt at cost factor 12. The `hashPassword()` functio
|
|
|
310
310
|
|
|
311
311
|
### Authelia Reload
|
|
312
312
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
```bash
|
|
316
|
-
sudo systemctl restart authelia
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
Authelia reads `users.yml` on restart. If the restart fails, a warning is logged but the API request still succeeds — the user data is persisted and the next Authelia restart picks it up.
|
|
313
|
+
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. Who may reach which domain is part of the file too: the groups Lamaste owns (`lamaste:m:<key>`, `lamaste:x:<key>`, `lamaste:s:<site id>`, hostnames, `lamaste:oidc@<client>` — never shown as groups). Authelia restarts when its configuration changes — a domain or a protected static site added or removed, the OIDC clients changed — and when a change takes a device-code OIDC client (`feria login`) away from someone, because Authelia's device flow checks the groups a session last read. Authelia's own password change and reset are disabled (they cannot work on a relay: its notifier is a file); passwords are set by invitation or by an administrator.
|
|
320
314
|
|
|
321
315
|
## Quick Reference
|
|
322
316
|
|
|
@@ -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.7.0` 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.7.0`)
|
|
217
217
|
2. `test-lamaste-check.example.com` — tests wildcard resolution (optional)
|
|
218
218
|
3. `example.com` — reported, not required
|
|
219
219
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Adding a Second Domain
|
|
2
|
+
|
|
3
|
+
> Serve another base domain from the same relay, with its own sign-in and its own members — `codelama.com.tr` beside `samplepark.tr`, or a customer's domain.
|
|
4
|
+
|
|
5
|
+
## In Plain English
|
|
6
|
+
|
|
7
|
+
One relay can serve several domains. Each gets a sign-in page at `auth.<domain>` and a member list; a person signs in to each domain once with the same account and reaches only the domains they are a member of. The panel and the tunnel endpoint stay on the primary domain, so agents change nothing.
|
|
8
|
+
|
|
9
|
+
## 1. Add the domain
|
|
10
|
+
|
|
11
|
+
Panel → **Domains** → enter the name → **Add domain**, or:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
sudo lamaste-server domains add codelama.com.tr
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
It is `pending`: nothing is served on it yet.
|
|
18
|
+
|
|
19
|
+
## 2. Create the DNS records
|
|
20
|
+
|
|
21
|
+
At the domain's DNS host, point the sign-in at the relay:
|
|
22
|
+
|
|
23
|
+
| Type | Name | Value |
|
|
24
|
+
| ---- | ---------------------- | ---------------- |
|
|
25
|
+
| A | `auth.codelama.com.tr` | the relay's IPv4 |
|
|
26
|
+
|
|
27
|
+
Then either one wildcard for every later hostname, or one record per hostname:
|
|
28
|
+
|
|
29
|
+
| Type | Name | Value |
|
|
30
|
+
| ---- | ------------------- | ---------------- |
|
|
31
|
+
| A | `*.codelama.com.tr` | the relay's IPv4 |
|
|
32
|
+
|
|
33
|
+
Explicit records keep precedence over a wildcard, so an apex, `www` or mail (MX, SPF, DKIM) record elsewhere stays as it is. Some DNS hosts (Turhost among them) take a wildcard as a plain record named `*`; if yours refuses one, create an A record per hostname as you add tunnels and sites. Certificates are Let's Encrypt HTTP-01 per hostname, issued by the relay — the DNS host does not matter.
|
|
34
|
+
|
|
35
|
+
**Check DNS** on the domain's card (or `lamaste-server domains verify-dns codelama.com.tr`) lists the records the panel expects and whether each resolves here.
|
|
36
|
+
|
|
37
|
+
## 3. Choose the members
|
|
38
|
+
|
|
39
|
+
Add members on the domain's card (**Members**), or `lamaste-server domains members codelama.com.tr add <username>`. Members of a pending domain are let in the moment it goes live. From now on new users and invitations name their domains.
|
|
40
|
+
|
|
41
|
+
## 4. Activate
|
|
42
|
+
|
|
43
|
+
**Activate** (or `lamaste-server domains activate codelama.com.tr`) issues `auth.codelama.com.tr`, serves its sign-in and admits its members. It is one operation: if the certificate, nginx or Authelia step fails, nothing changes.
|
|
44
|
+
|
|
45
|
+
## 5. Put hostnames on it
|
|
46
|
+
|
|
47
|
+
Tunnel and managed-site forms gain a **Domain** picker; the CLI takes `--domain`. A plugin belongs to one domain: move it on its card (or `lamaste-server plugins domain <name> <domain>`) before giving it a user or web surface there.
|
|
48
|
+
|
|
49
|
+
## What members see
|
|
50
|
+
|
|
51
|
+
- A member signs in at `auth.<domain>` once per domain (browsers never share cookies between domains), with the same password and TOTP.
|
|
52
|
+
- A signed-in non-member gets a "not a member of this domain" page with your contact and a sign-out link.
|
|
53
|
+
- `authenticated` means "any member of this domain"; `restricted` still needs a Gatekeeper grant.
|
|
54
|
+
|
|
55
|
+
## External members
|
|
56
|
+
|
|
57
|
+
A client's people can sign in on your domain without reaching all of it: make them **external** members. An external member reaches only what names them:
|
|
58
|
+
|
|
59
|
+
- a `restricted` tunnel, user surface or web surface — with a Gatekeeper grant (to them, or a Lamaste group they are in);
|
|
60
|
+
- a protected static site that lists them in its allowed users;
|
|
61
|
+
- an OIDC client of a plugin on the domain that is granted to them (the plugin card's **OIDC sign-in**, or `lamaste-server plugins oidc-clients <plugin> grant <client> --user <name>`).
|
|
62
|
+
|
|
63
|
+
Every `authenticated` host stays closed to them — they get the access-request page. They hold no Authelia groups (`admins`, `feria-*`): remove a user's groups before making them external. A plugin's audience counts them when they are entitled to it, so the plugin sees them with their roles.
|
|
64
|
+
|
|
65
|
+
Make someone external when you create or invite them (the membership's kind, or **External member** on a one-domain relay), on the domain's **Members** list (**Make external**), or with the CLI:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
lamaste-server domains members codelama.com.tr add client-ali --external
|
|
69
|
+
lamaste-server domains members codelama.com.tr kind onur external
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
None of this restarts Authelia or signs anyone out: a change applies at the person's next request.
|
|
73
|
+
|
|
74
|
+
## Removing a domain
|
|
75
|
+
|
|
76
|
+
Delete or move what uses it first (the card lists it), then **Remove**. Its memberships end; the primary can never be removed.
|
|
77
|
+
|
|
78
|
+
## Related
|
|
79
|
+
|
|
80
|
+
- [Domains API](../04-api-reference/domains.md)
|
|
81
|
+
- [DNS & Domains](../01-concepts/dns-and-domains.md#multiple-domains)
|
|
82
|
+
- [Authorization](../01-concepts/authorization.md)
|
|
@@ -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.7.0` 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.7.0` — the admin does not need to do anything.
|
|
100
100
|
|
|
101
101
|
```mermaid
|
|
102
102
|
sequenceDiagram
|
|
@@ -181,6 +181,10 @@ The file browser lets you:
|
|
|
181
181
|
|
|
182
182
|
The Let's Encrypt certificate is left in place (certbot manages its lifecycle).
|
|
183
183
|
|
|
184
|
+
### Sites that belong to a plugin
|
|
185
|
+
|
|
186
|
+
An agent-hosted plugin can own a site: its **web surface**, where the relay serves the application its users open, from the files its approved version ships ([Web surface](../04-api-reference/agent-hosted-plugins.md#web-surface)). Such a site is listed on the Sites page with the plugin it belongs to, but it is managed on the plugin's card — no uploads, no settings, no deletion here, and `lamaste-agent deploy` refuses it: its files change only with an approved version of the plugin.
|
|
187
|
+
|
|
184
188
|
## For Developers
|
|
185
189
|
|
|
186
190
|
### Site Data Model
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Installer Flow
|
|
2
2
|
|
|
3
|
-
## What `npx @lamalibre/create-lamaste@4.
|
|
3
|
+
## What `npx @lamalibre/create-lamaste@4.7.0` Does
|
|
4
4
|
|
|
5
5
|
The installer is a **zero-prompt, fire-and-forget** command. It assumes:
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ It requires **no user input**. All configuration happens later through the brows
|
|
|
13
13
|
## Execution Flow
|
|
14
14
|
|
|
15
15
|
```
|
|
16
|
-
$ npx @lamalibre/create-lamaste@4.
|
|
16
|
+
$ npx @lamalibre/create-lamaste@4.7.0
|
|
17
17
|
|
|
18
18
|
Lamaste Installer v1.0.0
|
|
19
19
|
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## In Plain English
|
|
6
6
|
|
|
7
|
-
When you run `npx @lamalibre/create-lamaste@4.
|
|
7
|
+
When you run `npx @lamalibre/create-lamaste@4.7.0` on a fresh VPS, the installer takes over and does everything automatically: hardens the OS, installs dependencies, generates security certificates, configures nginx, deploys the panel, and starts the service. It prints a summary with instructions for downloading your client certificate and accessing the panel. No prompts, no questions, no configuration files to edit.
|
|
8
8
|
|
|
9
9
|
The installer is deliberately limited in scope. It sets up just enough to serve the panel UI over a secure connection. Everything else — domain configuration, tunnel setup, user management — happens through the browser-based onboarding wizard after the installer finishes.
|
|
10
10
|
|
|
11
11
|
## Overview
|
|
12
12
|
|
|
13
13
|
```
|
|
14
|
-
npx @lamalibre/create-lamaste@4.
|
|
14
|
+
npx @lamalibre/create-lamaste@4.7.0
|
|
15
15
|
│
|
|
16
16
|
├── bin/create-lamaste.js ← CLI entry point
|
|
17
17
|
│ └── calls main() from src/index.js
|
|
@@ -181,7 +181,7 @@ Six task groups run sequentially through Listr2:
|
|
|
181
181
|
**Chisel and Authelia** (`lib/relay-services.js`, run on install and on every redeploy):
|
|
182
182
|
|
|
183
183
|
- Creates the `lamaste-chisel` group (and adds `lamaste` to it) and the `lamaste-authelia` system account (no login shell, no home)
|
|
184
|
-
- Installs Chisel 1.12.0 and Authelia 4.39.28 to `/usr/local/bin` (`lib/binaries.js`): downloaded from fixed release URLs, verified against the SHA-256 digests pinned in `@lamalibre/lamaste@4.
|
|
184
|
+
- Installs Chisel 1.12.0 and Authelia 4.39.28 to `/usr/local/bin` (`lib/binaries.js`): downloaded from fixed release URLs, verified against the SHA-256 digests pinned in `@lamalibre/lamaste@4.7.0` (`CHISEL_RELEASE`, `AUTHELIA_RELEASE`) before anything is unpacked, staged in a `mkdtemp` directory and renamed into place. A binary already at the pinned version is left alone; an Authelia **newer** than the pin is kept, never downgraded (its database may use a schema the pinned release cannot read)
|
|
185
185
|
- Writes `/etc/systemd/system/chisel.service` (`User=nobody`, `Group=lamaste-chisel`) and `/etc/systemd/system/authelia.service` (`User=lamaste-authelia`, `UMask=027`, `Environment=X_AUTHELIA_CONFIG_FILTERS=template`, `ProtectSystem=strict` with `ReadWritePaths=/etc/authelia /var/log/authelia`, `SystemCallFilter=@system-service`, empty `CapabilityBoundingSet`, `NoNewPrivileges`); both are enabled and started later by onboarding
|
|
186
186
|
- Generates the OpenID Connect issuer key `/etc/authelia/oidc-issuer.pem` if it is missing (`lib/oidc-issuer-key.js`): RSA 4096 generated in the installer process, written by a child process running as `lamaste-authelia` (`wx`, 0600, renamed into place) so root never writes through `/etc/authelia`. The panel references it from Authelia's configuration with a `{{ secret "…" }}` template expression — which is why the unit and `lamaste-priv authelia-totp` set the `template` configuration filter — and can never read it. A key owned by anyone else is replaced; one owned by the Authelia account is kept (its mode fixed through a descriptor if it drifted)
|
|
187
187
|
- Sets ownership (`lib/ownership.js`): `/var/www/lamaste` `lamaste:www-data 2750`; `/etc/authelia` `lamaste:lamaste-authelia 2770` (setgid) with `configuration.yml` `0640`, `users.yml` `0660`, `.secrets.json` `0600` (lamaste), `db.sqlite3*` and `notifications.txt` `lamaste-authelia 0600`; `/var/log/authelia` `lamaste-authelia 0750`; `chisel-server.key` (if present) `lamaste:lamaste-chisel 0640`; the PKI directory `lamaste:lamaste` (the panel is the CA)
|
|
@@ -253,7 +253,7 @@ When the installer detects an existing Lamaste installation (`/etc/lamalibre/lam
|
|
|
253
253
|
|
|
254
254
|
Redeploy mode stops the panel and gatekeeper, secures the install directory (a non-root-owned tree is moved aside and removed at the end), redeploys the panel server, `lamaste-server` CLI, UI, docs, gatekeeper and cert help page, merges `panel.json`, runs the same Chisel/Authelia step as a fresh install (stopping a running Authelia while its files change hands), rewrites the panel's systemd unit, the root-owned programs and the sudoers rules, ensures the port-80 redirect, then restarts Chisel if its binary or unit changed, starts Authelia and the gatekeeper if they were running, and restarts the panel. It does not touch OS hardening, mTLS certificates or the panel's vhosts. The panel's self-update (`sudo lamaste-priv self-update <version>`) runs this path as root, so it never writes through a path the `lamaste` user controls.
|
|
255
255
|
|
|
256
|
-
This provides a fast upgrade path: re-running `npx @lamalibre/create-lamaste@4.
|
|
256
|
+
This provides a fast upgrade path: re-running `npx @lamalibre/create-lamaste@4.7.0` on an existing installation updates the code and the pinned services while preserving all configuration and certificates. Use `--force-full` to bypass this and run the complete installer.
|
|
257
257
|
|
|
258
258
|
The redeploy logic lives in `tasks/redeploy.js`, with shared systemd unit and sudoers content generators in `lib/service-config.js`.
|
|
259
259
|
|
|
@@ -278,7 +278,7 @@ Everything else the panel does needs no rule: the PKI directory (agent CSR signi
|
|
|
278
278
|
|
|
279
279
|
The certbot wrappers accept only lowercase DNS hostnames (no wildcards or path characters, at most 100 per certificate) and a syntactically valid email address. Renewals the panel triggers pass `--no-random-sleep-on-renew`, because certbot otherwise sleeps up to about 8 minutes before a non-interactive renewal (a delay meant for `certbot.timer`) while an operator waits.
|
|
280
280
|
|
|
281
|
-
Redeploying (`npx @lamalibre/create-lamaste@4.
|
|
281
|
+
Redeploying (`npx @lamalibre/create-lamaste@4.7.0` on an existing install) reinstalls the programs, removes retired ones (`lamaste-sign-csr`, `lamaste-pki-rename`), and replaces this file atomically after `visudo -c` accepts it, so upgrades pick up new rules.
|
|
282
282
|
|
|
283
283
|
## File Operation Safety
|
|
284
284
|
|