@lamalibre/create-lamaste 4.0.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/LICENSE.md +118 -0
- package/README.md +114 -0
- package/bin/create-lamaste.js +15 -0
- package/package.json +54 -0
- package/scripts/bundle-vendor.js +110 -0
- package/scripts/lamaste-cert-info +62 -0
- package/scripts/lamaste-certbot +96 -0
- package/scripts/lamaste-priv +693 -0
- package/src/index.js +646 -0
- package/src/lib/accounts.js +86 -0
- package/src/lib/binaries.js +137 -0
- package/src/lib/cert-help-page.js +160 -0
- package/src/lib/env.js +132 -0
- package/src/lib/http-redirect.js +38 -0
- package/src/lib/ownership.js +231 -0
- package/src/lib/relay-services.js +103 -0
- package/src/lib/secrets.js +19 -0
- package/src/lib/service-config.js +311 -0
- package/src/lib/summary.js +131 -0
- package/src/lib/wrappers.js +63 -0
- package/src/tasks/gatekeeper.js +233 -0
- package/src/tasks/harden.js +293 -0
- package/src/tasks/mtls.js +193 -0
- package/src/tasks/nginx.js +265 -0
- package/src/tasks/node.js +110 -0
- package/src/tasks/panel.js +408 -0
- package/src/tasks/redeploy.js +438 -0
- package/vendor/docs/00-introduction/how-it-works.md +447 -0
- package/vendor/docs/00-introduction/quickstart.md +472 -0
- package/vendor/docs/00-introduction/what-is-lamaste.md +112 -0
- package/vendor/docs/01-concepts/authentication.md +464 -0
- package/vendor/docs/01-concepts/authorization.md +242 -0
- package/vendor/docs/01-concepts/certificates.md +452 -0
- package/vendor/docs/01-concepts/dns-and-domains.md +343 -0
- package/vendor/docs/01-concepts/mtls.md +490 -0
- package/vendor/docs/01-concepts/nginx-reverse-proxy.md +540 -0
- package/vendor/docs/01-concepts/security-model.md +600 -0
- package/vendor/docs/01-concepts/tickets.md +414 -0
- package/vendor/docs/01-concepts/tunneling.md +367 -0
- package/vendor/docs/02-guides/agent-setup.md +194 -0
- package/vendor/docs/02-guides/certificate-management.md +341 -0
- package/vendor/docs/02-guides/cloud-provisioning.md +406 -0
- package/vendor/docs/02-guides/desktop-app-setup.md +226 -0
- package/vendor/docs/02-guides/disaster-recovery.md +464 -0
- package/vendor/docs/02-guides/first-tunnel.md +230 -0
- package/vendor/docs/02-guides/installation.md +393 -0
- package/vendor/docs/02-guides/managing-users.md +255 -0
- package/vendor/docs/02-guides/onboarding.md +244 -0
- package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +375 -0
- package/vendor/docs/02-guides/static-sites.md +364 -0
- package/vendor/docs/03-architecture/e2e-three-vm-sequences.md +457 -0
- package/vendor/docs/03-architecture/installer-flow.md +151 -0
- package/vendor/docs/03-architecture/installer.md +445 -0
- package/vendor/docs/03-architecture/management-flow.md +288 -0
- package/vendor/docs/03-architecture/nginx-configuration.md +830 -0
- package/vendor/docs/03-architecture/onboarding-flow.md +164 -0
- package/vendor/docs/03-architecture/overview.md +541 -0
- package/vendor/docs/03-architecture/panel-client.md +416 -0
- package/vendor/docs/03-architecture/panel-server.md +695 -0
- package/vendor/docs/03-architecture/state-management.md +529 -0
- package/vendor/docs/03-architecture/system-overview.md +167 -0
- package/vendor/docs/04-api-reference/certificates.md +1141 -0
- package/vendor/docs/04-api-reference/gatekeeper.md +592 -0
- package/vendor/docs/04-api-reference/onboarding.md +473 -0
- package/vendor/docs/04-api-reference/overview.md +404 -0
- package/vendor/docs/04-api-reference/services.md +267 -0
- package/vendor/docs/04-api-reference/settings.md +343 -0
- package/vendor/docs/04-api-reference/sites.md +716 -0
- package/vendor/docs/04-api-reference/system.md +268 -0
- package/vendor/docs/04-api-reference/tickets.md +618 -0
- package/vendor/docs/04-api-reference/tunnels.md +417 -0
- package/vendor/docs/04-api-reference/users.md +333 -0
- package/vendor/docs/05-operations/backup-and-restore.md +342 -0
- package/vendor/docs/05-operations/monitoring.md +285 -0
- package/vendor/docs/05-operations/uninstalling.md +344 -0
- package/vendor/docs/05-operations/upgrades.md +270 -0
- package/vendor/docs/06-reference/config-files.md +1080 -0
- package/vendor/docs/06-reference/glossary.md +528 -0
- package/vendor/docs/06-reference/installer-flags.md +260 -0
- package/vendor/docs/06-reference/ports-and-services.md +244 -0
- package/vendor/docs/06-reference/troubleshooting.md +665 -0
- package/vendor/docs/_index.json +233 -0
- package/vendor/docs/gatekeeper-design.md +953 -0
- package/vendor/docs/package.json +15 -0
- package/vendor/docs/todo/lib-cli-desktop-refactor.md +641 -0
- package/vendor/gatekeeper/dist/boot.d.ts +1 -0
- package/vendor/gatekeeper/dist/boot.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/boot.js +17 -0
- package/vendor/gatekeeper/dist/boot.js.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/access.d.ts +2 -0
- package/vendor/gatekeeper/dist/cli/commands/access.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/access.js +33 -0
- package/vendor/gatekeeper/dist/cli/commands/access.js.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/grants.d.ts +2 -0
- package/vendor/gatekeeper/dist/cli/commands/grants.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/grants.js +110 -0
- package/vendor/gatekeeper/dist/cli/commands/grants.js.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/groups.d.ts +2 -0
- package/vendor/gatekeeper/dist/cli/commands/groups.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/groups.js +98 -0
- package/vendor/gatekeeper/dist/cli/commands/groups.js.map +1 -0
- package/vendor/gatekeeper/dist/cli/index.d.ts +3 -0
- package/vendor/gatekeeper/dist/cli/index.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/cli/index.js +45 -0
- package/vendor/gatekeeper/dist/cli/index.js.map +1 -0
- package/vendor/gatekeeper/dist/index.d.ts +9 -0
- package/vendor/gatekeeper/dist/index.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/index.js +13 -0
- package/vendor/gatekeeper/dist/index.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/authz.d.ts +16 -0
- package/vendor/gatekeeper/dist/lib/authz.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/authz.js +42 -0
- package/vendor/gatekeeper/dist/lib/authz.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/cache-bust.d.ts +15 -0
- package/vendor/gatekeeper/dist/lib/cache-bust.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/cache-bust.js +19 -0
- package/vendor/gatekeeper/dist/lib/cache-bust.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/constants.d.ts +82 -0
- package/vendor/gatekeeper/dist/lib/constants.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/constants.js +79 -0
- package/vendor/gatekeeper/dist/lib/constants.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/grants.d.ts +32 -0
- package/vendor/gatekeeper/dist/lib/grants.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/grants.js +314 -0
- package/vendor/gatekeeper/dist/lib/grants.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/groups.d.ts +10 -0
- package/vendor/gatekeeper/dist/lib/groups.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/groups.js +247 -0
- package/vendor/gatekeeper/dist/lib/groups.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/migration.d.ts +17 -0
- package/vendor/gatekeeper/dist/lib/migration.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/migration.js +79 -0
- package/vendor/gatekeeper/dist/lib/migration.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0001_groups.sql +7 -0
- package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0002_access_grants.sql +14 -0
- package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0003_access_request_log.sql +9 -0
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0001_groups.sql +7 -0
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0002_access_grants.sql +14 -0
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0003_access_request_log.sql +9 -0
- package/vendor/gatekeeper/dist/lib/state-db.d.ts +16 -0
- package/vendor/gatekeeper/dist/lib/state-db.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/state-db.js +154 -0
- package/vendor/gatekeeper/dist/lib/state-db.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/templates.d.ts +21 -0
- package/vendor/gatekeeper/dist/lib/templates.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/templates.js +151 -0
- package/vendor/gatekeeper/dist/lib/templates.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/types.d.ts +178 -0
- package/vendor/gatekeeper/dist/lib/types.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/types.js +2 -0
- package/vendor/gatekeeper/dist/lib/types.js.map +1 -0
- package/vendor/gatekeeper/dist/server/index.d.ts +15 -0
- package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/index.js +251 -0
- package/vendor/gatekeeper/dist/server/index.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/access-request.d.ts +7 -0
- package/vendor/gatekeeper/dist/server/routes/access-request.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/access-request.js +17 -0
- package/vendor/gatekeeper/dist/server/routes/access-request.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/authz.d.ts +3 -0
- package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/authz.js +279 -0
- package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts +13 -0
- package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/diagnostic.js +249 -0
- package/vendor/gatekeeper/dist/server/routes/diagnostic.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/grants.d.ts +3 -0
- package/vendor/gatekeeper/dist/server/routes/grants.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/grants.js +112 -0
- package/vendor/gatekeeper/dist/server/routes/grants.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/groups.d.ts +3 -0
- package/vendor/gatekeeper/dist/server/routes/groups.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/groups.js +139 -0
- package/vendor/gatekeeper/dist/server/routes/groups.js.map +1 -0
- package/vendor/gatekeeper/package.json +49 -0
- package/vendor/server/bin/lamaste-server.js +204 -0
- package/vendor/server/package.json +31 -0
- package/vendor/server/src/commands/certs.js +224 -0
- package/vendor/server/src/commands/chisel.js +132 -0
- package/vendor/server/src/commands/logs.js +49 -0
- package/vendor/server/src/commands/plugins.js +321 -0
- package/vendor/server/src/commands/reset-admin.js +478 -0
- package/vendor/server/src/commands/restart.js +94 -0
- package/vendor/server/src/commands/sites.js +257 -0
- package/vendor/server/src/commands/status.js +158 -0
- package/vendor/server/src/commands/tunnels.js +365 -0
- package/vendor/server/src/commands/uninstall.js +326 -0
- package/vendor/server/src/config.js +38 -0
- package/vendor/server/src/exec.js +26 -0
- package/vendor/server/src/logger.js +39 -0
- package/vendor/server/src/ndjson.js +56 -0
- package/vendor/server/src/panel-api.js +85 -0
- package/vendor/server/src/state.js +45 -0
- package/vendor/server-ui/dist/assets/index-B0nWuUyL.js +257 -0
- package/vendor/server-ui/dist/assets/index-BqWWFlTU.css +1 -0
- package/vendor/server-ui/dist/index.html +13 -0
- package/vendor/serverd/package.json +44 -0
- package/vendor/serverd/src/boot.js +13 -0
- package/vendor/serverd/src/index.js +191 -0
- package/vendor/serverd/src/lib/app-error.js +14 -0
- package/vendor/serverd/src/lib/authelia.js +85 -0
- package/vendor/serverd/src/lib/certbot.js +74 -0
- package/vendor/serverd/src/lib/chisel-args.js +6 -0
- package/vendor/serverd/src/lib/chisel-reconcile.js +232 -0
- package/vendor/serverd/src/lib/chisel-runtime.js +46 -0
- package/vendor/serverd/src/lib/chisel-users.js +109 -0
- package/vendor/serverd/src/lib/chisel.js +81 -0
- package/vendor/serverd/src/lib/config.js +190 -0
- package/vendor/serverd/src/lib/constants.js +8 -0
- package/vendor/serverd/src/lib/csr-signing.js +331 -0
- package/vendor/serverd/src/lib/enrollment.js +302 -0
- package/vendor/serverd/src/lib/files.js +19 -0
- package/vendor/serverd/src/lib/gatekeeper-client.js +135 -0
- package/vendor/serverd/src/lib/invite-page.js +281 -0
- package/vendor/serverd/src/lib/ip-utils.js +79 -0
- package/vendor/serverd/src/lib/migrations/state/0001_enrollment_tokens.sql +17 -0
- package/vendor/serverd/src/lib/migrations/state/0002_tickets.sql +70 -0
- package/vendor/serverd/src/lib/migrations/state/0003_plugins.sql +15 -0
- package/vendor/serverd/src/lib/migrations/state/0004_agents.sql +19 -0
- package/vendor/serverd/src/lib/mtls.js +795 -0
- package/vendor/serverd/src/lib/nginx.js +1090 -0
- package/vendor/serverd/src/lib/pki-paths.js +41 -0
- package/vendor/serverd/src/lib/pki-sign.js +103 -0
- package/vendor/serverd/src/lib/plugins.js +538 -0
- package/vendor/serverd/src/lib/push-install.js +390 -0
- package/vendor/serverd/src/lib/revocation.js +112 -0
- package/vendor/serverd/src/lib/services.js +131 -0
- package/vendor/serverd/src/lib/session.js +151 -0
- package/vendor/serverd/src/lib/state-db.js +130 -0
- package/vendor/serverd/src/lib/state.js +140 -0
- package/vendor/serverd/src/lib/storage.js +63 -0
- package/vendor/serverd/src/lib/system-stats.js +58 -0
- package/vendor/serverd/src/lib/tickets.js +1556 -0
- package/vendor/serverd/src/lib/totp.js +76 -0
- package/vendor/serverd/src/lib/tunnel-deps.js +41 -0
- package/vendor/serverd/src/lib/user-access-session.js +142 -0
- package/vendor/serverd/src/lib/user-access.js +52 -0
- package/vendor/serverd/src/middleware/errors.js +63 -0
- package/vendor/serverd/src/middleware/mtls.js +120 -0
- package/vendor/serverd/src/middleware/onboarding-guard.js +30 -0
- package/vendor/serverd/src/middleware/role-guard.js +58 -0
- package/vendor/serverd/src/middleware/twofa-session.js +65 -0
- package/vendor/serverd/src/middleware/user-access-session.js +52 -0
- package/vendor/serverd/src/routes/enrollment.js +120 -0
- package/vendor/serverd/src/routes/health.js +22 -0
- package/vendor/serverd/src/routes/invite.js +163 -0
- package/vendor/serverd/src/routes/management/agents.js +182 -0
- package/vendor/serverd/src/routes/management/certs.js +911 -0
- package/vendor/serverd/src/routes/management/gatekeeper-proxy.js +160 -0
- package/vendor/serverd/src/routes/management/identity.js +107 -0
- package/vendor/serverd/src/routes/management/invitations.js +166 -0
- package/vendor/serverd/src/routes/management/logs.js +218 -0
- package/vendor/serverd/src/routes/management/plugins.js +560 -0
- package/vendor/serverd/src/routes/management/services.js +63 -0
- package/vendor/serverd/src/routes/management/settings.js +325 -0
- package/vendor/serverd/src/routes/management/sites.js +522 -0
- package/vendor/serverd/src/routes/management/storage.js +192 -0
- package/vendor/serverd/src/routes/management/system.js +201 -0
- package/vendor/serverd/src/routes/management/tickets.js +457 -0
- package/vendor/serverd/src/routes/management/tunnels.js +709 -0
- package/vendor/serverd/src/routes/management/users.js +377 -0
- package/vendor/serverd/src/routes/management.js +36 -0
- package/vendor/serverd/src/routes/onboarding/dns.js +101 -0
- package/vendor/serverd/src/routes/onboarding/domain.js +42 -0
- package/vendor/serverd/src/routes/onboarding/index.js +18 -0
- package/vendor/serverd/src/routes/onboarding/provision.js +327 -0
- package/vendor/serverd/src/routes/onboarding/status.js +12 -0
- package/vendor/serverd/src/routes/plugin-router.js +79 -0
- package/vendor/serverd/src/routes/user-access.js +389 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# Users API
|
|
2
|
+
|
|
3
|
+
> Manage Authelia users who authenticate to tunneled applications with TOTP two-factor authentication.
|
|
4
|
+
|
|
5
|
+
## In Plain English
|
|
6
|
+
|
|
7
|
+
When someone visits one of your tunneled apps (like `app.example.com`), they are prompted to log in through Authelia with a username, password, and a TOTP code from an authenticator app. The users API lets you create those login accounts, update their details, reset their TOTP secrets, and delete accounts you no longer need.
|
|
8
|
+
|
|
9
|
+
These are not admin panel users — the panel itself is protected by mTLS client certificates with no login screen. These users are for the apps you expose through tunnels.
|
|
10
|
+
|
|
11
|
+
## Authentication
|
|
12
|
+
|
|
13
|
+
All user endpoints require a valid mTLS client certificate and a completed onboarding. See the [API Overview](./overview.md) for details.
|
|
14
|
+
|
|
15
|
+
If onboarding is not complete, all endpoints return `503 Service Unavailable`.
|
|
16
|
+
|
|
17
|
+
## Important Behavior
|
|
18
|
+
|
|
19
|
+
- **Password hashing:** Passwords are hashed with bcrypt (not argon2id — argon2id uses ~93MB per hash and causes OOM kills on a 512MB droplet).
|
|
20
|
+
- **Authelia restart:** After every user change that modifies `users.yml` (create, update, delete), Authelia is restarted via `systemctl restart authelia` to pick up the changes. If the restart fails, the operation still succeeds — a warning is logged but no error is returned to the client. Note: TOTP reset does **not** restart Authelia — it writes directly to Authelia's SQLite database via the `authelia storage user totp generate` CLI command, which takes effect immediately.
|
|
21
|
+
- **Atomic writes:** The `users.yml` file is written atomically (write to temp file, then rename) to prevent Authelia from reading a partially written file.
|
|
22
|
+
- **Last user protection:** You cannot delete the last remaining user. At least one user must always exist.
|
|
23
|
+
|
|
24
|
+
## Endpoints
|
|
25
|
+
|
|
26
|
+
### `GET /api/users`
|
|
27
|
+
|
|
28
|
+
Returns all Authelia users, sorted alphabetically by username. Sensitive fields (password hash, TOTP secret) are excluded from the response.
|
|
29
|
+
|
|
30
|
+
**Request:**
|
|
31
|
+
|
|
32
|
+
No request body.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
curl -s --cert client.p12:password \
|
|
36
|
+
https://203.0.113.42:9292/api/users | jq
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Response (200):**
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"users": [
|
|
44
|
+
{
|
|
45
|
+
"username": "admin",
|
|
46
|
+
"displayname": "Admin User",
|
|
47
|
+
"email": "admin@example.com",
|
|
48
|
+
"groups": []
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"username": "alice",
|
|
52
|
+
"displayname": "Alice Smith",
|
|
53
|
+
"email": "alice@example.com",
|
|
54
|
+
"groups": ["developers"]
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
| Field | Type | Description |
|
|
61
|
+
| ------------- | ---------- | --------------------------- |
|
|
62
|
+
| `username` | `string` | Unique login identifier |
|
|
63
|
+
| `displayname` | `string` | Human-readable display name |
|
|
64
|
+
| `email` | `string` | User's email address |
|
|
65
|
+
| `groups` | `string[]` | Authelia group memberships |
|
|
66
|
+
|
|
67
|
+
**Errors:**
|
|
68
|
+
|
|
69
|
+
| Status | Body | When |
|
|
70
|
+
| ------ | ------------------------------------------ | -------------------------------- |
|
|
71
|
+
| 500 | `{"error":"Failed to read user database"}` | Cannot read or parse `users.yml` |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### `POST /api/users`
|
|
76
|
+
|
|
77
|
+
Creates a new Authelia user. The password is hashed with bcrypt before being stored in `users.yml`.
|
|
78
|
+
|
|
79
|
+
**Request:**
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"username": "alice",
|
|
84
|
+
"displayname": "Alice Smith",
|
|
85
|
+
"email": "alice@example.com",
|
|
86
|
+
"password": "s3cur3p4ssw0rd!",
|
|
87
|
+
"groups": ["developers"]
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
| Field | Type | Validation | Description |
|
|
92
|
+
| ------------- | ---------- | ------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
|
93
|
+
| `username` | `string` | 2-32 chars, lowercase alphanumeric + underscores + hyphens, starting with a letter or digit | Login identifier |
|
|
94
|
+
| `displayname` | `string` | 1-100 chars | Display name |
|
|
95
|
+
| `email` | `string` | Valid email format | Email address |
|
|
96
|
+
| `password` | `string` | 8-128 chars | Plain-text password (hashed before storage) |
|
|
97
|
+
| `groups` | `string[]` | Optional, defaults to `[]` | Authelia group memberships |
|
|
98
|
+
|
|
99
|
+
**Username regex** (the same rule applies to invitations — a leading `-` would read as a flag to Authelia's CLI when a TOTP secret is stored):
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
^[a-z0-9][a-z0-9_-]*$
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
curl -s --cert client.p12:password \
|
|
107
|
+
-X POST \
|
|
108
|
+
-H "Content-Type: application/json" \
|
|
109
|
+
-d '{"username":"alice","displayname":"Alice Smith","email":"alice@example.com","password":"s3cur3p4ssw0rd!"}' \
|
|
110
|
+
https://203.0.113.42:9292/api/users | jq
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Response (201):**
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"ok": true,
|
|
118
|
+
"user": {
|
|
119
|
+
"username": "alice",
|
|
120
|
+
"displayname": "Alice Smith",
|
|
121
|
+
"email": "alice@example.com",
|
|
122
|
+
"groups": []
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Errors:**
|
|
128
|
+
|
|
129
|
+
| Status | Body | When |
|
|
130
|
+
| ------ | ---------------------------------------------------------- | ------------------------------------------- |
|
|
131
|
+
| 400 | `{"error":"Validation failed","details":{"issues":[...]}}` | Invalid username, email, or password length |
|
|
132
|
+
| 409 | `{"error":"Username already exists"}` | A user with this username already exists |
|
|
133
|
+
| 500 | `{"error":"Failed to read user database"}` | Cannot read `users.yml` |
|
|
134
|
+
| 500 | `{"error":"Failed to hash password"}` | bcrypt hashing failed |
|
|
135
|
+
| 500 | `{"error":"Failed to update user database"}` | Cannot write `users.yml` |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### `PUT /api/users/:username`
|
|
140
|
+
|
|
141
|
+
Updates one or more fields of an existing user. At least one field must be provided. Only the fields included in the request body are updated — omitted fields remain unchanged.
|
|
142
|
+
|
|
143
|
+
If a new password is provided, it is hashed with bcrypt before storage.
|
|
144
|
+
|
|
145
|
+
**Request:**
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"displayname": "Alice J. Smith",
|
|
150
|
+
"email": "alice.smith@example.com",
|
|
151
|
+
"password": "n3wP4ssw0rd!",
|
|
152
|
+
"groups": ["developers", "admins"]
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
| Field | Type | Validation | Description |
|
|
157
|
+
| ------------- | ---------- | --------------------- | -------------------------------------------- |
|
|
158
|
+
| `displayname` | `string` | 1-100 chars, optional | New display name |
|
|
159
|
+
| `email` | `string` | Valid email, optional | New email address |
|
|
160
|
+
| `password` | `string` | 8-128 chars, optional | New password (hashed before storage) |
|
|
161
|
+
| `groups` | `string[]` | Optional | New group memberships (replaces entire list) |
|
|
162
|
+
|
|
163
|
+
All fields are optional, but at least one must be provided (validated by a Zod `.refine()`).
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
curl -s --cert client.p12:password \
|
|
167
|
+
-X PUT \
|
|
168
|
+
-H "Content-Type: application/json" \
|
|
169
|
+
-d '{"displayname":"Alice J. Smith","groups":["developers","admins"]}' \
|
|
170
|
+
https://203.0.113.42:9292/api/users/alice | jq
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Response (200):**
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"ok": true,
|
|
178
|
+
"user": {
|
|
179
|
+
"username": "alice",
|
|
180
|
+
"displayname": "Alice J. Smith",
|
|
181
|
+
"email": "alice.smith@example.com",
|
|
182
|
+
"groups": ["developers", "admins"]
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Errors:**
|
|
188
|
+
|
|
189
|
+
| Status | Body | When |
|
|
190
|
+
| ------ | ---------------------------------------------------------- | ------------------------------------------------ |
|
|
191
|
+
| 400 | `{"error":"Validation failed","details":{"issues":[...]}}` | No fields provided, or invalid field values |
|
|
192
|
+
| 404 | `{"error":"User not found"}` | No user with this username |
|
|
193
|
+
| 500 | `{"error":"Failed to read user database"}` | Cannot read `users.yml` |
|
|
194
|
+
| 500 | `{"error":"Failed to hash password"}` | bcrypt hashing failed (when password is updated) |
|
|
195
|
+
| 500 | `{"error":"Failed to update user database"}` | Cannot write `users.yml` |
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### `DELETE /api/users/:username`
|
|
200
|
+
|
|
201
|
+
Deletes an Authelia user. The user is removed from `users.yml` and Authelia is reloaded.
|
|
202
|
+
|
|
203
|
+
You cannot delete the last remaining user. This safety check prevents accidentally locking out all users from tunneled applications.
|
|
204
|
+
|
|
205
|
+
**Request:**
|
|
206
|
+
|
|
207
|
+
No request body.
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
curl -s --cert client.p12:password \
|
|
211
|
+
-X DELETE \
|
|
212
|
+
https://203.0.113.42:9292/api/users/alice | jq
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Response (200):**
|
|
216
|
+
|
|
217
|
+
```json
|
|
218
|
+
{
|
|
219
|
+
"ok": true
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Errors:**
|
|
224
|
+
|
|
225
|
+
| Status | Body | When |
|
|
226
|
+
| ------ | -------------------------------------------- | -------------------------- |
|
|
227
|
+
| 400 | `{"error":"Cannot delete the last user"}` | Only one user remains |
|
|
228
|
+
| 404 | `{"error":"User not found"}` | No user with this username |
|
|
229
|
+
| 500 | `{"error":"Failed to read user database"}` | Cannot read `users.yml` |
|
|
230
|
+
| 500 | `{"error":"Failed to update user database"}` | Cannot write `users.yml` |
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
### `POST /api/users/:username/reset-totp`
|
|
235
|
+
|
|
236
|
+
Generates a new TOTP secret for a user and writes it to Authelia's SQLite database via the `authelia storage user totp generate` CLI command. Returns an `otpauth://` URI that can be used to enroll an authenticator app. The old TOTP secret is immediately replaced — the user's existing authenticator enrollment becomes invalid.
|
|
237
|
+
|
|
238
|
+
**Request:**
|
|
239
|
+
|
|
240
|
+
No request body.
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
curl -s --cert client.p12:password \
|
|
244
|
+
-X POST \
|
|
245
|
+
https://203.0.113.42:9292/api/users/alice/reset-totp | jq
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Response (200):**
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"ok": true,
|
|
253
|
+
"totpUri": "otpauth://totp/Lamaste:alice?secret=JBSWY3DPEHPK3PXP&issuer=Lamaste&algorithm=SHA1&digits=6&period=30"
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
| Field | Type | Description |
|
|
258
|
+
| --------- | --------- | ------------------------------------------------------------------------------- |
|
|
259
|
+
| `ok` | `boolean` | Always `true` on success |
|
|
260
|
+
| `totpUri` | `string` | `otpauth://` URI for QR code generation or manual entry in an authenticator app |
|
|
261
|
+
|
|
262
|
+
The `totpUri` follows the [Key Uri Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format) standard. The panel client renders this as a QR code for scanning with Google Authenticator, Authy, or similar apps.
|
|
263
|
+
|
|
264
|
+
**Errors:**
|
|
265
|
+
|
|
266
|
+
| Status | Body | When |
|
|
267
|
+
| ------ | ------------------------------------------------ | ------------------------------------------------------ |
|
|
268
|
+
| 404 | `{"error":"User not found"}` | No user with this username |
|
|
269
|
+
| 500 | `{"error":"Failed to read user database"}` | Cannot read `users.yml` |
|
|
270
|
+
| 500 | `{"error":"Failed to write TOTP configuration"}` | Cannot write TOTP secret to Authelia's SQLite database |
|
|
271
|
+
|
|
272
|
+
## Quick Reference
|
|
273
|
+
|
|
274
|
+
| Method | Path | Description |
|
|
275
|
+
| ------ | --------------------------------- | -------------------------------------------------- |
|
|
276
|
+
| GET | `/api/users` | List all users (alphabetical, no sensitive fields) |
|
|
277
|
+
| POST | `/api/users` | Create user (bcrypt hash + Authelia reload) |
|
|
278
|
+
| PUT | `/api/users/:username` | Update user fields (partial update) |
|
|
279
|
+
| DELETE | `/api/users/:username` | Delete user (not the last one) |
|
|
280
|
+
| POST | `/api/users/:username/reset-totp` | Generate new TOTP secret |
|
|
281
|
+
|
|
282
|
+
### User Object Shape
|
|
283
|
+
|
|
284
|
+
Returned by list and mutation endpoints (sensitive fields excluded):
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"username": "alice",
|
|
289
|
+
"displayname": "Alice Smith",
|
|
290
|
+
"email": "alice@example.com",
|
|
291
|
+
"groups": ["developers"]
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Validation Summary
|
|
296
|
+
|
|
297
|
+
| Field | Rules |
|
|
298
|
+
| ------------- | --------------------------------------------- |
|
|
299
|
+
| `username` | 2-32 chars, `/^[a-z0-9][a-z0-9_-]*$/`, unique |
|
|
300
|
+
| `displayname` | 1-100 chars |
|
|
301
|
+
| `email` | Valid email format |
|
|
302
|
+
| `password` | 8-128 chars |
|
|
303
|
+
| `groups` | Array of strings, optional |
|
|
304
|
+
|
|
305
|
+
### curl Cheat Sheet
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# List users
|
|
309
|
+
curl -s --cert client.p12:password \
|
|
310
|
+
https://203.0.113.42:9292/api/users | jq
|
|
311
|
+
|
|
312
|
+
# Create user
|
|
313
|
+
curl -s --cert client.p12:password \
|
|
314
|
+
-X POST -H "Content-Type: application/json" \
|
|
315
|
+
-d '{"username":"bob","displayname":"Bob","email":"bob@example.com","password":"mypassword"}' \
|
|
316
|
+
https://203.0.113.42:9292/api/users | jq
|
|
317
|
+
|
|
318
|
+
# Update user (change display name and groups)
|
|
319
|
+
curl -s --cert client.p12:password \
|
|
320
|
+
-X PUT -H "Content-Type: application/json" \
|
|
321
|
+
-d '{"displayname":"Robert","groups":["admins"]}' \
|
|
322
|
+
https://203.0.113.42:9292/api/users/bob | jq
|
|
323
|
+
|
|
324
|
+
# Delete user
|
|
325
|
+
curl -s --cert client.p12:password \
|
|
326
|
+
-X DELETE \
|
|
327
|
+
https://203.0.113.42:9292/api/users/bob | jq
|
|
328
|
+
|
|
329
|
+
# Reset TOTP
|
|
330
|
+
curl -s --cert client.p12:password \
|
|
331
|
+
-X POST \
|
|
332
|
+
https://203.0.113.42:9292/api/users/bob/reset-totp | jq
|
|
333
|
+
```
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# Backup and Restore
|
|
2
|
+
|
|
3
|
+
> Protect your Lamaste installation by backing up critical configuration, state, and certificates.
|
|
4
|
+
|
|
5
|
+
## In Plain English
|
|
6
|
+
|
|
7
|
+
A backup is a copy of everything that makes your Lamaste server work the way you set it up — your domain configuration, user accounts, encryption certificates, and tunnel definitions. If something goes wrong (accidental deletion, server failure, or provider issue), a backup lets you rebuild everything on a fresh server instead of starting from scratch.
|
|
8
|
+
|
|
9
|
+
Lamaste stores all its important data in a handful of directories. There is no database to dump. Everything is plain files: JSON, YAML, and certificate files. Backing up means copying these directories to a safe location.
|
|
10
|
+
|
|
11
|
+
## For Users
|
|
12
|
+
|
|
13
|
+
### Critical Files to Back Up
|
|
14
|
+
|
|
15
|
+
Lamaste's state is spread across four directories. All of them matter.
|
|
16
|
+
|
|
17
|
+
#### `/etc/lamalibre/lamaste/` — Configuration, State, and PKI
|
|
18
|
+
|
|
19
|
+
This is the most important directory. It contains:
|
|
20
|
+
|
|
21
|
+
| File | Purpose |
|
|
22
|
+
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| `panel.json` | Server configuration (IP, domain, email, onboarding status) |
|
|
24
|
+
| `tunnels.json` | Tunnel definitions (subdomain, port, carrying agent, enabled state) |
|
|
25
|
+
| `sites.json` | Static site definitions (including custom-domain aliases) |
|
|
26
|
+
| `chisel-credentials.json` | Per-agent Chisel credentials. If lost, the panel mints a new credential for every active agent at its next start, and each agent's sync timer fetches it within about 30 seconds (the issue time changed) |
|
|
27
|
+
| `chisel-users` | Chisel authfile — derived; rewritten from the two files above, with mode `0640` and group `lamaste-chisel`, at every panel start |
|
|
28
|
+
| `chisel-sentinel` | Password of the no-grants sentinel Chisel user |
|
|
29
|
+
| `invitations.json` | Pending user invitations |
|
|
30
|
+
| `pki/revoked.json` | Revoked certificate tracking |
|
|
31
|
+
| `pki/ca.key` | Certificate Authority private key |
|
|
32
|
+
| `pki/ca.crt` | Certificate Authority certificate |
|
|
33
|
+
| `pki/client.key` | Client certificate private key |
|
|
34
|
+
| `pki/client.crt` | Client certificate |
|
|
35
|
+
| `pki/client.p12` | PKCS12 bundle (imported into browsers) |
|
|
36
|
+
| `pki/.p12-password` | Password for the PKCS12 bundle |
|
|
37
|
+
| `pki/self-signed.pem` | Self-signed TLS cert for IP:9292 access |
|
|
38
|
+
| `pki/self-signed-key.pem` | Self-signed TLS key for IP:9292 access |
|
|
39
|
+
|
|
40
|
+
**If you lose the PKI files**, every browser that imported the client certificate will need a new one. This is the single most important directory to back up.
|
|
41
|
+
|
|
42
|
+
#### `/etc/authelia/` — User Database and Authentication Config
|
|
43
|
+
|
|
44
|
+
| File | Purpose |
|
|
45
|
+
| ------------------- | --------------------------------------------------------- |
|
|
46
|
+
| `configuration.yml` | Authelia server configuration |
|
|
47
|
+
| `users.yml` | User accounts (usernames, bcrypt password hashes, groups) |
|
|
48
|
+
| `.secrets.json` | JWT secret, session secret, storage encryption key |
|
|
49
|
+
| `db.sqlite3` | Authelia session/state database (TOTP registrations) |
|
|
50
|
+
|
|
51
|
+
**If you lose the users database**, all user accounts and TOTP secrets are gone. Users will need to be recreated and re-enroll their authenticator apps.
|
|
52
|
+
|
|
53
|
+
#### `/etc/letsencrypt/` — TLS Certificates
|
|
54
|
+
|
|
55
|
+
| Path | Purpose |
|
|
56
|
+
| ---------------------- | ---------------------------------------- |
|
|
57
|
+
| `live/*/fullchain.pem` | Active certificate chain for each domain |
|
|
58
|
+
| `live/*/privkey.pem` | Private key for each domain |
|
|
59
|
+
| `renewal/*.conf` | Auto-renewal configuration per domain |
|
|
60
|
+
| `accounts/` | Let's Encrypt account credentials |
|
|
61
|
+
|
|
62
|
+
**If you lose Let's Encrypt certificates**, you can re-issue them (free, no limit for different domains), but it takes a few minutes per domain and is subject to rate limits (50 certificates per registered domain per week).
|
|
63
|
+
|
|
64
|
+
#### `/etc/nginx/` — Reverse Proxy Configuration
|
|
65
|
+
|
|
66
|
+
| Path | Purpose |
|
|
67
|
+
| -------------------------------------- | --------------------------------------------- |
|
|
68
|
+
| `sites-available/lamalibre-lamaste-*` | Lamaste vhost configurations |
|
|
69
|
+
| `sites-enabled/lamalibre-lamaste-*` | Symlinks to enabled vhosts |
|
|
70
|
+
| `snippets/lamalibre-lamaste-mtls.conf` | mTLS configuration snippet |
|
|
71
|
+
| `nginx.conf` | Main nginx configuration (usually unmodified) |
|
|
72
|
+
|
|
73
|
+
**If you lose nginx configs**, the panel can regenerate vhosts for tunnels and sites, but you will need to re-run the provisioning or manually recreate the base vhosts (panel, auth, tunnel).
|
|
74
|
+
|
|
75
|
+
### Backup Commands
|
|
76
|
+
|
|
77
|
+
#### Full Backup (Recommended)
|
|
78
|
+
|
|
79
|
+
Run this on the droplet to create a single compressed archive of everything:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Create a timestamped backup
|
|
83
|
+
BACKUP_FILE="/root/lamaste-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
|
84
|
+
|
|
85
|
+
sudo tar czf "$BACKUP_FILE" \
|
|
86
|
+
/etc/lamalibre/lamaste/ \
|
|
87
|
+
/etc/authelia/ \
|
|
88
|
+
/etc/letsencrypt/ \
|
|
89
|
+
/etc/nginx/sites-available/lamalibre-lamaste-* \
|
|
90
|
+
/etc/nginx/sites-enabled/lamalibre-lamaste-* \
|
|
91
|
+
/etc/nginx/snippets/lamalibre-lamaste-mtls.conf \
|
|
92
|
+
/etc/systemd/system/lamalibre-lamaste-serverd.service \
|
|
93
|
+
/etc/systemd/system/chisel.service \
|
|
94
|
+
/etc/systemd/system/authelia.service \
|
|
95
|
+
/etc/fail2ban/jail.d/lamaste.conf \
|
|
96
|
+
/etc/sudoers.d/lamaste \
|
|
97
|
+
2>/dev/null
|
|
98
|
+
|
|
99
|
+
echo "Backup created: $BACKUP_FILE"
|
|
100
|
+
ls -lh "$BACKUP_FILE"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Download the Backup to Your Local Machine
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# From your local machine
|
|
107
|
+
scp root@203.0.113.42:/root/lamaste-backup-*.tar.gz ~/backups/
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Minimal Backup (Essential Files Only)
|
|
111
|
+
|
|
112
|
+
If you just want the irreplaceable data (certificates and state):
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
BACKUP_FILE="/root/lamaste-essential-$(date +%Y%m%d-%H%M%S).tar.gz"
|
|
116
|
+
|
|
117
|
+
sudo tar czf "$BACKUP_FILE" \
|
|
118
|
+
/etc/lamalibre/lamaste/ \
|
|
119
|
+
/etc/authelia/users.yml \
|
|
120
|
+
/etc/authelia/.secrets.json \
|
|
121
|
+
/etc/authelia/configuration.yml
|
|
122
|
+
|
|
123
|
+
echo "Essential backup created: $BACKUP_FILE"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### Automated Daily Backup
|
|
127
|
+
|
|
128
|
+
Create a cron job that runs daily and keeps the last 7 backups:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
sudo tee /etc/cron.daily/lamaste-backup << 'SCRIPT'
|
|
132
|
+
#!/bin/bash
|
|
133
|
+
BACKUP_DIR="/root/lamaste-backups"
|
|
134
|
+
mkdir -p "$BACKUP_DIR"
|
|
135
|
+
|
|
136
|
+
tar czf "$BACKUP_DIR/lamaste-$(date +%Y%m%d).tar.gz" \
|
|
137
|
+
/etc/lamalibre/lamaste/ \
|
|
138
|
+
/etc/authelia/ \
|
|
139
|
+
/etc/letsencrypt/ \
|
|
140
|
+
/etc/nginx/sites-available/lamalibre-lamaste-* \
|
|
141
|
+
/etc/nginx/snippets/lamalibre-lamaste-mtls.conf \
|
|
142
|
+
2>/dev/null
|
|
143
|
+
|
|
144
|
+
# Keep only the last 7 backups
|
|
145
|
+
ls -t "$BACKUP_DIR"/lamaste-*.tar.gz | tail -n +8 | xargs -r rm --
|
|
146
|
+
SCRIPT
|
|
147
|
+
|
|
148
|
+
sudo chmod +x /etc/cron.daily/lamaste-backup
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Restore Procedure
|
|
152
|
+
|
|
153
|
+
#### Restoring to the Same Server
|
|
154
|
+
|
|
155
|
+
If you need to restore files on the same server (e.g., after accidental deletion):
|
|
156
|
+
|
|
157
|
+
**Step 1: Stop all services**
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
sudo systemctl stop lamalibre-lamaste-serverd
|
|
161
|
+
sudo systemctl stop chisel
|
|
162
|
+
sudo systemctl stop authelia
|
|
163
|
+
sudo systemctl stop nginx
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Step 2: Extract the backup**
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Preview the contents first
|
|
170
|
+
tar tzf /root/lamaste-backup-20260313-103045.tar.gz | head -30
|
|
171
|
+
|
|
172
|
+
# Extract (overwrites existing files)
|
|
173
|
+
sudo tar xzf /root/lamaste-backup-20260313-103045.tar.gz -C /
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Step 3: Fix permissions**
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
sudo chown -R lamaste:lamaste /etc/lamalibre/lamaste/
|
|
180
|
+
sudo chmod 700 /etc/lamalibre/lamaste/pki/
|
|
181
|
+
sudo chmod 600 /etc/lamalibre/lamaste/pki/ca.key
|
|
182
|
+
sudo chmod 600 /etc/lamalibre/lamaste/pki/client.key
|
|
183
|
+
sudo chmod 600 /etc/lamalibre/lamaste/pki/client.p12
|
|
184
|
+
sudo chmod 600 /etc/lamalibre/lamaste/pki/.p12-password
|
|
185
|
+
sudo chmod 640 /etc/lamalibre/lamaste/panel.json
|
|
186
|
+
# Files the Chisel server (User=nobody, Group=lamaste-chisel) must read
|
|
187
|
+
sudo chgrp lamaste-chisel /etc/lamalibre/lamaste/chisel-users /etc/lamalibre/lamaste/chisel-server.key
|
|
188
|
+
sudo chmod 640 /etc/lamalibre/lamaste/chisel-users /etc/lamalibre/lamaste/chisel-server.key
|
|
189
|
+
# Authelia: the panel owns its configuration; Authelia (lamaste-authelia) reads it
|
|
190
|
+
# through the group and owns its database and notification file
|
|
191
|
+
sudo chown lamaste:lamaste-authelia /etc/authelia /etc/authelia/configuration.yml /etc/authelia/users.yml /etc/authelia/.secrets.json
|
|
192
|
+
sudo chmod 2770 /etc/authelia
|
|
193
|
+
sudo chmod 640 /etc/authelia/configuration.yml
|
|
194
|
+
sudo chmod 660 /etc/authelia/users.yml
|
|
195
|
+
sudo chmod 600 /etc/authelia/.secrets.json
|
|
196
|
+
sudo chown lamaste-authelia:lamaste-authelia /etc/authelia/db.sqlite3* /etc/authelia/notifications.txt
|
|
197
|
+
sudo chmod 600 /etc/authelia/db.sqlite3* /etc/authelia/notifications.txt
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
A backup taken on a version before the privilege boundary holds root-owned Authelia files and older unit files. After restoring one, re-run `npx @lamalibre/create-lamaste@4.0.0 --yes`: the redeploy rewrites the `chisel` and `authelia` units and converts the ownership of `/etc/authelia`, the Chisel key and the PKI directory (see [Upgrades](upgrades.md)).
|
|
201
|
+
|
|
202
|
+
The panel re-applies the authfile's group and mode itself on every start, so a Chisel that fails to read it before the panel is up is started again by the panel's reconciliation.
|
|
203
|
+
|
|
204
|
+
**Step 4: Validate nginx configuration**
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
sudo nginx -t
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
If the test fails, check for missing certificate files referenced in the vhosts.
|
|
211
|
+
|
|
212
|
+
**Step 5: Restart services**
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
sudo systemctl start nginx
|
|
216
|
+
sudo systemctl start authelia
|
|
217
|
+
sudo systemctl start chisel
|
|
218
|
+
sudo systemctl start lamalibre-lamaste-serverd
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Step 6: Verify**
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
sudo systemctl status nginx chisel authelia lamalibre-lamaste-serverd
|
|
225
|
+
curl -s http://127.0.0.1:3100/api/health
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### Restoring to a New Server (Migration)
|
|
229
|
+
|
|
230
|
+
To move Lamaste to a new droplet:
|
|
231
|
+
|
|
232
|
+
**Step 1: Create a fresh droplet** (Ubuntu 24.04, same region if possible)
|
|
233
|
+
|
|
234
|
+
**Step 2: Run the installer**
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
npx @lamalibre/create-lamaste@latest --yes
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Step 3: Stop services**
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
sudo systemctl stop lamalibre-lamaste-serverd chisel authelia nginx
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Step 4: Upload and extract the backup**
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# From your local machine
|
|
250
|
+
scp ~/backups/lamaste-backup-20260313-103045.tar.gz root@<new-ip>:/root/
|
|
251
|
+
|
|
252
|
+
# On the new server
|
|
253
|
+
sudo tar xzf /root/lamaste-backup-20260313-103045.tar.gz -C /
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Step 5: Update the IP address in panel.json**
|
|
257
|
+
|
|
258
|
+
The new server has a different IP. Update it:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Replace old IP with new IP
|
|
262
|
+
sudo sed -i 's/OLD_IP/NEW_IP/g' /etc/lamalibre/lamaste/panel.json
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Step 6: Regenerate the self-signed certificate for the new IP**
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
sudo openssl req -x509 -nodes -days 3650 \
|
|
269
|
+
-newkey rsa:2048 \
|
|
270
|
+
-keyout /etc/lamalibre/lamaste/pki/self-signed-key.pem \
|
|
271
|
+
-out /etc/lamalibre/lamaste/pki/self-signed.pem \
|
|
272
|
+
-subj "/CN=NEW_IP/O=Lamaste" \
|
|
273
|
+
-addext "subjectAltName=IP:NEW_IP"
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Step 7: Update DNS records** to point to the new IP
|
|
277
|
+
|
|
278
|
+
**Step 8: Fix permissions (same as Step 3 above)**
|
|
279
|
+
|
|
280
|
+
**Step 9: Restart services**
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
sudo systemctl daemon-reload
|
|
284
|
+
sudo systemctl start nginx authelia chisel lamalibre-lamaste-serverd
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Step 10: Re-issue Let's Encrypt certificates** (they are bound to the server that responded to the ACME challenge)
|
|
288
|
+
|
|
289
|
+
If DNS is already pointing to the new server, the existing certificates will still work. When they are due for renewal, certbot will handle it automatically. If you need to force re-issuance:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
sudo certbot renew --force-renewal
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Step 11: Verify everything works** through the browser at `https://<new-ip>:9292`
|
|
296
|
+
|
|
297
|
+
The existing client certificate (`.p12` file) will still work because the CA key was restored from the backup.
|
|
298
|
+
|
|
299
|
+
## For Developers
|
|
300
|
+
|
|
301
|
+
### State File Locations
|
|
302
|
+
|
|
303
|
+
All Lamaste state is stored as flat files with atomic writes:
|
|
304
|
+
|
|
305
|
+
| File | Format | Write Pattern |
|
|
306
|
+
| ----------------------------------------- | ------ | ------------------------------------------------------------- |
|
|
307
|
+
| `/etc/lamalibre/lamaste/panel.json` | JSON | Write `.tmp` then `rename()` |
|
|
308
|
+
| `/etc/lamalibre/lamaste/tunnels.json` | JSON | Write `.tmp`, `fsync()`, then `rename()` |
|
|
309
|
+
| `/etc/lamalibre/lamaste/sites.json` | JSON | Write `.tmp`, `fsync()`, then `rename()` |
|
|
310
|
+
| `/etc/lamalibre/lamaste/invitations.json` | JSON | Write `.tmp`, `fsync()`, then `rename()` |
|
|
311
|
+
| `/etc/authelia/users.yml` | YAML | Temp file in `/etc/authelia`, `fsync()`, `rename()` (no sudo) |
|
|
312
|
+
|
|
313
|
+
The atomic write pattern (write to temporary file, sync, rename) ensures that a crash during a write does not corrupt the primary file. The `rename()` system call is atomic on POSIX filesystems.
|
|
314
|
+
|
|
315
|
+
### Backup Considerations
|
|
316
|
+
|
|
317
|
+
- **`/etc/lamalibre/lamaste/pki/ca.key`** is the root of trust. All client certificates are signed by this CA. If the CA key changes, all previously issued client certificates become invalid.
|
|
318
|
+
- **`/etc/authelia/.secrets.json`** contains the JWT secret. If this changes, all active Authelia sessions are invalidated and users must re-authenticate.
|
|
319
|
+
- **`/etc/authelia/db.sqlite3`** contains Authelia session data and TOTP registration states. It can be regenerated (users re-enroll TOTP), but this is disruptive.
|
|
320
|
+
- **Let's Encrypt account credentials** in `/etc/letsencrypt/accounts/` are tied to the email address used during registration. If lost, certbot creates a new account on next run.
|
|
321
|
+
|
|
322
|
+
## Quick Reference
|
|
323
|
+
|
|
324
|
+
| Directory | Contains | Criticality |
|
|
325
|
+
| ----------------------------- | -------------------------- | --------------------------------- |
|
|
326
|
+
| `/etc/lamalibre/lamaste/` | Config, state, PKI | Critical — irreplaceable PKI keys |
|
|
327
|
+
| `/etc/authelia/` | User database, auth config | High — user accounts and secrets |
|
|
328
|
+
| `/etc/letsencrypt/` | TLS certificates | Medium — can be re-issued |
|
|
329
|
+
| `/etc/nginx/sites-available/` | Vhost configs | Low — can be regenerated |
|
|
330
|
+
|
|
331
|
+
| Backup Command | What It Does |
|
|
332
|
+
| -------------------------------------------------------------------------------- | ------------------- |
|
|
333
|
+
| `tar czf backup.tar.gz /etc/lamalibre/lamaste/ /etc/authelia/ /etc/letsencrypt/` | Full config backup |
|
|
334
|
+
| `scp root@IP:/root/backup.tar.gz ~/backups/` | Download backup |
|
|
335
|
+
| `tar xzf backup.tar.gz -C /` | Restore from backup |
|
|
336
|
+
|
|
337
|
+
| Post-Restore Step | Command |
|
|
338
|
+
| -------------------- | ------------------------------------------------------------------------------------------------ |
|
|
339
|
+
| Fix PKI permissions | `sudo chmod 700 /etc/lamalibre/lamaste/pki/ && sudo chmod 600 /etc/lamalibre/lamaste/pki/ca.key` |
|
|
340
|
+
| Validate nginx | `sudo nginx -t` |
|
|
341
|
+
| Restart all services | `sudo systemctl restart nginx authelia chisel lamalibre-lamaste-serverd` |
|
|
342
|
+
| Verify health | `curl -s http://127.0.0.1:3100/api/health` |
|