@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,230 @@
|
|
|
1
|
+
# Creating Your First Tunnel
|
|
2
|
+
|
|
3
|
+
> Expose a local web app to the internet through Lamaste in under 5 minutes.
|
|
4
|
+
|
|
5
|
+
## In Plain English
|
|
6
|
+
|
|
7
|
+
A tunnel connects a web app running on your local machine (behind your home router or office firewall) to a public URL on your Lamaste server. Visitors go to `app.example.com`, and Lamaste forwards the request through a secure WebSocket tunnel to your machine, which serves the response. Your app never leaves your machine — only the traffic flows through the relay.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- A completed [Lamaste onboarding](onboarding.md) with your domain configured
|
|
12
|
+
- A **web app running locally** on your machine (macOS or Linux) on a port between 1024 and 65535
|
|
13
|
+
- That machine **enrolled as an agent** — with the [Desktop App](desktop-app-setup.md) or `lamaste-agent setup` (see [Agent Setup](agent-setup.md)). Every tunnel is carried by exactly one agent, so the agent must exist before its tunnel
|
|
14
|
+
|
|
15
|
+
For this guide, assume you have a web app running on `http://localhost:3000`.
|
|
16
|
+
|
|
17
|
+
## Step-by-Step
|
|
18
|
+
|
|
19
|
+
### 1. Open the Tunnels Page
|
|
20
|
+
|
|
21
|
+
Log in to the Lamaste admin panel at `https://panel.example.com` (or `https://<ip>:9292`).
|
|
22
|
+
|
|
23
|
+
Click **Tunnels** in the sidebar navigation.
|
|
24
|
+
|
|
25
|
+
You see an empty state: "No tunnels configured. Create your first tunnel to get started."
|
|
26
|
+
|
|
27
|
+
### 2. Click Add Tunnel
|
|
28
|
+
|
|
29
|
+
Click the **Add Tunnel** button in the top right corner.
|
|
30
|
+
|
|
31
|
+
A form appears with these fields:
|
|
32
|
+
|
|
33
|
+
| Field | Description | Example |
|
|
34
|
+
| ------------------------------ | ------------------------------------------------------------------ | --------------------- |
|
|
35
|
+
| **Subdomain** | The subdomain for your tunnel's public URL | `app` |
|
|
36
|
+
| **Port** | The port your app listens on, on the agent | `3000` |
|
|
37
|
+
| **Agent** | The enrolled agent that carries the tunnel (required) | `laptop` |
|
|
38
|
+
| **Largest request body (MiB)** | Biggest upload nginx accepts for this tunnel (1–10240, default 10) | `10` |
|
|
39
|
+
| **Description** | Optional note for your reference | `My React dev server` |
|
|
40
|
+
| **Access** | Restricted (default), All Authelia Users, or Public | Restricted |
|
|
41
|
+
|
|
42
|
+
### 3. Fill in the Form
|
|
43
|
+
|
|
44
|
+
Enter a subdomain name. This becomes the public URL: if your domain is `example.com` and you enter `app`, the tunnel URL is `app.example.com`.
|
|
45
|
+
|
|
46
|
+
Subdomain rules:
|
|
47
|
+
|
|
48
|
+
- Lowercase letters, numbers, and hyphens only
|
|
49
|
+
- Cannot start or end with a hyphen
|
|
50
|
+
- Maximum 63 characters
|
|
51
|
+
- Cannot use reserved names: `panel`, `auth`, `tunnel`, `www`, `mail`, `ftp`, `api`
|
|
52
|
+
- Cannot start with `agent-` (this prefix is reserved for agent panel tunnels)
|
|
53
|
+
|
|
54
|
+
Enter the port number. This is the port your web app listens on, on `127.0.0.1` of the agent machine. Must be between 1024 and 65535, and unique across all tunnels (Chisel binds the same port on the server). Ports 3100, 9090, 9091, 9292 and 9294 are refused: they belong to Lamaste's own services on the server, and a tunnel on one of them would publish that service.
|
|
55
|
+
|
|
56
|
+
Pick the **Agent** that runs the app. Only that agent is told about the tunnel, and only that agent's Chisel credential may open its port on the server — another agent cannot take over the hostname.
|
|
57
|
+
|
|
58
|
+
Leave **Largest request body** at 10 MiB unless the app takes larger uploads; requests above the limit get HTTP 413. Optionally add a description to help you remember what this tunnel is for.
|
|
59
|
+
|
|
60
|
+
### 4. Create the Tunnel
|
|
61
|
+
|
|
62
|
+
Click **Add Tunnel**.
|
|
63
|
+
|
|
64
|
+
The panel performs four operations in sequence:
|
|
65
|
+
|
|
66
|
+
1. **Issues a TLS certificate** — Runs certbot to get a Let's Encrypt certificate for `app.example.com`. This takes a few seconds.
|
|
67
|
+
2. **Writes an nginx vhost** — Creates a reverse proxy configuration that forwards `app.example.com` traffic through Gatekeeper/Authelia (unless the tunnel is public) to `127.0.0.1:3000`, with the tunnel's `client_max_body_size`.
|
|
68
|
+
3. **Saves the tunnel** — Writes the tunnel record, including its `agentLabel`, to `/etc/lamalibre/lamaste/tunnels.json`.
|
|
69
|
+
4. **Syncs Chisel** — Re-renders the Chisel authfile from the saved state so the carrying agent — and only that agent — may bind the port. Chisel picks up the added grant without a restart, so other tunnels are not interrupted.
|
|
70
|
+
|
|
71
|
+
When all four steps succeed, the new tunnel appears in the list with its subdomain, FQDN, port, agent, access mode, and body limit.
|
|
72
|
+
|
|
73
|
+
**If something goes wrong:** The panel rolls back completed steps. If nginx configuration fails, the certificate is left in place (harmless). If saving the state or the Chisel sync fails, the tunnel is removed from the state and the nginx vhost is removed. You see an error message describing what went wrong.
|
|
74
|
+
|
|
75
|
+
### 5. Wait for the Agent (about 30 seconds)
|
|
76
|
+
|
|
77
|
+
The server now accepts the port from the carrying agent. The agent picks the tunnel up by itself: its sync timer asks the panel for its tunnel configuration (`GET /api/tunnels/agent-config`) every 30 seconds, rewrites its Chisel service (launchd on macOS, a systemd user unit on Linux) when the set changed, and restarts it — or starts it, if this is the agent's first tunnel. To apply the change at once, run on the agent machine:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
lamaste-agent update
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The same happens for every later change — a deleted or disabled tunnel, or one moved to or from this agent. `lamaste-agent status` shows the last sync on its **Sync** line.
|
|
84
|
+
|
|
85
|
+
### 6. Verify the Tunnel
|
|
86
|
+
|
|
87
|
+
Once the agent has picked up the tunnel, test your tunnel:
|
|
88
|
+
|
|
89
|
+
1. Make sure your local app is running on the configured port (e.g., `http://localhost:3000`).
|
|
90
|
+
2. Open `https://app.example.com` in a new browser window (or incognito).
|
|
91
|
+
3. Authelia redirects you to the login page at `auth.example.com`.
|
|
92
|
+
4. Enter your Authelia username and password.
|
|
93
|
+
5. Enter your TOTP code from your authenticator app.
|
|
94
|
+
6. After authentication, you see your local app.
|
|
95
|
+
|
|
96
|
+
**Expected behavior:** The first visit takes a moment because Authelia intercepts the request for authentication. After logging in, subsequent requests flow through quickly. Authelia sets a session cookie, so you do not need to re-authenticate for each page load.
|
|
97
|
+
|
|
98
|
+
### 7. Share Access with Users
|
|
99
|
+
|
|
100
|
+
By default a tunnel is **Restricted**: a visitor needs an Authelia account and a grant for this tunnel. To let someone else access the tunnel:
|
|
101
|
+
|
|
102
|
+
1. Go to the **Users** page in the panel.
|
|
103
|
+
2. Create a new user with a username, display name, email, and password.
|
|
104
|
+
3. Grant the user (or a group they belong to) access to the tunnel — see [Authorization](../01-concepts/authorization.md). Tunnels set to **All Authelia Users** skip this step.
|
|
105
|
+
4. Share the credentials and the tunnel URL with the person.
|
|
106
|
+
5. On their first login, they set up TOTP with their own authenticator app.
|
|
107
|
+
|
|
108
|
+
See [Managing Users](managing-users.md) for the full guide.
|
|
109
|
+
|
|
110
|
+
## For Developers
|
|
111
|
+
|
|
112
|
+
### Tunnel Data Model
|
|
113
|
+
|
|
114
|
+
Each tunnel is stored as a JSON object in `/etc/lamalibre/lamaste/tunnels.json`:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
119
|
+
"subdomain": "app",
|
|
120
|
+
"fqdn": "app.example.com",
|
|
121
|
+
"port": 3000,
|
|
122
|
+
"description": "My React dev server",
|
|
123
|
+
"type": "app",
|
|
124
|
+
"accessMode": "restricted",
|
|
125
|
+
"agentLabel": "laptop",
|
|
126
|
+
"maxBodySizeMb": 10,
|
|
127
|
+
"enabled": true,
|
|
128
|
+
"createdAt": "2024-01-15T10:30:00.000Z"
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`agentLabel` is the carrying agent. `maxBodySizeMb` becomes the vhost's `client_max_body_size`; tunnels created before the setting existed have no value and keep nginx's built-in 1 MiB until a body limit is set on them.
|
|
133
|
+
|
|
134
|
+
### API Endpoints
|
|
135
|
+
|
|
136
|
+
| Method | Path | Purpose |
|
|
137
|
+
| -------- | --------------------------- | ---------------------------------------------------------------------- |
|
|
138
|
+
| `GET` | `/api/tunnels` | List tunnels, newest first (an agent sees only its own) |
|
|
139
|
+
| `POST` | `/api/tunnels` | Create a tunnel (certbot + nginx + state + chisel) |
|
|
140
|
+
| `PATCH` | `/api/tunnels/:id` | Enable/disable, move to another agent, change access mode or body size |
|
|
141
|
+
| `DELETE` | `/api/tunnels/:id` | Remove a tunnel (nginx + state + chisel) |
|
|
142
|
+
| `GET` | `/api/tunnels/agent-config` | One agent's Chisel client configuration (used by `lamaste-agent`) |
|
|
143
|
+
|
|
144
|
+
See the [Tunnels API](../04-api-reference/tunnels.md) for the full reference.
|
|
145
|
+
|
|
146
|
+
### Create Tunnel Request
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
POST /api/tunnels
|
|
150
|
+
{
|
|
151
|
+
"subdomain": "app",
|
|
152
|
+
"port": 3000,
|
|
153
|
+
"agentLabel": "laptop",
|
|
154
|
+
"description": "My React dev server"
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Validation rules (Zod schema):
|
|
159
|
+
|
|
160
|
+
- `subdomain`: lowercase alphanumeric with hyphens, max 63 chars, not reserved, not already served by a static site or site alias
|
|
161
|
+
- `port`: integer between 1024 and 65535, unique across tunnels
|
|
162
|
+
- `agentLabel`: an enrolled, non-revoked agent — required for admin certificates; an agent certificate defaults to itself and may not name another agent
|
|
163
|
+
- `accessMode`: `restricted` (default), `authenticated`, or `public` — the last two admin-only
|
|
164
|
+
- `maxBodySizeMb`: optional integer 1–10240, default 10
|
|
165
|
+
- `description`: optional, max 200 characters
|
|
166
|
+
|
|
167
|
+
### nginx Vhost Structure
|
|
168
|
+
|
|
169
|
+
Each tunnel gets a vhost that:
|
|
170
|
+
|
|
171
|
+
1. Terminates TLS with a Let's Encrypt certificate
|
|
172
|
+
2. Sends an auth subrequest to Authelia (`auth_request /authelia`)
|
|
173
|
+
3. Proxies authenticated traffic to `127.0.0.1:<tunnel-port>`
|
|
174
|
+
|
|
175
|
+
The Chisel server on the VPS accepts a reverse tunnel for the port only from the carrying agent — its authfile grants each `agent-<label>` user exactly `^R:127\.0\.0\.1:<port>$` for the enabled tunnels it owns — and forwards traffic to that agent.
|
|
176
|
+
|
|
177
|
+
### Traffic Flow
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
Browser → app.example.com:443
|
|
181
|
+
→ nginx (TLS termination)
|
|
182
|
+
→ Authelia auth_request (checks session cookie / prompts login)
|
|
183
|
+
→ proxy_pass 127.0.0.1:3000
|
|
184
|
+
→ Chisel server (reverse tunnel)
|
|
185
|
+
→ Chisel client (on your machine)
|
|
186
|
+
→ localhost:3000 (your app)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Agent Service
|
|
190
|
+
|
|
191
|
+
`lamaste-agent setup`, `update` and the 30-second sync timer render the Chisel client service from the `chiselArgs` returned by `GET /api/tunnels/agent-config` (implementation: `packages/core/lib/src/agent/converge.ts` and `chisel-service.ts`, shared by the CLI and `lamaste-agentd`). The service:
|
|
192
|
+
|
|
193
|
+
- Runs `chisel client --max-retry-interval 30s https://tunnel.example.com:443` and verifies the server's Let's Encrypt certificate — no `--tls-skip-verify`. The server URL must be `tunnel.<the domain the agent enrolled with>`
|
|
194
|
+
- Is stopped while the agent carries no tunnels (Chisel cannot run without a remote), and while the operator has stopped it
|
|
195
|
+
- Adds a `R:127.0.0.1:<port>:127.0.0.1:<port>` argument for each tunnel the agent carries
|
|
196
|
+
- Reads its credential from the environment (`AUTH=`), never from argv: the 0600 `chisel.env` on Linux, the 0600 plist's `EnvironmentVariables` on macOS
|
|
197
|
+
- Restarts automatically (`KeepAlive` on macOS, `Restart=always` on Linux)
|
|
198
|
+
|
|
199
|
+
### Deletion Rollback
|
|
200
|
+
|
|
201
|
+
When deleting a tunnel, the panel removes components in order:
|
|
202
|
+
|
|
203
|
+
1. Remove the nginx vhost and reload
|
|
204
|
+
2. Remove the tunnel from `tunnels.json`
|
|
205
|
+
3. Sync Chisel — the authfile is re-rendered without the owner's grant for the port, and Chisel restarts so live sessions drop it. The owner's sync timer stops asking for the port within about 30 seconds (until then Chisel refuses the owner's session, so its other tunnels are briefly down too)
|
|
206
|
+
|
|
207
|
+
The TLS certificate is left in place (certbot manages its lifecycle).
|
|
208
|
+
|
|
209
|
+
## Quick Reference
|
|
210
|
+
|
|
211
|
+
| Action | How |
|
|
212
|
+
| ---------------------- | ----------------------------------------------------------- |
|
|
213
|
+
| **Create tunnel** | Tunnels page, "Add Tunnel" button |
|
|
214
|
+
| **Delete tunnel** | Click delete icon on the tunnel row |
|
|
215
|
+
| **Move / reconfigure** | "Edit" on the tunnel row (agent, access mode, body limit) |
|
|
216
|
+
| **Enable / disable** | Toggle on the tunnel row |
|
|
217
|
+
| **View tunnel URL** | Click the domain link on the tunnel row |
|
|
218
|
+
| **Update client** | Automatic within ~30 s; `lamaste-agent update` to apply now |
|
|
219
|
+
|
|
220
|
+
| Constraint | Value |
|
|
221
|
+
| -------------------- | ----------------------------------------------- |
|
|
222
|
+
| Subdomain format | `^[a-z0-9]([a-z0-9-]*[a-z0-9])?$` |
|
|
223
|
+
| Port range | 1024-65535, except 3100, 9090, 9091, 9292, 9294 |
|
|
224
|
+
| Max subdomain length | 63 characters |
|
|
225
|
+
| Reserved subdomains | panel, auth, tunnel, www, mail, ftp, api |
|
|
226
|
+
| Reserved prefix | `agent-` (used by agent panel tunnels) |
|
|
227
|
+
| Unique port | Yes (one tunnel per port) |
|
|
228
|
+
| Unique subdomain | Yes (one tunnel per subdomain) |
|
|
229
|
+
| Carrying agent | Exactly one (`agentLabel`) |
|
|
230
|
+
| Request body limit | 1-10240 MiB (agents: up to 100), default 10 |
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# Installation
|
|
2
|
+
|
|
3
|
+
> Complete guide to provisioning a Lamaste server from a fresh DigitalOcean droplet in under 10 minutes.
|
|
4
|
+
|
|
5
|
+
## In Plain English
|
|
6
|
+
|
|
7
|
+
This guide walks you through creating a cheap cloud server and running a single command that turns it into a secure relay for your local web apps. By the end, you have a browser-accessible admin panel protected by a client certificate — no SSH required after setup.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
Before you begin, make sure you have:
|
|
12
|
+
|
|
13
|
+
- A **DigitalOcean account** (or any VPS provider offering Ubuntu 24.04)
|
|
14
|
+
- A **local terminal** with SSH and SCP available (macOS Terminal, Linux shell, or Windows PowerShell)
|
|
15
|
+
- A **modern browser** (Chrome, Firefox, Safari, or Edge) for importing the client certificate
|
|
16
|
+
- Approximately **10 minutes** of uninterrupted time
|
|
17
|
+
|
|
18
|
+
## Step-by-Step
|
|
19
|
+
|
|
20
|
+
### 1. Create a DigitalOcean Droplet
|
|
21
|
+
|
|
22
|
+
1. Log in to [DigitalOcean](https://cloud.digitalocean.com/).
|
|
23
|
+
2. Click **Create** and select **Droplets**.
|
|
24
|
+
3. Choose these settings:
|
|
25
|
+
|
|
26
|
+
| Setting | Value |
|
|
27
|
+
| ------------------ | ----------------------------------------------------- |
|
|
28
|
+
| **Region** | Choose the closest to your users |
|
|
29
|
+
| **Image** | Ubuntu 24.04 (LTS) x64 |
|
|
30
|
+
| **Size** | Basic, Regular, $4/mo (512 MB RAM, 1 vCPU, 10 GB SSD) |
|
|
31
|
+
| **Authentication** | SSH keys (recommended) or password |
|
|
32
|
+
| **Hostname** | Something memorable, e.g. `lamaste-relay` |
|
|
33
|
+
|
|
34
|
+
4. Click **Create Droplet**.
|
|
35
|
+
5. Wait for the droplet to boot. Copy its **public IP address** from the dashboard.
|
|
36
|
+
|
|
37
|
+
The $4/month droplet is sufficient. Lamaste is designed for a 512 MB RAM budget — all services together use approximately 245 MB, with a 1 GB swap file as a safety net.
|
|
38
|
+
|
|
39
|
+
### 2. SSH into the Droplet
|
|
40
|
+
|
|
41
|
+
Open your terminal and connect:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
ssh root@203.0.113.42
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Replace `203.0.113.42` with your droplet's actual IP address.
|
|
48
|
+
|
|
49
|
+
If you used an SSH key during droplet creation, you connect immediately. If you chose a password, enter it when prompted.
|
|
50
|
+
|
|
51
|
+
**Expected output:**
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.x.x-xxx-generic x86_64)
|
|
55
|
+
...
|
|
56
|
+
root@lamaste-relay:~#
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. Run the Installer
|
|
60
|
+
|
|
61
|
+
Execute the Lamaste installer:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
apt install -y npm
|
|
65
|
+
npx @lamalibre/create-lamaste@4.0.0
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The installer displays a confirmation banner before making any changes:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
72
|
+
│ Lamaste Installer │
|
|
73
|
+
├─────────────────────────────────────────────────────────────┤
|
|
74
|
+
│ │
|
|
75
|
+
│ This will install Lamaste on this machine. │
|
|
76
|
+
│ │
|
|
77
|
+
│ The following changes will be made: │
|
|
78
|
+
│ │
|
|
79
|
+
│ * Reset UFW firewall (allow ports 22, 80, 443, 9292) │
|
|
80
|
+
│ * Harden SSH (disable password authentication) │
|
|
81
|
+
│ * Install fail2ban, Node.js 20, nginx, certbot │
|
|
82
|
+
│ * Generate mTLS certificates for browser access │
|
|
83
|
+
│ * Create lamaste user and systemd service │
|
|
84
|
+
│ * Deploy panel to /opt/lamalibre/lamaste/ │
|
|
85
|
+
│ │
|
|
86
|
+
│ Designed for a fresh Ubuntu 24.04 droplet. │
|
|
87
|
+
│ │
|
|
88
|
+
└─────────────────────────────────────────────────────────────┘
|
|
89
|
+
|
|
90
|
+
Press Enter to continue or Ctrl+C to abort...
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Press **Enter** to proceed. To skip the confirmation prompt, use `npx @lamalibre/create-lamaste@4.0.0 --yes`.
|
|
94
|
+
|
|
95
|
+
### 4. What the Installer Does
|
|
96
|
+
|
|
97
|
+
The installer runs seven sequential phases. Each phase displays real-time progress:
|
|
98
|
+
|
|
99
|
+
**Phase 1 — Environment checks**
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
✔ Checking environment
|
|
103
|
+
✔ Verifying root access
|
|
104
|
+
✔ Detecting operating system → Ubuntu 24.04 LTS
|
|
105
|
+
✔ Detecting IP address → 203.0.113.42
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The installer verifies you are running as root on Ubuntu 24.04 and detects the droplet's public IP address.
|
|
109
|
+
|
|
110
|
+
**Phase 2 — OS hardening**
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
✔ Hardening operating system
|
|
114
|
+
✔ Creating swap file → Swap file created and activated
|
|
115
|
+
✔ Configuring UFW firewall → UFW enabled with ports 22, 80, 443, 9292 allowed
|
|
116
|
+
✔ Installing and configuring fail2ban → fail2ban status: active
|
|
117
|
+
✔ Hardening SSH configuration → SSH hardened: key-auth only, root with keys only
|
|
118
|
+
✔ Installing system dependencies → System dependencies installed, nginx stopped
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This phase creates a 1 GB swap file, configures the UFW firewall to allow only ports 22 (SSH), 80 (HTTP for Let's Encrypt), 443 (HTTPS), and 9292 (panel), installs fail2ban with SSH and nginx jails, hardens SSH to disable password authentication, and installs nginx, certbot, curl, and openssl.
|
|
122
|
+
|
|
123
|
+
**Phase 3 — Node.js**
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
✔ Installing Node.js 20
|
|
127
|
+
✔ Checking existing Node.js installation → Node.js not found, installing v20 LTS
|
|
128
|
+
✔ Installing NodeSource repository → NodeSource repository added
|
|
129
|
+
✔ Installing Node.js 20 LTS → Node.js installed
|
|
130
|
+
✔ Verifying Node.js installation → Node.js v20.x.x, npm 10.x.x
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If Node.js 20 or later is already installed, this phase is skipped.
|
|
134
|
+
|
|
135
|
+
**Phase 4 — mTLS certificates**
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
✔ Generating mTLS certificates
|
|
139
|
+
✔ Creating PKI directory → PKI directory: /etc/lamalibre/lamaste/pki
|
|
140
|
+
✔ Generating CA private key and certificate → CA key and certificate generated
|
|
141
|
+
✔ Generating client key and CSR → Client key and CSR generated
|
|
142
|
+
✔ Signing client certificate with CA → Client certificate signed and CSR removed
|
|
143
|
+
✔ Creating PKCS12 bundle → PKCS12 bundle created
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This phase creates a private certificate authority (CA), signs a client certificate, and bundles it into a `.p12` file for browser import. The CA certificate has a 10-year validity; the client certificate has a 2-year validity.
|
|
147
|
+
|
|
148
|
+
**Phase 5 — nginx**
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
✔ Configuring nginx
|
|
152
|
+
✔ Generating self-signed TLS certificate for IP access → Self-signed TLS certificate generated
|
|
153
|
+
✔ Writing mTLS snippet → mTLS snippet written
|
|
154
|
+
✔ Writing IP-based panel vhost → Vhost written
|
|
155
|
+
✔ Deploying certificate help page → Certificate help page deployed
|
|
156
|
+
✔ Enabling site and cleaning up defaults → Site enabled, default removed
|
|
157
|
+
✔ Redirecting plain HTTP to HTTPS → Port 80 answers every host with a redirect to https://
|
|
158
|
+
✔ Validating and starting nginx → nginx is running and listening on port 9292
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
nginx is configured to listen on port 9292 with TLS and mTLS client certificate verification. A self-signed certificate is used for the IP-based connection (a proper Let's Encrypt certificate is issued later during onboarding when you configure a domain).
|
|
162
|
+
|
|
163
|
+
Port 80 gets a catch-all site, `lamalibre-lamaste-http-redirect` (`listen 80 default_server`), that answers every plain-HTTP request with a `301` to `https://$host$request_uri`. It does not get in the way of Let's Encrypt: during an HTTP-01 challenge certbot's nginx plugin clones this default server for the name being validated, answers the challenge, and restores the file afterwards — for new certificates and renewals alike. If another site on the machine already owns port 80's default server, the step is skipped and the relay works without the redirect.
|
|
164
|
+
|
|
165
|
+
**Phase 6 — Panel deployment**
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
✔ Deploying Lamaste panel
|
|
169
|
+
✔ Creating system user → Created system user: lamaste
|
|
170
|
+
✔ Creating directory structure → Directories created: /opt/lamalibre/lamaste, /etc/lamalibre/lamaste
|
|
171
|
+
✔ Installing chisel and Authelia → chisel and Authelia installed (started during onboarding)
|
|
172
|
+
✔ Deploying serverd → Panel server deployed
|
|
173
|
+
✔ Deploying lamaste-server CLI → lamaste-server CLI deployed; lamaste-reset-admin shim installed
|
|
174
|
+
✔ Deploying server-ui → Panel client deployed from pre-built dist
|
|
175
|
+
✔ Deploying documentation → Documentation deployed
|
|
176
|
+
✔ Writing panel configuration → Configuration written to /etc/lamalibre/lamaste/panel.json
|
|
177
|
+
✔ Writing systemd service unit → Systemd service unit written
|
|
178
|
+
✔ Installing sudoers wrapper scripts → Sudoers wrappers installed
|
|
179
|
+
✔ Writing sudoers rules → Sudoers rules written and validated
|
|
180
|
+
✔ Starting panel service → Panel service running. Health: {"status":"ok"}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The panel server runs as the unprivileged `lamaste` system user. Its code in `/opt/lamalibre/lamaste/` is root-owned and read-only for it. The installer — not onboarding — installs the pinned Chisel (1.12.0) and Authelia (4.39.28) releases, verified against pinned SHA-256 digests, with their systemd units; it creates the `lamaste-chisel` group (Chisel runs as it; the panel is a member so it can hand Chisel its authfile without sudo) and the `lamaste-authelia` account Authelia runs as. `/etc/sudoers.d/lamaste` has no wildcards: fixed `systemctl` command lines, `nginx -t`, and three root-owned programs in `/usr/local/sbin/` that validate every argument — `lamaste-priv` (the panel's nginx vhosts, checked against a directive allow-list; Authelia TOTP secrets; self-update), `lamaste-certbot` and `lamaste-cert-info`. The sudoers file is checked with `visudo -c` before it replaces the old one. See [Security Model](../01-concepts/security-model.md#privilege-boundary). Configuration lives in `/etc/lamalibre/lamaste/panel.json`.
|
|
184
|
+
|
|
185
|
+
**Phase 7 — Gatekeeper deployment** deploys the tunnel authorization service into `/opt/lamalibre/lamaste/gatekeeper` and starts it.
|
|
186
|
+
|
|
187
|
+
### 5. Read the Summary
|
|
188
|
+
|
|
189
|
+
After all phases complete, the installer prints a summary box:
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
╔════════════════════════════════════════════════════════════════╗
|
|
193
|
+
║ ║
|
|
194
|
+
║ Lamaste installed successfully! ║
|
|
195
|
+
║ ║
|
|
196
|
+
╠════════════════════════════════════════════════════════════════╣
|
|
197
|
+
║ ║
|
|
198
|
+
║ 1. Download your client certificate: ║
|
|
199
|
+
║ ║
|
|
200
|
+
║ scp root@203.0.113.42:/etc/lamalibre/lamaste/pki/client.p12 . ║
|
|
201
|
+
║ ║
|
|
202
|
+
║ 2. Import client.p12 into your browser: ║
|
|
203
|
+
║ ║
|
|
204
|
+
║ macOS: Double-click the file → Keychain Access ║
|
|
205
|
+
║ → select "System" keychain (not "login") ║
|
|
206
|
+
║ → enter the password below when prompted ║
|
|
207
|
+
║ → find cert in System keychain → double-click ║
|
|
208
|
+
║ → Trust → Always Trust ║
|
|
209
|
+
║ ║
|
|
210
|
+
║ Linux: Chrome → Settings → Privacy & Security ║
|
|
211
|
+
║ → Security → Manage certificates → Import ║
|
|
212
|
+
║ ║
|
|
213
|
+
║ Windows: Double-click the file → Certificate Import ║
|
|
214
|
+
║ Wizard → enter the password below ║
|
|
215
|
+
║ ║
|
|
216
|
+
║ 3. Certificate password: ║
|
|
217
|
+
║ ║
|
|
218
|
+
║ <random-password-here> ║
|
|
219
|
+
║ ║
|
|
220
|
+
║ 4. Open the Lamaste panel: ║
|
|
221
|
+
║ ║
|
|
222
|
+
║ https://203.0.113.42:9292 ║
|
|
223
|
+
║ ║
|
|
224
|
+
║ (Your browser will warn about the self-signed cert. ║
|
|
225
|
+
║ This is expected — click "Advanced" → "Proceed") ║
|
|
226
|
+
║ ║
|
|
227
|
+
║ You can now disconnect from SSH. ║
|
|
228
|
+
║ The panel is running and accessible from your browser. ║
|
|
229
|
+
║ ║
|
|
230
|
+
╚════════════════════════════════════════════════════════════════╝
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Save the certificate password.** You need it to import the `.p12` file into your browser.
|
|
234
|
+
|
|
235
|
+
### 6. Download the Client Certificate
|
|
236
|
+
|
|
237
|
+
Open a **new terminal window** on your local machine (not the SSH session) and run:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
scp root@203.0.113.42:/etc/lamalibre/lamaste/pki/client.p12 .
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
This copies the certificate bundle to your current directory.
|
|
244
|
+
|
|
245
|
+
### 7. Import the Certificate into Your Browser
|
|
246
|
+
|
|
247
|
+
The `.p12` file contains both your client certificate and private key, protected by the password shown in the summary.
|
|
248
|
+
|
|
249
|
+
**macOS (Chrome, Safari, Firefox):**
|
|
250
|
+
|
|
251
|
+
1. Double-click `client.p12`.
|
|
252
|
+
2. Keychain Access opens. Select the **System** keychain (not "login").
|
|
253
|
+
3. Enter the certificate password when prompted.
|
|
254
|
+
4. Find the imported certificate in the System keychain (look for "admin" under "My Certificates").
|
|
255
|
+
5. Double-click the certificate, expand **Trust**, and set "When using this certificate" to **Always Trust**.
|
|
256
|
+
6. Close the dialog and enter your macOS password to confirm.
|
|
257
|
+
|
|
258
|
+
If you see an error about "Local Items" — ignore it. The System keychain import is what matters.
|
|
259
|
+
|
|
260
|
+
**Linux (Chrome):**
|
|
261
|
+
|
|
262
|
+
1. Open Chrome and navigate to `chrome://settings/certificates`.
|
|
263
|
+
2. Click **Import** under "Your Certificates".
|
|
264
|
+
3. Select `client.p12` and enter the password.
|
|
265
|
+
|
|
266
|
+
**Windows (Chrome, Edge):**
|
|
267
|
+
|
|
268
|
+
1. Double-click `client.p12`.
|
|
269
|
+
2. The Certificate Import Wizard opens.
|
|
270
|
+
3. Choose "Current User" and click Next.
|
|
271
|
+
4. Enter the certificate password and click Next.
|
|
272
|
+
5. Let Windows automatically select the certificate store.
|
|
273
|
+
6. Click Finish.
|
|
274
|
+
|
|
275
|
+
### 8. Access the Panel
|
|
276
|
+
|
|
277
|
+
Open your browser and navigate to:
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
https://203.0.113.42:9292
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Your browser warns about the self-signed TLS certificate. This is expected — the IP-based connection uses a self-signed cert because Let's Encrypt cannot issue certificates for IP addresses.
|
|
284
|
+
|
|
285
|
+
- **Chrome:** Click "Advanced", then "Proceed to 203.0.113.42 (unsafe)".
|
|
286
|
+
- **Firefox:** Click "Advanced", then "Accept the Risk and Continue".
|
|
287
|
+
- **Safari:** Click "Show Details", then "visit this website".
|
|
288
|
+
|
|
289
|
+
Your browser then presents the client certificate. Select the "admin" certificate and click OK.
|
|
290
|
+
|
|
291
|
+
You see the Lamaste onboarding wizard. Proceed to the [Onboarding Guide](onboarding.md) for the next steps.
|
|
292
|
+
|
|
293
|
+
### 9. Disconnect SSH
|
|
294
|
+
|
|
295
|
+
You can now close your SSH session:
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
exit
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Everything from this point forward happens through the browser-based admin panel. SSH is never needed again for normal operation.
|
|
302
|
+
|
|
303
|
+
## For Developers
|
|
304
|
+
|
|
305
|
+
### Installer Internals
|
|
306
|
+
|
|
307
|
+
The installer (`packages/create-lamaste`) is built with Listr2 for progress display and execa for shell commands. It runs as a single orchestrated pipeline:
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
main() → envTasks → confirmInstallation() → installTasks → printSummary()
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Each task module exports a function that returns a Listr2 subtask list:
|
|
314
|
+
|
|
315
|
+
| Module | File | Purpose |
|
|
316
|
+
| ------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
317
|
+
| `hardenTasks` | `src/tasks/harden.js` | Swap, UFW, fail2ban, SSH, apt packages |
|
|
318
|
+
| `nodeTasks` | `src/tasks/node.js` | Node.js 20 LTS via NodeSource |
|
|
319
|
+
| `mtlsTasks` | `src/tasks/mtls.js` | CA, client cert, PKCS12 bundle |
|
|
320
|
+
| `nginxTasks` | `src/tasks/nginx.js` | Self-signed TLS, mTLS snippet, vhost |
|
|
321
|
+
| `panelTasks` | `src/tasks/panel.js` | System user, root-owned install dir, pinned chisel + Authelia, deploy, config, systemd, sudoers programs + rules |
|
|
322
|
+
|
|
323
|
+
### Idempotency
|
|
324
|
+
|
|
325
|
+
Every task includes skip guards. Running the installer a second time detects existing state and skips completed steps:
|
|
326
|
+
|
|
327
|
+
- Swap already active: skips creation
|
|
328
|
+
- Node.js 20+ installed: skips NodeSource setup
|
|
329
|
+
- mTLS CA and client.p12 exist: skips all certificate generation
|
|
330
|
+
- UFW active with correct rules: skips firewall configuration
|
|
331
|
+
- SSH already hardened: skips SSH changes
|
|
332
|
+
- Existing `panel.json`: merges rather than overwrites
|
|
333
|
+
|
|
334
|
+
### Directory Structure on the Server
|
|
335
|
+
|
|
336
|
+
After installation, the server has these Lamaste directories:
|
|
337
|
+
|
|
338
|
+
| Path | Owner | Purpose |
|
|
339
|
+
| ----------------------------------- | --------------------------------- | ----------------------------------------------- |
|
|
340
|
+
| `/etc/lamalibre/lamaste/` | `lamaste:lamaste` | Configuration and state files |
|
|
341
|
+
| `/etc/lamalibre/lamaste/pki/` | `lamaste:lamaste` (700) | CA, client cert, server cert, .p12 |
|
|
342
|
+
| `/etc/lamalibre/lamaste/panel.json` | `lamaste:lamaste` | Panel configuration |
|
|
343
|
+
| `/opt/lamalibre/lamaste/` | `root:root` | Panel server, CLI, UI, docs, gatekeeper (code) |
|
|
344
|
+
| `/var/www/lamaste/` | `lamaste:www-data` (2750, setgid) | Static site files (0640; nginx reads via group) |
|
|
345
|
+
| `/etc/authelia/` | `lamaste:lamaste-authelia` (2770) | Authelia configuration and database |
|
|
346
|
+
| `/var/log/authelia/` | `lamaste-authelia` (750) | Authelia log |
|
|
347
|
+
| `/usr/local/bin/chisel`, `authelia` | `root:root` | Pinned releases |
|
|
348
|
+
|
|
349
|
+
### CLI Flags
|
|
350
|
+
|
|
351
|
+
| Flag | Effect |
|
|
352
|
+
| --------------- | ------------------------------------------- |
|
|
353
|
+
| `--help`, `-h` | Print help and exit |
|
|
354
|
+
| `--yes`, `-y` | Skip confirmation prompt |
|
|
355
|
+
| `--skip-harden` | Skip swap, UFW, fail2ban, and SSH hardening |
|
|
356
|
+
| `--dev` | Allow private/non-routable IP addresses |
|
|
357
|
+
| `--uninstall` | Print manual removal guide and exit |
|
|
358
|
+
|
|
359
|
+
### Systemd Service
|
|
360
|
+
|
|
361
|
+
The panel runs as `lamalibre-lamaste-serverd.service`:
|
|
362
|
+
|
|
363
|
+
```ini
|
|
364
|
+
[Service]
|
|
365
|
+
User=lamaste
|
|
366
|
+
Group=lamaste
|
|
367
|
+
# Lets the panel hand the chisel authfile to the group chisel runs as.
|
|
368
|
+
SupplementaryGroups=lamaste-chisel
|
|
369
|
+
WorkingDirectory=/opt/lamalibre/lamaste/serverd
|
|
370
|
+
ExecStart=/usr/bin/node src/index.js
|
|
371
|
+
Environment=NODE_ENV=production
|
|
372
|
+
Environment=CONFIG_FILE=/etc/lamalibre/lamaste/panel.json
|
|
373
|
+
Restart=always
|
|
374
|
+
RestartSec=5
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
The service includes security hardening: `ProtectHome=true`, `PrivateTmp=true`, and `ReadWritePaths` for the config and static site directories. `NoNewPrivileges` is intentionally omitted because the panel runs the fixed `sudo` commands in `/etc/sudoers.d/lamaste` (service control, `nginx -t`, `lamaste-priv`, `lamaste-certbot`, `lamaste-cert-info`) — nothing else.
|
|
378
|
+
|
|
379
|
+
## Quick Reference
|
|
380
|
+
|
|
381
|
+
| Item | Value |
|
|
382
|
+
| ------------------------ | ------------------------------------------------------------ |
|
|
383
|
+
| **Install command** | `npx @lamalibre/create-lamaste@4.0.0` |
|
|
384
|
+
| **Minimum VPS** | Ubuntu 24.04, 512 MB RAM |
|
|
385
|
+
| **Required ports** | 22 (SSH), 80 (HTTP/Let's Encrypt), 443 (HTTPS), 9292 (panel) |
|
|
386
|
+
| **Certificate location** | `/etc/lamalibre/lamaste/pki/client.p12` |
|
|
387
|
+
| **Download command** | `scp root@<ip>:/etc/lamalibre/lamaste/pki/client.p12 .` |
|
|
388
|
+
| **Panel URL** | `https://<ip>:9292` |
|
|
389
|
+
| **Config file** | `/etc/lamalibre/lamaste/panel.json` |
|
|
390
|
+
| **Service name** | `lamalibre-lamaste-serverd` |
|
|
391
|
+
| **Service logs** | `journalctl -u lamalibre-lamaste-serverd -f` |
|
|
392
|
+
| **Re-run safe** | Yes (idempotent) |
|
|
393
|
+
| **Total install time** | ~5-10 minutes |
|