@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.
Files changed (270) hide show
  1. package/LICENSE.md +118 -0
  2. package/README.md +114 -0
  3. package/bin/create-lamaste.js +15 -0
  4. package/package.json +54 -0
  5. package/scripts/bundle-vendor.js +110 -0
  6. package/scripts/lamaste-cert-info +62 -0
  7. package/scripts/lamaste-certbot +96 -0
  8. package/scripts/lamaste-priv +693 -0
  9. package/src/index.js +646 -0
  10. package/src/lib/accounts.js +86 -0
  11. package/src/lib/binaries.js +137 -0
  12. package/src/lib/cert-help-page.js +160 -0
  13. package/src/lib/env.js +132 -0
  14. package/src/lib/http-redirect.js +38 -0
  15. package/src/lib/ownership.js +231 -0
  16. package/src/lib/relay-services.js +103 -0
  17. package/src/lib/secrets.js +19 -0
  18. package/src/lib/service-config.js +311 -0
  19. package/src/lib/summary.js +131 -0
  20. package/src/lib/wrappers.js +63 -0
  21. package/src/tasks/gatekeeper.js +233 -0
  22. package/src/tasks/harden.js +293 -0
  23. package/src/tasks/mtls.js +193 -0
  24. package/src/tasks/nginx.js +265 -0
  25. package/src/tasks/node.js +110 -0
  26. package/src/tasks/panel.js +408 -0
  27. package/src/tasks/redeploy.js +438 -0
  28. package/vendor/docs/00-introduction/how-it-works.md +447 -0
  29. package/vendor/docs/00-introduction/quickstart.md +472 -0
  30. package/vendor/docs/00-introduction/what-is-lamaste.md +112 -0
  31. package/vendor/docs/01-concepts/authentication.md +464 -0
  32. package/vendor/docs/01-concepts/authorization.md +242 -0
  33. package/vendor/docs/01-concepts/certificates.md +452 -0
  34. package/vendor/docs/01-concepts/dns-and-domains.md +343 -0
  35. package/vendor/docs/01-concepts/mtls.md +490 -0
  36. package/vendor/docs/01-concepts/nginx-reverse-proxy.md +540 -0
  37. package/vendor/docs/01-concepts/security-model.md +600 -0
  38. package/vendor/docs/01-concepts/tickets.md +414 -0
  39. package/vendor/docs/01-concepts/tunneling.md +367 -0
  40. package/vendor/docs/02-guides/agent-setup.md +194 -0
  41. package/vendor/docs/02-guides/certificate-management.md +341 -0
  42. package/vendor/docs/02-guides/cloud-provisioning.md +406 -0
  43. package/vendor/docs/02-guides/desktop-app-setup.md +226 -0
  44. package/vendor/docs/02-guides/disaster-recovery.md +464 -0
  45. package/vendor/docs/02-guides/first-tunnel.md +230 -0
  46. package/vendor/docs/02-guides/installation.md +393 -0
  47. package/vendor/docs/02-guides/managing-users.md +255 -0
  48. package/vendor/docs/02-guides/onboarding.md +244 -0
  49. package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +375 -0
  50. package/vendor/docs/02-guides/static-sites.md +364 -0
  51. package/vendor/docs/03-architecture/e2e-three-vm-sequences.md +457 -0
  52. package/vendor/docs/03-architecture/installer-flow.md +151 -0
  53. package/vendor/docs/03-architecture/installer.md +445 -0
  54. package/vendor/docs/03-architecture/management-flow.md +288 -0
  55. package/vendor/docs/03-architecture/nginx-configuration.md +830 -0
  56. package/vendor/docs/03-architecture/onboarding-flow.md +164 -0
  57. package/vendor/docs/03-architecture/overview.md +541 -0
  58. package/vendor/docs/03-architecture/panel-client.md +416 -0
  59. package/vendor/docs/03-architecture/panel-server.md +695 -0
  60. package/vendor/docs/03-architecture/state-management.md +529 -0
  61. package/vendor/docs/03-architecture/system-overview.md +167 -0
  62. package/vendor/docs/04-api-reference/certificates.md +1141 -0
  63. package/vendor/docs/04-api-reference/gatekeeper.md +592 -0
  64. package/vendor/docs/04-api-reference/onboarding.md +473 -0
  65. package/vendor/docs/04-api-reference/overview.md +404 -0
  66. package/vendor/docs/04-api-reference/services.md +267 -0
  67. package/vendor/docs/04-api-reference/settings.md +343 -0
  68. package/vendor/docs/04-api-reference/sites.md +716 -0
  69. package/vendor/docs/04-api-reference/system.md +268 -0
  70. package/vendor/docs/04-api-reference/tickets.md +618 -0
  71. package/vendor/docs/04-api-reference/tunnels.md +417 -0
  72. package/vendor/docs/04-api-reference/users.md +333 -0
  73. package/vendor/docs/05-operations/backup-and-restore.md +342 -0
  74. package/vendor/docs/05-operations/monitoring.md +285 -0
  75. package/vendor/docs/05-operations/uninstalling.md +344 -0
  76. package/vendor/docs/05-operations/upgrades.md +270 -0
  77. package/vendor/docs/06-reference/config-files.md +1080 -0
  78. package/vendor/docs/06-reference/glossary.md +528 -0
  79. package/vendor/docs/06-reference/installer-flags.md +260 -0
  80. package/vendor/docs/06-reference/ports-and-services.md +244 -0
  81. package/vendor/docs/06-reference/troubleshooting.md +665 -0
  82. package/vendor/docs/_index.json +233 -0
  83. package/vendor/docs/gatekeeper-design.md +953 -0
  84. package/vendor/docs/package.json +15 -0
  85. package/vendor/docs/todo/lib-cli-desktop-refactor.md +641 -0
  86. package/vendor/gatekeeper/dist/boot.d.ts +1 -0
  87. package/vendor/gatekeeper/dist/boot.d.ts.map +1 -0
  88. package/vendor/gatekeeper/dist/boot.js +17 -0
  89. package/vendor/gatekeeper/dist/boot.js.map +1 -0
  90. package/vendor/gatekeeper/dist/cli/commands/access.d.ts +2 -0
  91. package/vendor/gatekeeper/dist/cli/commands/access.d.ts.map +1 -0
  92. package/vendor/gatekeeper/dist/cli/commands/access.js +33 -0
  93. package/vendor/gatekeeper/dist/cli/commands/access.js.map +1 -0
  94. package/vendor/gatekeeper/dist/cli/commands/grants.d.ts +2 -0
  95. package/vendor/gatekeeper/dist/cli/commands/grants.d.ts.map +1 -0
  96. package/vendor/gatekeeper/dist/cli/commands/grants.js +110 -0
  97. package/vendor/gatekeeper/dist/cli/commands/grants.js.map +1 -0
  98. package/vendor/gatekeeper/dist/cli/commands/groups.d.ts +2 -0
  99. package/vendor/gatekeeper/dist/cli/commands/groups.d.ts.map +1 -0
  100. package/vendor/gatekeeper/dist/cli/commands/groups.js +98 -0
  101. package/vendor/gatekeeper/dist/cli/commands/groups.js.map +1 -0
  102. package/vendor/gatekeeper/dist/cli/index.d.ts +3 -0
  103. package/vendor/gatekeeper/dist/cli/index.d.ts.map +1 -0
  104. package/vendor/gatekeeper/dist/cli/index.js +45 -0
  105. package/vendor/gatekeeper/dist/cli/index.js.map +1 -0
  106. package/vendor/gatekeeper/dist/index.d.ts +9 -0
  107. package/vendor/gatekeeper/dist/index.d.ts.map +1 -0
  108. package/vendor/gatekeeper/dist/index.js +13 -0
  109. package/vendor/gatekeeper/dist/index.js.map +1 -0
  110. package/vendor/gatekeeper/dist/lib/authz.d.ts +16 -0
  111. package/vendor/gatekeeper/dist/lib/authz.d.ts.map +1 -0
  112. package/vendor/gatekeeper/dist/lib/authz.js +42 -0
  113. package/vendor/gatekeeper/dist/lib/authz.js.map +1 -0
  114. package/vendor/gatekeeper/dist/lib/cache-bust.d.ts +15 -0
  115. package/vendor/gatekeeper/dist/lib/cache-bust.d.ts.map +1 -0
  116. package/vendor/gatekeeper/dist/lib/cache-bust.js +19 -0
  117. package/vendor/gatekeeper/dist/lib/cache-bust.js.map +1 -0
  118. package/vendor/gatekeeper/dist/lib/constants.d.ts +82 -0
  119. package/vendor/gatekeeper/dist/lib/constants.d.ts.map +1 -0
  120. package/vendor/gatekeeper/dist/lib/constants.js +79 -0
  121. package/vendor/gatekeeper/dist/lib/constants.js.map +1 -0
  122. package/vendor/gatekeeper/dist/lib/grants.d.ts +32 -0
  123. package/vendor/gatekeeper/dist/lib/grants.d.ts.map +1 -0
  124. package/vendor/gatekeeper/dist/lib/grants.js +314 -0
  125. package/vendor/gatekeeper/dist/lib/grants.js.map +1 -0
  126. package/vendor/gatekeeper/dist/lib/groups.d.ts +10 -0
  127. package/vendor/gatekeeper/dist/lib/groups.d.ts.map +1 -0
  128. package/vendor/gatekeeper/dist/lib/groups.js +247 -0
  129. package/vendor/gatekeeper/dist/lib/groups.js.map +1 -0
  130. package/vendor/gatekeeper/dist/lib/migration.d.ts +17 -0
  131. package/vendor/gatekeeper/dist/lib/migration.d.ts.map +1 -0
  132. package/vendor/gatekeeper/dist/lib/migration.js +79 -0
  133. package/vendor/gatekeeper/dist/lib/migration.js.map +1 -0
  134. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0001_groups.sql +7 -0
  135. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0002_access_grants.sql +14 -0
  136. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0003_access_request_log.sql +9 -0
  137. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0001_groups.sql +7 -0
  138. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0002_access_grants.sql +14 -0
  139. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0003_access_request_log.sql +9 -0
  140. package/vendor/gatekeeper/dist/lib/state-db.d.ts +16 -0
  141. package/vendor/gatekeeper/dist/lib/state-db.d.ts.map +1 -0
  142. package/vendor/gatekeeper/dist/lib/state-db.js +154 -0
  143. package/vendor/gatekeeper/dist/lib/state-db.js.map +1 -0
  144. package/vendor/gatekeeper/dist/lib/templates.d.ts +21 -0
  145. package/vendor/gatekeeper/dist/lib/templates.d.ts.map +1 -0
  146. package/vendor/gatekeeper/dist/lib/templates.js +151 -0
  147. package/vendor/gatekeeper/dist/lib/templates.js.map +1 -0
  148. package/vendor/gatekeeper/dist/lib/types.d.ts +178 -0
  149. package/vendor/gatekeeper/dist/lib/types.d.ts.map +1 -0
  150. package/vendor/gatekeeper/dist/lib/types.js +2 -0
  151. package/vendor/gatekeeper/dist/lib/types.js.map +1 -0
  152. package/vendor/gatekeeper/dist/server/index.d.ts +15 -0
  153. package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -0
  154. package/vendor/gatekeeper/dist/server/index.js +251 -0
  155. package/vendor/gatekeeper/dist/server/index.js.map +1 -0
  156. package/vendor/gatekeeper/dist/server/routes/access-request.d.ts +7 -0
  157. package/vendor/gatekeeper/dist/server/routes/access-request.d.ts.map +1 -0
  158. package/vendor/gatekeeper/dist/server/routes/access-request.js +17 -0
  159. package/vendor/gatekeeper/dist/server/routes/access-request.js.map +1 -0
  160. package/vendor/gatekeeper/dist/server/routes/authz.d.ts +3 -0
  161. package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -0
  162. package/vendor/gatekeeper/dist/server/routes/authz.js +279 -0
  163. package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -0
  164. package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts +13 -0
  165. package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts.map +1 -0
  166. package/vendor/gatekeeper/dist/server/routes/diagnostic.js +249 -0
  167. package/vendor/gatekeeper/dist/server/routes/diagnostic.js.map +1 -0
  168. package/vendor/gatekeeper/dist/server/routes/grants.d.ts +3 -0
  169. package/vendor/gatekeeper/dist/server/routes/grants.d.ts.map +1 -0
  170. package/vendor/gatekeeper/dist/server/routes/grants.js +112 -0
  171. package/vendor/gatekeeper/dist/server/routes/grants.js.map +1 -0
  172. package/vendor/gatekeeper/dist/server/routes/groups.d.ts +3 -0
  173. package/vendor/gatekeeper/dist/server/routes/groups.d.ts.map +1 -0
  174. package/vendor/gatekeeper/dist/server/routes/groups.js +139 -0
  175. package/vendor/gatekeeper/dist/server/routes/groups.js.map +1 -0
  176. package/vendor/gatekeeper/package.json +49 -0
  177. package/vendor/server/bin/lamaste-server.js +204 -0
  178. package/vendor/server/package.json +31 -0
  179. package/vendor/server/src/commands/certs.js +224 -0
  180. package/vendor/server/src/commands/chisel.js +132 -0
  181. package/vendor/server/src/commands/logs.js +49 -0
  182. package/vendor/server/src/commands/plugins.js +321 -0
  183. package/vendor/server/src/commands/reset-admin.js +478 -0
  184. package/vendor/server/src/commands/restart.js +94 -0
  185. package/vendor/server/src/commands/sites.js +257 -0
  186. package/vendor/server/src/commands/status.js +158 -0
  187. package/vendor/server/src/commands/tunnels.js +365 -0
  188. package/vendor/server/src/commands/uninstall.js +326 -0
  189. package/vendor/server/src/config.js +38 -0
  190. package/vendor/server/src/exec.js +26 -0
  191. package/vendor/server/src/logger.js +39 -0
  192. package/vendor/server/src/ndjson.js +56 -0
  193. package/vendor/server/src/panel-api.js +85 -0
  194. package/vendor/server/src/state.js +45 -0
  195. package/vendor/server-ui/dist/assets/index-B0nWuUyL.js +257 -0
  196. package/vendor/server-ui/dist/assets/index-BqWWFlTU.css +1 -0
  197. package/vendor/server-ui/dist/index.html +13 -0
  198. package/vendor/serverd/package.json +44 -0
  199. package/vendor/serverd/src/boot.js +13 -0
  200. package/vendor/serverd/src/index.js +191 -0
  201. package/vendor/serverd/src/lib/app-error.js +14 -0
  202. package/vendor/serverd/src/lib/authelia.js +85 -0
  203. package/vendor/serverd/src/lib/certbot.js +74 -0
  204. package/vendor/serverd/src/lib/chisel-args.js +6 -0
  205. package/vendor/serverd/src/lib/chisel-reconcile.js +232 -0
  206. package/vendor/serverd/src/lib/chisel-runtime.js +46 -0
  207. package/vendor/serverd/src/lib/chisel-users.js +109 -0
  208. package/vendor/serverd/src/lib/chisel.js +81 -0
  209. package/vendor/serverd/src/lib/config.js +190 -0
  210. package/vendor/serverd/src/lib/constants.js +8 -0
  211. package/vendor/serverd/src/lib/csr-signing.js +331 -0
  212. package/vendor/serverd/src/lib/enrollment.js +302 -0
  213. package/vendor/serverd/src/lib/files.js +19 -0
  214. package/vendor/serverd/src/lib/gatekeeper-client.js +135 -0
  215. package/vendor/serverd/src/lib/invite-page.js +281 -0
  216. package/vendor/serverd/src/lib/ip-utils.js +79 -0
  217. package/vendor/serverd/src/lib/migrations/state/0001_enrollment_tokens.sql +17 -0
  218. package/vendor/serverd/src/lib/migrations/state/0002_tickets.sql +70 -0
  219. package/vendor/serverd/src/lib/migrations/state/0003_plugins.sql +15 -0
  220. package/vendor/serverd/src/lib/migrations/state/0004_agents.sql +19 -0
  221. package/vendor/serverd/src/lib/mtls.js +795 -0
  222. package/vendor/serverd/src/lib/nginx.js +1090 -0
  223. package/vendor/serverd/src/lib/pki-paths.js +41 -0
  224. package/vendor/serverd/src/lib/pki-sign.js +103 -0
  225. package/vendor/serverd/src/lib/plugins.js +538 -0
  226. package/vendor/serverd/src/lib/push-install.js +390 -0
  227. package/vendor/serverd/src/lib/revocation.js +112 -0
  228. package/vendor/serverd/src/lib/services.js +131 -0
  229. package/vendor/serverd/src/lib/session.js +151 -0
  230. package/vendor/serverd/src/lib/state-db.js +130 -0
  231. package/vendor/serverd/src/lib/state.js +140 -0
  232. package/vendor/serverd/src/lib/storage.js +63 -0
  233. package/vendor/serverd/src/lib/system-stats.js +58 -0
  234. package/vendor/serverd/src/lib/tickets.js +1556 -0
  235. package/vendor/serverd/src/lib/totp.js +76 -0
  236. package/vendor/serverd/src/lib/tunnel-deps.js +41 -0
  237. package/vendor/serverd/src/lib/user-access-session.js +142 -0
  238. package/vendor/serverd/src/lib/user-access.js +52 -0
  239. package/vendor/serverd/src/middleware/errors.js +63 -0
  240. package/vendor/serverd/src/middleware/mtls.js +120 -0
  241. package/vendor/serverd/src/middleware/onboarding-guard.js +30 -0
  242. package/vendor/serverd/src/middleware/role-guard.js +58 -0
  243. package/vendor/serverd/src/middleware/twofa-session.js +65 -0
  244. package/vendor/serverd/src/middleware/user-access-session.js +52 -0
  245. package/vendor/serverd/src/routes/enrollment.js +120 -0
  246. package/vendor/serverd/src/routes/health.js +22 -0
  247. package/vendor/serverd/src/routes/invite.js +163 -0
  248. package/vendor/serverd/src/routes/management/agents.js +182 -0
  249. package/vendor/serverd/src/routes/management/certs.js +911 -0
  250. package/vendor/serverd/src/routes/management/gatekeeper-proxy.js +160 -0
  251. package/vendor/serverd/src/routes/management/identity.js +107 -0
  252. package/vendor/serverd/src/routes/management/invitations.js +166 -0
  253. package/vendor/serverd/src/routes/management/logs.js +218 -0
  254. package/vendor/serverd/src/routes/management/plugins.js +560 -0
  255. package/vendor/serverd/src/routes/management/services.js +63 -0
  256. package/vendor/serverd/src/routes/management/settings.js +325 -0
  257. package/vendor/serverd/src/routes/management/sites.js +522 -0
  258. package/vendor/serverd/src/routes/management/storage.js +192 -0
  259. package/vendor/serverd/src/routes/management/system.js +201 -0
  260. package/vendor/serverd/src/routes/management/tickets.js +457 -0
  261. package/vendor/serverd/src/routes/management/tunnels.js +709 -0
  262. package/vendor/serverd/src/routes/management/users.js +377 -0
  263. package/vendor/serverd/src/routes/management.js +36 -0
  264. package/vendor/serverd/src/routes/onboarding/dns.js +101 -0
  265. package/vendor/serverd/src/routes/onboarding/domain.js +42 -0
  266. package/vendor/serverd/src/routes/onboarding/index.js +18 -0
  267. package/vendor/serverd/src/routes/onboarding/provision.js +327 -0
  268. package/vendor/serverd/src/routes/onboarding/status.js +12 -0
  269. package/vendor/serverd/src/routes/plugin-router.js +79 -0
  270. package/vendor/serverd/src/routes/user-access.js +389 -0
@@ -0,0 +1,541 @@
1
+ # System Architecture Overview
2
+
3
+ > Lamaste is a relay-based tunneling platform where a $4 VPS acts as a gateway between the public internet and web apps running behind a firewall.
4
+
5
+ ## In Plain English
6
+
7
+ Lamaste has three main pieces:
8
+
9
+ 1. **The Installer** (`npx @lamalibre/create-lamaste@4.0.0`) — a one-shot script you run once on a fresh VPS. It sets up nginx, generates security certificates, and deploys a web-based control panel. After it finishes, you never SSH into the server again.
10
+
11
+ 2. **The Panel** (browser UI + backend API) — a management interface protected by a client certificate. Through it, you configure your domain, create tunnels, manage users, and monitor services.
12
+
13
+ 3. **The Tunnel Stack** (Chisel + Authelia + nginx + certbot) — the runtime infrastructure that routes traffic from the internet to your local apps through encrypted WebSocket tunnels, protected by two-factor authentication.
14
+
15
+ These three pieces interact through a clear lifecycle: the installer creates the panel, the panel provisions the tunnel stack, and the tunnel stack serves your apps.
16
+
17
+ ## System Diagram
18
+
19
+ ```
20
+ ┌──────────────────────────────────────────────────────┐
21
+ │ VPS (Ubuntu 24.04) │
22
+ │ │
23
+ Admin Browser │ ┌──────────────────────────────────────────────┐ │
24
+ (with client cert) │ │ nginx (public-facing) │ │
25
+ │ │ │ │ │
26
+ │ HTTPS :9292 │ │ :9292 (mTLS, self-signed) │ │
27
+ ├─────────────────►│ │ └─► 127.0.0.1:3100 (Panel Server) │ │
28
+ │ │ │ │ │
29
+ │ HTTPS :443 │ │ :443 (Let's Encrypt) │ │
30
+ │ │ │ panel.<domain> │ │
31
+ │ │ │ └─► 127.0.0.1:3100 (Panel Server) │ │
32
+ │ │ │ auth.<domain> │ │
33
+ End Users │ │ └─► 127.0.0.1:9091 (Authelia) │ │
34
+ │ │ │ tunnel.<domain> │ │
35
+ ├─────────────────►│ │ └─► 127.0.0.1:9090 (Chisel Server) │ │
36
+ │ │ │ <app>.<domain> │ │
37
+ │ │ │ └─► auth_request to Authelia │ │
38
+ │ │ │ └─► 127.0.0.1:<port> (tunneled app) │ │
39
+ │ │ └──────────────────────────────────────────────┘ │
40
+ │ │ │
41
+ │ │ ┌──────────────┐ ┌──────────────┐ │
42
+ │ │ │ Panel Server │ │ Authelia │ │
43
+ │ │ │ (Fastify) │ │ (TOTP 2FA) │ │
44
+ │ │ │ 127.0.0.1 │ │ 127.0.0.1 │ │
45
+ │ │ │ :3100 │ │ :9091 │ │
46
+ │ │ └──────────────┘ └──────────────┘ │
47
+ │ │ │
48
+ │ │ ┌──────────────────────┐ │
49
+ │ │ │ Chisel Server │ │
50
+ │ │ │ 127.0.0.1:9090 │◄────── WebSocket ──────┐ │
51
+ │ │ │ (reverse mode) │ │ │
52
+ │ │ └──────────────────────┘ │ │
53
+ │ │ │ │
54
+ │ └───────────────────────────────────────────────────┼──┘
55
+ │ │
56
+ │ │
57
+ │ ┌──────────────────────────────────────────┐ │
58
+ │ │ Agent (Mac or Linux, behind NAT) │ │
59
+ │ │ │ │
60
+ │ │ ┌──────────────────────┐ │ │
61
+ │ │ │ Chisel Client │───────────────┼────────┘
62
+ │ │ │ (launchd / systemd) │ │
63
+ │ │ │ auto-reconnect │ │
64
+ │ │ └──────────┬───────────┘ │
65
+ │ │ │ │
66
+ │ │ ┌──────────┴───────────┐ │
67
+ │ │ │ Your Web Apps │ │
68
+ │ │ │ :3000, :8001, etc. │ │
69
+ │ │ └──────────────────────┘ │
70
+ │ └──────────────────────────────────────────┘
71
+ ```
72
+
73
+ ## Component Roles
74
+
75
+ | Component | Binary / Process | Role |
76
+ | ----------------- | -------------------------------- | ------------------------------------------------------------------------------------------ |
77
+ | **nginx** | `nginx` (system package) | Only public-facing service. TLS termination, mTLS enforcement, reverse proxy, forward auth |
78
+ | **Panel Server** | `node src/index.js` (Fastify 5) | REST API + WebSocket backend for all management operations |
79
+ | **Panel Client** | Static files (React SPA) | Browser-based UI served by Panel Server via `@fastify/static` |
80
+ | **Chisel Server** | `/usr/local/bin/chisel` | WebSocket tunnel server accepting reverse connections from clients |
81
+ | **Chisel Client** | `/usr/local/bin/chisel` (on Mac) | Connects outbound to VPS, exposes local ports via reverse tunneling |
82
+ | **Authelia** | `/usr/local/bin/authelia` | TOTP two-factor authentication for tunneled apps via nginx forward auth |
83
+ | **Gatekeeper** | `node src/index.js` (Fastify 5) | Tunnel authorization service — nginx auth_request target for grant-based access control |
84
+ | **certbot** | `certbot` (system package) | Issues and auto-renews Let's Encrypt TLS certificates |
85
+ | **fail2ban** | `fail2ban` (system package) | Rate-limits brute-force attempts on SSH and nginx |
86
+
87
+ ## Port Allocation
88
+
89
+ | Port | Listener | Protocol | Exposure | Purpose |
90
+ | ------ | ------------- | -------- | ------------- | ------------------------------------------ |
91
+ | `22` | sshd | TCP | Public (UFW) | SSH access (key-only after hardening) |
92
+ | `443` | nginx | TCP | Public (UFW) | All domain-based HTTPS traffic |
93
+ | `9292` | nginx | TCP | Public (UFW) | IP-based admin panel access (mTLS) |
94
+ | `3100` | Panel Server | TCP | Loopback only | Fastify API + static file serving |
95
+ | `9090` | Chisel Server | TCP | Loopback only | WebSocket tunnel endpoint |
96
+ | `9091` | Authelia | TCP | Loopback only | Authentication portal + forward auth API |
97
+ | `9294` | Gatekeeper | TCP | Loopback only | Tunnel authorization (auth_request target) |
98
+
99
+ All backend services (Panel Server, Chisel, Authelia) bind exclusively to `127.0.0.1`. nginx is the only process listening on public interfaces.
100
+
101
+ ## RAM Budget (512MB Droplet)
102
+
103
+ The platform is designed to run on the cheapest possible VPS. Every technology choice was made with this constraint in mind.
104
+
105
+ | Component | Approximate RAM | Notes |
106
+ | ---------------------- | --------------- | ------------------------------------------------ |
107
+ | Ubuntu 24.04 baseline | ~120 MB | Systemd, kernel, base services |
108
+ | nginx | ~15 MB | Efficient C-based reverse proxy |
109
+ | Authelia | ~25 MB | Go binary, **must use bcrypt** (not argon2id) |
110
+ | Chisel Server | ~20 MB | Go binary, lightweight |
111
+ | Panel Server (Node.js) | ~30 MB | Fastify is one of the leanest Node.js frameworks |
112
+ | fail2ban | ~35 MB | Python-based, runs as daemon |
113
+ | **Total** | **~245 MB** | |
114
+ | **Headroom** | **~265 MB** | Plus 1 GB swap as safety net |
115
+
116
+ Authelia is configured with bcrypt (cost factor 12) instead of argon2id. argon2id uses ~93 MB per hash operation and causes OOM kills on 512 MB droplets. This is a hard constraint documented in Authelia's configuration at `packages/lamaste-serverd/src/lib/authelia.js`.
117
+
118
+ ## Data Flow: Admin Panel Access
119
+
120
+ ```
121
+ 1. Admin opens https://203.0.113.42:9292 in browser
122
+
123
+ 2. nginx :9292 performs TLS handshake with self-signed server cert
124
+ └─ ssl_verify_client optional → requests client certificate
125
+ └─ Enforcement per-location: if ($ssl_client_verify != SUCCESS) { return 496; }
126
+ └─ Public endpoints (/api/enroll, /api/invite) skip the check
127
+
128
+ 3. Browser presents client.p12 certificate (imported during setup)
129
+ └─ nginx validates against CA at /etc/lamalibre/lamaste/pki/ca.crt
130
+ └─ Sets X-SSL-Client-Verify: SUCCESS header
131
+
132
+ 4. nginx proxies to 127.0.0.1:3100
133
+ └─ Passes X-SSL-Client-Verify and X-SSL-Client-DN headers
134
+
135
+ 5. Panel Server (Fastify) onRequest hook checks X-SSL-Client-Verify
136
+ └─ If not SUCCESS → 403 (never reached in production, nginx blocks first)
137
+ └─ If SUCCESS → check certificate serial against revoked.json
138
+ └─ If revoked → 403 "Certificate has been revoked"
139
+ └─ Parse X-SSL-Client-DN for CN: admin → certRole=admin; agent:<label> → certRole=agent
140
+ └─ Set request.certRole, request.certLabel, request.certCapabilities
141
+
142
+ 6. Route handler executes business logic via lib/ layer
143
+ └─ Returns JSON response
144
+
145
+ 7. For SPA routes (non-/api paths), Fastify serves index.html from lamaste-server-ui dist/
146
+ ```
147
+
148
+ ## Data Flow: Tunnel Traffic
149
+
150
+ ```
151
+ 1. Mac Chisel Client connects outbound to wss://tunnel.example.com:443
152
+ └─ nginx :443 terminates TLS, proxies WebSocket to 127.0.0.1:9090
153
+ └─ Chisel Server accepts reverse tunnel registration
154
+
155
+ 2. End user visits https://myapp.example.com
156
+ └─ nginx :443 matches server_name myapp.example.com
157
+ └─ Let's Encrypt TLS certificate serves the connection
158
+
159
+ 3. nginx sends auth_request to Authelia at 127.0.0.1:9091
160
+ └─ Authelia checks session cookie
161
+ └─ If no session → 401 → nginx redirects to auth.example.com
162
+ └─ User enters username + TOTP code
163
+ └─ Authelia sets session cookie → redirect back
164
+
165
+ 4. With valid session, nginx proxies to 127.0.0.1:<port>
166
+ └─ Chisel Server forwards the request through the WebSocket tunnel
167
+ └─ Chisel Client on the Mac receives the request
168
+ └─ Chisel Client forwards to 127.0.0.1:<port> on the Mac
169
+ └─ Response travels back through the same path
170
+ ```
171
+
172
+ ## Gatekeeper (Tunnel Authorization)
173
+
174
+ The Gatekeeper is a dedicated Fastify service on `127.0.0.1:9294` that acts as an nginx `auth_request` target for tunnel authorization. It decouples access control decisions from both the Panel Server and Authelia, providing a generic grant-based authorization layer for tunnel traffic.
175
+
176
+ **Architecture:**
177
+
178
+ ```
179
+ End User → nginx :443 → auth_request → 127.0.0.1:9294/authz/check
180
+ │
181
+ ┌─────────┴──────────┐
182
+ │ Gatekeeper │
183
+ │ (Fastify, :9294) │
184
+ │ │
185
+ │ In-memory session │
186
+ │ cache (Map) │
187
+ │ │
188
+ │ State files: │
189
+ │ - groups.json │
190
+ │ - access-grants.json│
191
+ │ - gatekeeper.json │
192
+ └─────────────────────┘
193
+ ```
194
+
195
+ **Grant model:** The Gatekeeper uses a generic principal-to-resource grant model. A principal is an Authelia user or a Lamaste group. A resource is a tunnel subdomain or other protected endpoint. Grants are stored in `/etc/lamalibre/lamaste/access-grants.json`.
196
+
197
+ **Lamaste groups:** Separate from Authelia groups. Stored in `/etc/lamalibre/lamaste/groups.json`. Lamaste groups allow the admin to organize users for access control without modifying Authelia's `users.yml`.
198
+
199
+ **Two-layer caching:**
200
+
201
+ 1. **nginx `proxy_cache`** — the `lamaste_authz` cache zone (1m keys, 10m storage) caches authorization responses. Cache key is `$cookie_authelia_session$http_host`. Positive responses (200) are cached for 30 seconds, negative responses (401/403) for 10 seconds. This eliminates redundant auth_request subrequests for rapid page loads.
202
+ 2. **In-memory session cache** — the Gatekeeper maintains a `Map` of recent authorization decisions keyed by session + host. This avoids re-reading state files on every check within the cache TTL.
203
+
204
+ **State files:** All stored in `/etc/lamalibre/lamaste/` with 0600 permissions, `lamaste:lamaste` ownership, and atomic writes (tmp, fsync, rename):
205
+
206
+ - `groups.json` — Lamaste group definitions and membership
207
+ - `access-grants.json` — Principal-to-resource access grants
208
+ - `gatekeeper.json` — Settings (admin contact info, cache TTL, logging configuration)
209
+ - `access-request-log.json` — Optional log of denied access attempts (for admin review)
210
+
211
+ **Service:** Runs as `lamalibre-lamaste-gatekeeper.service` (systemd), binding `127.0.0.1:9294`. nginx is the sole entry point — the Gatekeeper is never directly accessible from the internet.
212
+
213
+ ## Data Flow: Onboarding Provisioning
214
+
215
+ ```
216
+ 1. Admin completes domain + DNS verification in the panel UI
217
+
218
+ 2. Panel Client sends POST /api/onboarding/provision
219
+ └─ Panel Server starts background provisioning task
220
+ └─ Returns 202 Accepted immediately
221
+
222
+ 3. Panel Client opens WebSocket to /api/onboarding/provision/stream
223
+ └─ Receives real-time progress events for each task
224
+
225
+ 4. Provisioning sequence (in Panel Server):
226
+ a. Check Chisel is installed (create-lamaste installed the pinned release
227
+ and its unit), create its key and authfile, start it
228
+ b. Check Authelia is installed (likewise: pinned release, unit, account)
229
+ c. Write Authelia config (bcrypt, TOTP, session cookies)
230
+ d. Create admin user with random password
231
+ e. Issue Let's Encrypt certs for panel/auth/tunnel subdomains
232
+ f. Write nginx vhosts for panel-domain, auth, tunnel
233
+ g. Enable sites + test nginx config + reload
234
+ h. Verify all services are running + healthy
235
+ i. Update panel.json onboarding.status to COMPLETED
236
+
237
+ 5. Panel Client receives completion event with admin credentials
238
+ └─ Displays TOTP enrollment QR code
239
+ ```
240
+
241
+ ## Monorepo Structure
242
+
243
+ ```
244
+ lamaste/
245
+ ├── packages/
246
+ │ ├── create-lamaste/ ← npx installer (zero-prompt)
247
+ │ │ ├── bin/create-lamaste.js ← CLI entry point
248
+ │ │ ├── src/
249
+ │ │ │ ├── index.js ← Listr2 orchestrator
250
+ │ │ │ ├── tasks/
251
+ │ │ │ │ ├── harden.js ← OS hardening (swap, UFW, fail2ban, SSH)
252
+ │ │ │ │ ├── node.js ← Node.js 20 installation
253
+ │ │ │ │ ├── mtls.js ← mTLS CA + client cert generation
254
+ │ │ │ │ ├── nginx.js ← IP-based nginx vhost + mTLS snippet
255
+ │ │ │ │ ├── panel.js ← Panel deployment + systemd service
256
+ │ │ │ │ ├── gatekeeper.js ← Gatekeeper deployment
257
+ │ │ │ │ └── redeploy.js ← Redeployment (upgrade, self-update)
258
+ │ │ │ └── lib/
259
+ │ │ │ ├── env.js ← OS detection, IP detection, root check
260
+ │ │ │ ├── secrets.js ← crypto.randomBytes wrappers
261
+ │ │ │ ├── summary.js ← Post-install summary box
262
+ │ │ │ ├── cert-help-page.js ← HTML page for visitors without certs
263
+ │ │ │ ├── relay-services.js ← Pinned chisel + Authelia, units, accounts, ownership
264
+ │ │ │ ├── ownership.js ← Symlink-safe root writes and ownership migrations
265
+ │ │ │ ├── wrappers.js ← Installs lamaste-priv etc. and the sudoers file
266
+ │ │ │ └── service-config.js ← Systemd unit + sudoers content generators
267
+ │ │ ├── scripts/ ← lamaste-priv, lamaste-certbot, lamaste-cert-info
268
+ │ │ └── vendor/ ← Bundled lamalibre-lamaste-serverd + lamaste-server-ui at publish time
269
+ │ │
270
+ │ ├── lamaste-serverd/ ← Fastify REST API (127.0.0.1:3100)
271
+ │ │ └── src/
272
+ │ │ ├── index.js ← Server entry, plugin registration
273
+ │ │ ├── middleware/
274
+ │ │ │ ├── mtls.js ← Client cert verification + revocation + role parsing
275
+ │ │ │ ├── role-guard.js ← Role-based access control (admin vs agent capabilities)
276
+ │ │ │ ├── onboarding-guard.js ← Route access control by onboarding state
277
+ │ │ │ ├── twofa-session.js ← 2FA session validation (runs after mTLS, before roleGuard)
278
+ │ │ │ └── errors.js ← Global error handler (Zod, AppError, 500)
279
+ │ │ ├── routes/
280
+ │ │ │ ├── health.js ← GET /api/health
281
+ │ │ │ ├── invite.js ← Public invite acceptance routes (no mTLS)
282
+ │ │ │ ├── enrollment.js ← Public /api/enroll endpoint for agent certificate enrollment
283
+ │ │ │ ├── onboarding/
284
+ │ │ │ │ ├── index.js ← Route registration + guard
285
+ │ │ │ │ ├── status.js ← GET /api/onboarding/status
286
+ │ │ │ │ ├── domain.js ← POST /api/onboarding/domain
287
+ │ │ │ │ ├── dns.js ← POST /api/onboarding/verify-dns
288
+ │ │ │ │ └── provision.js ← POST + WebSocket provisioning
289
+ │ │ │ ├── management.js ← Route registration + guard
290
+ │ │ │ └── management/
291
+ │ │ │ ├── invitations.js ← Invitation CRUD (admin-only)
292
+ │ │ │ ├── system.js ← GET /api/system/stats
293
+ │ │ │ ├── services.js ← Service start/stop/restart
294
+ │ │ │ ├── logs.js ← WebSocket live log streaming
295
+ │ │ │ ├── tunnels.js ← Tunnel CRUD, ownership, agent-config
296
+ │ │ │ ├── sites.js ← Static site CRUD + file management
297
+ │ │ │ ├── users.js ← Authelia user CRUD + TOTP
298
+ │ │ │ ├── certs.js ← Certificate listing + renewal + mTLS rotation
299
+ │ │ │ ├── plugins.js ← Plugin management + push install API
300
+ │ │ │ ├── settings.js ← 2FA and admin auth mode endpoints
301
+ │ │ │ └── tickets.js ← Agent-to-agent authorization endpoints
302
+ │ │ ├── plugin-router.js ← Dynamic plugin route mounting + disabled-plugin guard
303
+ │ │ └── lib/
304
+ │ │ ├── config.js ← panel.json loading + Zod validation + atomic updates
305
+ │ │ ├── state.js ← tunnels.json + sites.json + invitations.json atomic read/write
306
+ │ │ ├── revocation.js ← Certificate revocation list management (revoked.json)
307
+ │ │ ├── invite-page.js ← Invitation acceptance HTML page generator
308
+ │ │ ├── nginx.js ← Vhost generation + write-with-rollback + reload
309
+ │ │ ├── chisel.js ← Chisel key + service management + syncChisel
310
+ │ │ ├── chisel-users.js ← Per-agent Chisel credentials + authfile grants
311
+ │ │ ├── chisel-reconcile.js ← Startup reconciliation of Chisel (fail closed)
312
+ │ │ ├── chisel-runtime.js ← Restart decision for authfile changes
313
+ │ │ ├── tunnel-deps.js ← Dependencies for the core tunnel workflows
314
+ │ │ ├── authelia.js ← Authelia install + config + user CRUD
315
+ │ │ ├── certbot.js ← Let's Encrypt issuance + renewal
316
+ │ │ ├── mtls.js ← mTLS cert info + rotation + dynamic capabilities
317
+ │ │ ├── plugins.js ← Plugin install/uninstall/enable/disable + manifest validation
318
+ │ │ ├── push-install.js ← Push install config, policies, sessions, agent enable/disable
319
+ │ │ ├── services.js ← systemctl wrapper for managed services
320
+ │ │ ├── system-stats.js ← CPU, memory, disk stats via systeminformation
321
+ │ │ ├── files.js ← Static site file operations (upload, delete, list)
322
+ │ │ └── app-error.js ← Operational error class (AppError)
323
+ │ │
324
+ │ ├── lamaste-server-ui/ ← React 18 + Vite + Tailwind SPA + shared admin components (@lamalibre/lamaste-server-ui@4.0.0)
325
+ │ │ └── src/
326
+ │ │ ├── index.js ← Package exports (pages, context, utilities)
327
+ │ │ ├── context/
328
+ │ │ │ ├── AdminClientContext.jsx ← Host-agnostic data client abstraction
329
+ │ │ │ └── TwoFaContext.jsx ← 2FA verification state management
330
+ │ │ ├── components/
331
+ │ │ │ ├── Toast.jsx ← Toast notification system
332
+ │ │ │ ├── TwoFaVerifyModal.jsx ← 2FA verification modal
333
+ │ │ │ ├── FileBrowser.jsx ← File tree for static site management
334
+ │ │ │ └── PluginLoader.jsx ← Plugin micro-frontend loader
335
+ │ │ ├── lib/
336
+ │ │ │ ├── cn.js ← Class name utility
337
+ │ │ │ └── formatters.js ← Byte, uptime, relative time formatters
338
+ │ │ └── pages/ ← Admin pages (Dashboard, Tunnels, Sites, Users, Certs, Services, Plugins, Tickets, Settings)
339
+ │ │
340
+ │ ├── lamaste-agent-ui/ ← Shared React agent UI (pages, context, components) (@lamalibre/lamaste-agent-ui@4.0.0)
341
+ │ │
342
+ │ ├── lamaste-tickets/ ← Agent-to-agent authorization SDK (mTLS, undici)
343
+ │ │ └── src/
344
+ │ │ ├── index.ts ← Client + types
345
+ │ │ └── ...
346
+ │ │
347
+ │ ├── lamaste-cloud/ ← Cloud provider abstraction for server provisioning
348
+ │ │ ├── bin/lamaste-cloud.js ← CLI entry point (NDJSON progress on stdout)
349
+ │ │ └── src/
350
+ │ │ ├── index.ts ← Provider exports
351
+ │ │ ├── provider.ts ← CloudProvider interface
352
+ │ │ ├── provisioner.ts ← Provisioning orchestrator (create → install → configure)
353
+ │ │ ├── registry.ts ← Server registry (servers.json, atomic writes)
354
+ │ │ ├── ssh.ts ← SSH/SCP with temporary ed25519 keys
355
+ │ │ ├── types.ts ← Shared types
356
+ │ │ ├── errors.ts ← Error types
357
+ │ │ └── digitalocean/ ← DigitalOcean provider implementation
358
+ │ │
359
+ │ └── lamaste-server-ui/ ← (continued) SPA entry point, onboarding pages, browser-specific code
360
+ │ └── src/
361
+ │ ├── App.jsx ← Mode detection, routing, provider wrappers
362
+ │ ├── main.jsx ← React root mount
363
+ │ ├── lib/
364
+ │ │ ├── api.js ← API fetch helper with 2FA detection
365
+ │ │ ├── cn.js ← className utility
366
+ │ │ ├── formatters.js ← Byte/time formatters
367
+ │ │ └── web-admin-client.js ← AdminClient implementation via apiFetch
368
+ │ ├── hooks/
369
+ │ │ ├── useOnboardingStatus.js ← Determines onboarding vs management mode
370
+ │ │ └── useProvisioningStream.js ← WebSocket hook for provisioning progress
371
+ │ ├── pages/
372
+ │ │ ├── onboarding/
373
+ │ │ │ ├── OnboardingShell.jsx ← Step container + progress indicator
374
+ │ │ │ ├── DomainStep.jsx ← Domain + email form
375
+ │ │ │ ├── DnsStep.jsx ← DNS record display + verification
376
+ │ │ │ ├── ProvisioningStep.jsx ← Real-time progress + log viewer
377
+ │ │ │ └── CompleteStep.jsx ← Credentials + TOTP QR + next steps
378
+ │ │ ├── management/ ← Legacy standalone implementations (kept for reference)
379
+ │ │ │ ├── Certificates.jsx ← Standalone certificates page (dead code)
380
+ │ │ │ ├── Dashboard.jsx ← Standalone dashboard (not imported — App.jsx uses @lamalibre/lamaste-server-ui@4.0.0)
381
+ │ │ │ ├── Plugins.jsx ← Standalone plugins page (dead code)
382
+ │ │ │ ├── Services.jsx ← Standalone services page (dead code)
383
+ │ │ │ ├── Settings.jsx ← Standalone settings page (dead code)
384
+ │ │ │ ├── Sites.jsx ← Standalone sites page (dead code)
385
+ │ │ │ ├── Tickets.jsx ← Standalone tickets page (dead code)
386
+ │ │ │ └── Tunnels.jsx ← Standalone tunnels page (dead code)
387
+ │ │ └── docs/
388
+ │ │ └── DocsPage.jsx ← Documentation viewer (markdown)
389
+ │ └── components/
390
+ │ ├── layout/
391
+ │ │ ├── Layout.jsx ← Sidebar + content area
392
+ │ │ ├── Sidebar.jsx ← Navigation with mobile responsive
393
+ │ │ └── SidebarLink.jsx ← Active-state nav link
394
+ │ ├── PluginLoaderRoute.jsx ← Bridges React Router params to shared PluginLoader
395
+ │ ├── PluginLoader.jsx ← Legacy plugin loader (dead code — shared package version used)
396
+ │ ├── Toast.jsx ← Toast notification system
397
+ │ ├── LoadingScreen.jsx ← Full-page loading state
398
+ │ ├── ErrorScreen.jsx ← Full-page error with retry
399
+ │ └── FileBrowser.jsx ← File tree for static site management
400
+ │
401
+ └── CLAUDE.md ← Project context for AI agents
402
+ ```
403
+
404
+ ## Security Layers
405
+
406
+ The platform implements defense-in-depth with multiple security layers:
407
+
408
+ ```
409
+ Layer 1: Network (UFW)
410
+ └─ Only ports 22, 443, 9292 open
411
+ └─ Everything else is firewalled
412
+
413
+ Layer 2: fail2ban
414
+ └─ SSH brute-force protection (5 attempts → 1 hour ban)
415
+ └─ nginx auth failure protection
416
+
417
+ Layer 3: SSH Hardening
418
+ └─ Password authentication disabled
419
+ └─ Root login with key only
420
+
421
+ Layer 4: mTLS (Admin Panel)
422
+ └─ nginx rejects connections without valid client certificate
423
+ └─ Panel Server double-checks X-SSL-Client-Verify header
424
+ └─ Panel Server checks certificate serial against revoked.json
425
+ └─ Panel Server parses DN for role (admin vs agent) and sets certRole/certLabel/certCapabilities
426
+ └─ Agent capabilities: tunnels:read/write, services:read/write, system:read, sites:read/write, plus plugin-declared capabilities
427
+
428
+ Layer 5: Authelia (Tunneled Apps)
429
+ └─ nginx forward auth for every app request
430
+ └─ TOTP two-factor authentication
431
+ └─ Session cookies scoped to domain
432
+
433
+ Layer 6: Service Isolation
434
+ └─ All backend services bind 127.0.0.1 only
435
+ └─ lamaste user runs with minimal privileges; code in /opt/lamalibre/lamaste is root-owned
436
+ └─ Fixed sudoers command lines + the validating lamaste-priv helper (no wildcards)
437
+ └─ Authelia runs as its own account (lamaste-authelia), Chisel as nobody:lamaste-chisel
438
+ └─ systemd security hardening (NoNewPrivileges, ProtectSystem, ProtectHome)
439
+
440
+ Layer 7: TLS Everywhere
441
+ └─ IP access: self-signed cert (port 9292)
442
+ └─ Domain access: Let's Encrypt (port 443)
443
+ └─ Tunnel traffic: WebSocket over HTTPS
444
+ ```
445
+
446
+ ## Design Decisions
447
+
448
+ ### Why a $4 VPS as relay instead of a VPN or cloud deploy?
449
+
450
+ VPNs like Tailscale or Cloudflare Tunnel work well but lock you into a service provider. Cloud deployment means maintaining infrastructure and paying for compute. Lamaste uses the cheapest possible VPS purely as a relay — your actual compute stays on hardware you own and control.
451
+
452
+ ### Why nginx instead of Caddy or Traefik?
453
+
454
+ nginx has the smallest memory footprint of production-grade reverse proxies (~15 MB). On a 512 MB budget, every megabyte matters. nginx also has the most mature mTLS support and the widest documentation base. The tradeoff is more configuration complexity, which is managed programmatically through the Panel Server's `nginx.js` library.
455
+
456
+ ### Why Chisel instead of SSH tunneling or WireGuard?
457
+
458
+ Chisel tunnels over WebSocket-over-HTTPS, which passes through virtually any firewall or DPI system. SSH tunnels are often blocked by corporate firewalls, and WireGuard requires a separate UDP port. Chisel also has built-in auto-reconnect and runs as a single Go binary with ~20 MB RAM usage.
459
+
460
+ ### Why Authelia instead of a simpler auth solution?
461
+
462
+ Authelia provides TOTP 2FA as a single binary with ~25 MB RAM usage and file-based user storage. Alternatives like Keycloak (~500 MB RAM) or Auth0 (SaaS dependency) do not fit the constraints. Authelia integrates with nginx via the standard `auth_request` module.
463
+
464
+ ### Why mTLS instead of passwords for the admin panel?
465
+
466
+ mTLS provides zero-login authentication — the browser presents the certificate automatically at the TLS level, before any HTTP request is processed. This eliminates credential stuffing, phishing, and session hijacking for admin access. The tradeoff is a one-time certificate import process during setup.
467
+
468
+ ### Why JSON files instead of a database?
469
+
470
+ At this scale (single admin, handful of tunnels), a database adds RAM overhead and operational complexity for no benefit. JSON files with atomic writes (write temp, fsync, rename) provide crash-safe persistence. The entire state fits in a few kilobytes. Authelia's user database is YAML-based for the same reason.
471
+
472
+ ### Why IP:9292 always works?
473
+
474
+ The IP-based panel access on port 9292 is the ultimate fallback. If your domain expires, DNS breaks, or Let's Encrypt fails to renew, you can always reach the panel via `https://<ip>:9292` to fix things. This is a core safety invariant of the system.
475
+
476
+ ### Why systemd for all services?
477
+
478
+ systemd provides automatic restart on failure, structured logging via journal, dependency ordering, and resource isolation (cgroups). All Lamaste services (`lamalibre-lamaste-serverd`, `chisel`, `authelia`) are managed through systemd, giving a consistent interface for the Panel Server to start, stop, restart, and query status. The `services.js` library wraps `systemctl` commands with an allowlist to prevent arbitrary service manipulation.
479
+
480
+ ### Why sudoers instead of running as root?
481
+
482
+ The Panel Server runs as the `lamaste` user with minimal privileges and cannot become root. The files it manages (state, PKI, web root, Authelia configuration, Chisel authfile) belong to it or to a group it is in, so most work needs no privileges at all. What does — service control, `nginx -t`, installing its nginx vhosts, storing an Authelia TOTP secret, certbot, starting a self-update — goes through fixed `sudoers` command lines and three root-owned programs that validate their arguments (`lamaste-priv`, `lamaste-certbot`, `lamaste-cert-info`). There is no wildcard rule and no blanket `lamaste ALL=(ALL) NOPASSWD: ALL`. Binaries, units and service accounts are installed by `create-lamaste` as root. This limits the blast radius of a compromised Panel Server process; see [Security Model](../01-concepts/security-model.md#privilege-boundary).
483
+
484
+ ## Lifecycle Summary
485
+
486
+ The full lifecycle of a Lamaste installation:
487
+
488
+ ```
489
+ Phase 1: Installation (npx @lamalibre/create-lamaste@4.0.0)
490
+ └─ OS hardening, Node.js, mTLS certs, nginx, panel deploy
491
+ └─ Result: Panel accessible at https://<ip>:9292
492
+
493
+ Phase 2: Onboarding (browser UI)
494
+ └─ Domain input → DNS verification → stack provisioning
495
+ └─ Provisions: Chisel, Authelia, Let's Encrypt, domain nginx vhosts
496
+ └─ Result: Panel accessible at https://panel.<domain>
497
+
498
+ Phase 3: Operation (browser UI)
499
+ └─ Create tunnels → apps accessible at https://<app>.<domain>
500
+ └─ Manage users → TOTP enrollment for app access
501
+ └─ Host static sites → served via nginx at https://<site>.<domain>
502
+ └─ Monitor services → dashboard, live logs
503
+ └─ Manage certificates → auto-renewal, mTLS rotation
504
+ └─ Install plugins → extend functionality via @lamalibre/ npm packages
505
+
506
+ Phase 4: Recovery (if needed)
507
+ └─ Domain lost? → https://<ip>:9292 always works
508
+ └─ Service down? → Panel shows status, restart from UI
509
+ └─ Cert expired? → Renew from certificates page
510
+ └─ Need to re-install? → Re-run installer, config preserved
511
+ ```
512
+
513
+ ## Key Files
514
+
515
+ | File | Role |
516
+ | ------------------------------------------------------- | ------------------------------------------------------- |
517
+ | `/etc/lamalibre/lamaste/panel.json` | Central configuration (IP, domain, onboarding state) |
518
+ | `/etc/lamalibre/lamaste/tunnels.json` | Tunnel definitions |
519
+ | `/etc/lamalibre/lamaste/sites.json` | Static site definitions |
520
+ | `/etc/lamalibre/lamaste/pki/` | mTLS certificates (CA, client, server, PKCS12) |
521
+ | `/opt/lamalibre/lamaste/lamaste-serverd/` | Deployed Panel Server code |
522
+ | `/opt/lamalibre/lamaste/lamaste-server-ui/dist/` | Built Panel Client SPA |
523
+ | `/var/www/lamaste/` | Static site file roots |
524
+ | `/etc/nginx/sites-available/lamaste-*` | nginx vhost configurations |
525
+ | `/etc/nginx/snippets/lamalibre-lamaste-mtls.conf` | Shared mTLS snippet |
526
+ | `/etc/authelia/configuration.yml` | Authelia main config |
527
+ | `/etc/authelia/users.yml` | Authelia user database |
528
+ | `/etc/systemd/system/lamalibre-lamaste-serverd.service` | Panel Server systemd unit |
529
+ | `/etc/systemd/system/chisel.service` | Chisel Server systemd unit |
530
+ | `/etc/systemd/system/authelia.service` | Authelia systemd unit |
531
+ | `/etc/lamalibre/lamaste/plugins.json` | Plugin registry (installed plugins and status) |
532
+ | `/etc/lamalibre/lamaste/plugins/` | Per-plugin data directories |
533
+ | `/etc/lamalibre/lamaste/groups.json` | Lamaste group definitions and membership |
534
+ | `/etc/lamalibre/lamaste/access-grants.json` | Generic access grants (principal → resource) |
535
+ | `/etc/lamalibre/lamaste/gatekeeper.json` | Gatekeeper settings (cache TTL, admin contact, logging) |
536
+ | `/etc/lamalibre/lamaste/push-install-config.json` | Push install configuration and policies |
537
+ | `/etc/lamalibre/lamaste/push-install-sessions.json` | Push install session audit log |
538
+ | `/etc/sudoers.d/lamaste` | Fixed sudo rules for lamaste user (no wildcards) |
539
+ | `/usr/local/sbin/lamaste-priv` | Root helper: panel vhosts, Authelia TOTP, self-update |
540
+ | `~/.lamalibre/lamaste/servers.json` | Desktop app server registry (multi-server support) |
541
+ | `~/.lamalibre/lamaste/services.json` | Desktop app service discovery registry |