@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,540 @@
|
|
|
1
|
+
# nginx Reverse Proxy
|
|
2
|
+
|
|
3
|
+
> nginx is the only public-facing service in Lamaste — it terminates TLS, enforces mTLS for the admin panel, delegates authentication to Authelia for tunneled apps, and proxies all traffic to internal services.
|
|
4
|
+
|
|
5
|
+
## In Plain English
|
|
6
|
+
|
|
7
|
+
Every request that reaches your Lamaste server goes through nginx first. Think of nginx as a concierge at a hotel. Every guest must pass through the lobby. The concierge checks credentials, directs guests to the right room, and turns away anyone who does not belong.
|
|
8
|
+
|
|
9
|
+
When a visitor arrives, nginx handles several jobs:
|
|
10
|
+
|
|
11
|
+
1. **Encryption** — it decrypts the HTTPS connection (TLS termination), so internal services do not need to deal with TLS themselves
|
|
12
|
+
2. **Routing** — it looks at the domain name in the request (e.g., `panel.example.com` vs `myapp.example.com`) and sends the request to the right internal service
|
|
13
|
+
3. **Authentication** — for the admin panel, it checks for a client certificate; for tunneled apps, it asks Authelia if the visitor is logged in
|
|
14
|
+
4. **Protection** — it is the only service listening on public ports, so everything else is shielded from direct internet access
|
|
15
|
+
|
|
16
|
+
No other service in Lamaste listens on a public network interface. nginx is the single point of entry.
|
|
17
|
+
|
|
18
|
+
## For Users
|
|
19
|
+
|
|
20
|
+
### What nginx does for you
|
|
21
|
+
|
|
22
|
+
You do not interact with nginx directly. The management panel handles all nginx configuration changes behind the scenes:
|
|
23
|
+
|
|
24
|
+
- When you complete onboarding, nginx vhosts are created for `panel.example.com`, `auth.example.com`, and `tunnel.example.com`
|
|
25
|
+
- When you create a tunnel, an nginx vhost is created for `myapp.example.com`
|
|
26
|
+
- When TLS certificates are renewed, nginx reloads to pick up the new certificates
|
|
27
|
+
- When you delete a tunnel, the vhost is removed and nginx reloads
|
|
28
|
+
|
|
29
|
+
### Plain HTTP
|
|
30
|
+
|
|
31
|
+
Port 80 answers every hostname with a redirect to the same address over HTTPS, so an `http://` link to your panel, a tunnel or a site still works. Let's Encrypt validation, which also uses port 80, is not affected by the redirect.
|
|
32
|
+
|
|
33
|
+
### The IP fallback
|
|
34
|
+
|
|
35
|
+
The panel is always accessible at `https://<your-ip>:9292`, even if your domain's DNS is misconfigured or your Let's Encrypt certificates expire. This IP-based vhost uses a self-signed certificate (your browser shows a warning) and requires the [mTLS client certificate](mtls.md).
|
|
36
|
+
|
|
37
|
+
This is your emergency backdoor. If everything goes wrong with domains and certificates, you can always reach the admin panel through the IP address.
|
|
38
|
+
|
|
39
|
+
### Vhosts in Lamaste
|
|
40
|
+
|
|
41
|
+
Each service gets its own virtual host (vhost) — a configuration block that tells nginx how to handle requests for a specific domain:
|
|
42
|
+
|
|
43
|
+
| Domain | Internal service | Authentication | Port |
|
|
44
|
+
| -------------------- | --------------------------------- | --------------------------------------- | ---- |
|
|
45
|
+
| `http://<anything>` | None — `301` to `https://` | None | 80 |
|
|
46
|
+
| `https://<ip>:9292` | Panel server (`:3100`) | mTLS client certificate | 9292 |
|
|
47
|
+
| `panel.example.com` | Panel server (`:3100`) | mTLS client certificate | 443 |
|
|
48
|
+
| `auth.example.com` | Authelia (`:9091`) | None (it is the auth service) | 443 |
|
|
49
|
+
| `tunnel.example.com` | Chisel server (`:9090`) | None (Chisel handles its own auth) | 443 |
|
|
50
|
+
| `myapp.example.com` | Chisel → carrying agent (`:3000`) | Gatekeeper + Authelia (per access mode) | 443 |
|
|
51
|
+
| `blog.example.com` | Files on disk (static site) | Optional Authelia | 443 |
|
|
52
|
+
|
|
53
|
+
### When things go wrong
|
|
54
|
+
|
|
55
|
+
If nginx fails to start or reload, your services become unreachable because nginx is the only public-facing gateway. The panel server always validates the nginx configuration (`nginx -t`) before reloading. If validation fails, the change is rolled back and the current configuration stays in place.
|
|
56
|
+
|
|
57
|
+
## For Developers
|
|
58
|
+
|
|
59
|
+
### Vhost architecture
|
|
60
|
+
|
|
61
|
+
nginx vhost files live in the standard Debian layout:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
/etc/nginx/
|
|
65
|
+
├── nginx.conf # Main config (default)
|
|
66
|
+
├── snippets/
|
|
67
|
+
│ └── lamalibre-lamaste-mtls.conf # mTLS snippet (included by panel vhosts)
|
|
68
|
+
├── sites-available/
|
|
69
|
+
│ ├── lamalibre-lamaste-http-redirect # :80 catch-all → HTTPS (installer)
|
|
70
|
+
│ ├── lamalibre-lamaste-panel-ip # IP:9292 vhost (always present)
|
|
71
|
+
│ ├── lamalibre-lamaste-panel-domain # panel.example.com (after onboarding)
|
|
72
|
+
│ ├── lamalibre-lamaste-auth # auth.example.com (after onboarding)
|
|
73
|
+
│ ├── lamalibre-lamaste-tunnel # tunnel.example.com (after onboarding)
|
|
74
|
+
│ ├── lamalibre-lamaste-app-myapp # myapp.example.com (per tunnel)
|
|
75
|
+
│ └── lamalibre-lamaste-site-<uuid> # Static site vhosts
|
|
76
|
+
└── sites-enabled/
|
|
77
|
+
└── (symlinks to sites-available)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
All Lamaste vhost files are prefixed with `lamaste-` to distinguish them from any pre-existing nginx configurations.
|
|
81
|
+
|
|
82
|
+
### The IP-based panel vhost
|
|
83
|
+
|
|
84
|
+
This vhost is created during installation and is the only vhost that exists before onboarding:
|
|
85
|
+
|
|
86
|
+
```nginx
|
|
87
|
+
map $http_upgrade $connection_upgrade {
|
|
88
|
+
default upgrade;
|
|
89
|
+
'' close;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
server {
|
|
93
|
+
listen 9292 ssl;
|
|
94
|
+
server_name _;
|
|
95
|
+
|
|
96
|
+
ssl_certificate /etc/lamalibre/lamaste/pki/self-signed.pem;
|
|
97
|
+
ssl_certificate_key /etc/lamalibre/lamaste/pki/self-signed-key.pem;
|
|
98
|
+
|
|
99
|
+
# mTLS enforcement
|
|
100
|
+
include /etc/nginx/snippets/lamalibre-lamaste-mtls.conf;
|
|
101
|
+
|
|
102
|
+
# SSL settings
|
|
103
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
104
|
+
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
105
|
+
ssl_prefer_server_ciphers on;
|
|
106
|
+
|
|
107
|
+
# Help page for visitors without client cert
|
|
108
|
+
error_page 495 496 /cert-help.html;
|
|
109
|
+
location = /cert-help.html {
|
|
110
|
+
root /opt/lamalibre/lamaste/lamaste-server-ui;
|
|
111
|
+
internal;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Proxy to lamalibre-lamaste-serverd
|
|
115
|
+
location / {
|
|
116
|
+
proxy_pass http://127.0.0.1:3100;
|
|
117
|
+
|
|
118
|
+
# Client cert headers — set from nginx TLS variables, never passed through from client
|
|
119
|
+
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
|
|
120
|
+
proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
|
|
121
|
+
proxy_set_header X-SSL-Client-Serial $ssl_client_serial;
|
|
122
|
+
|
|
123
|
+
# Standard proxy headers
|
|
124
|
+
proxy_set_header Host $host;
|
|
125
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
126
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
127
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
# API paths with WebSocket upgrade support
|
|
131
|
+
location /api {
|
|
132
|
+
proxy_pass http://127.0.0.1:3100;
|
|
133
|
+
proxy_http_version 1.1;
|
|
134
|
+
|
|
135
|
+
# Client cert headers — set from nginx TLS variables, never passed through from client
|
|
136
|
+
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
|
|
137
|
+
proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
|
|
138
|
+
proxy_set_header X-SSL-Client-Serial $ssl_client_serial;
|
|
139
|
+
|
|
140
|
+
# Standard proxy headers
|
|
141
|
+
proxy_set_header Host $host;
|
|
142
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
143
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
144
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
145
|
+
|
|
146
|
+
# WebSocket: only upgrade when client requests it
|
|
147
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
148
|
+
proxy_set_header Connection $connection_upgrade;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Key details:
|
|
154
|
+
|
|
155
|
+
- **Port 9292** — non-standard port to avoid conflicting with domain-based vhosts on 443
|
|
156
|
+
- **`server_name _`** — matches any hostname (catch-all for IP access)
|
|
157
|
+
- **Self-signed cert** — browsers show a security warning, which is expected for IP access
|
|
158
|
+
- **mTLS snippet** — requires client certificate at the TLS level
|
|
159
|
+
- **Error pages 495/496** — nginx-specific error codes for missing (496) or failed (495) client certificates
|
|
160
|
+
|
|
161
|
+
### The mTLS snippet
|
|
162
|
+
|
|
163
|
+
The snippet at `/etc/nginx/snippets/lamalibre-lamaste-mtls.conf` contains two directives:
|
|
164
|
+
|
|
165
|
+
```nginx
|
|
166
|
+
ssl_client_certificate /etc/lamalibre/lamaste/pki/ca.crt;
|
|
167
|
+
ssl_verify_client on;
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
- **`ssl_client_certificate`** — points to the CA certificate that signed the admin's client certificate
|
|
171
|
+
- **`ssl_verify_client on`** — hard requirement; connections without a valid client certificate are rejected at the TLS layer
|
|
172
|
+
|
|
173
|
+
This snippet is included in both the IP-based vhost and the domain-based panel vhost. It is not included in app vhosts (those use Authelia instead).
|
|
174
|
+
|
|
175
|
+
### Domain-based panel vhost
|
|
176
|
+
|
|
177
|
+
Created during onboarding for `panel.example.com`:
|
|
178
|
+
|
|
179
|
+
```nginx
|
|
180
|
+
server {
|
|
181
|
+
listen 443 ssl;
|
|
182
|
+
server_name panel.example.com;
|
|
183
|
+
|
|
184
|
+
ssl_certificate /etc/letsencrypt/live/panel.example.com/fullchain.pem;
|
|
185
|
+
ssl_certificate_key /etc/letsencrypt/live/panel.example.com/privkey.pem;
|
|
186
|
+
|
|
187
|
+
# mTLS — same as IP-based access
|
|
188
|
+
include /etc/nginx/snippets/lamalibre-lamaste-mtls.conf;
|
|
189
|
+
|
|
190
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
191
|
+
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
192
|
+
ssl_prefer_server_ciphers on;
|
|
193
|
+
|
|
194
|
+
location / {
|
|
195
|
+
proxy_pass http://127.0.0.1:3100;
|
|
196
|
+
|
|
197
|
+
# Client cert headers — set from nginx TLS variables, never passed through from client
|
|
198
|
+
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
|
|
199
|
+
proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
|
|
200
|
+
proxy_set_header X-SSL-Client-Serial $ssl_client_serial;
|
|
201
|
+
|
|
202
|
+
# Standard proxy headers
|
|
203
|
+
proxy_set_header Host $host;
|
|
204
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
205
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
206
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
# API paths with WebSocket upgrade support
|
|
210
|
+
location /api {
|
|
211
|
+
proxy_pass http://127.0.0.1:3100;
|
|
212
|
+
proxy_http_version 1.1;
|
|
213
|
+
|
|
214
|
+
# Client cert headers — set from nginx TLS variables, never passed through from client
|
|
215
|
+
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
|
|
216
|
+
proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
|
|
217
|
+
proxy_set_header X-SSL-Client-Serial $ssl_client_serial;
|
|
218
|
+
|
|
219
|
+
# Standard proxy headers
|
|
220
|
+
proxy_set_header Host $host;
|
|
221
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
222
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
223
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
224
|
+
|
|
225
|
+
# WebSocket: only upgrade when client requests it
|
|
226
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
227
|
+
proxy_set_header Connection $connection_upgrade;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The difference from the IP vhost: port 443 instead of 9292, Let's Encrypt certificates instead of self-signed, and a specific `server_name` instead of catch-all. Requires the same `map $http_upgrade $connection_upgrade` block to be present.
|
|
233
|
+
|
|
234
|
+
### App tunnel vhost
|
|
235
|
+
|
|
236
|
+
Each tunneled app gets its own vhost. Which template is used depends on the tunnel's access mode: `public` proxies directly, while `authenticated` and `restricted` (the default) delegate each request to Gatekeeper, which validates the Authelia session and — for restricted tunnels — the user's grant:
|
|
237
|
+
|
|
238
|
+
```nginx
|
|
239
|
+
server {
|
|
240
|
+
listen 443 ssl;
|
|
241
|
+
server_name myapp.example.com;
|
|
242
|
+
|
|
243
|
+
ssl_certificate /etc/letsencrypt/live/myapp.example.com/fullchain.pem;
|
|
244
|
+
ssl_certificate_key /etc/letsencrypt/live/myapp.example.com/privkey.pem;
|
|
245
|
+
|
|
246
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
247
|
+
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
248
|
+
ssl_prefer_server_ciphers on;
|
|
249
|
+
|
|
250
|
+
client_max_body_size 10m;
|
|
251
|
+
|
|
252
|
+
# Gatekeeper authorization subrequest (handles Authelia validation + grant check)
|
|
253
|
+
location /internal/lamaste/authz {
|
|
254
|
+
internal;
|
|
255
|
+
|
|
256
|
+
proxy_pass http://127.0.0.1:9294/authz/check;
|
|
257
|
+
proxy_pass_request_body off;
|
|
258
|
+
# ... X-Original-URL, X-Original-Method, Cookie headers ...
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
location / {
|
|
262
|
+
# Identity headers come from Gatekeeper's answer, replacing any
|
|
263
|
+
# the client sent (a public tunnel sets them all to "")
|
|
264
|
+
auth_request /internal/lamaste/authz;
|
|
265
|
+
auth_request_set $user $upstream_http_remote_user;
|
|
266
|
+
proxy_set_header Remote-User $user;
|
|
267
|
+
# ... Remote-Groups, Remote-Name, Remote-Email ...
|
|
268
|
+
|
|
269
|
+
# Proxy headers are declared here, in the location: a location with
|
|
270
|
+
# any proxy_set_header of its own inherits none from the server block
|
|
271
|
+
proxy_set_header Host $host;
|
|
272
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
273
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
274
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
275
|
+
|
|
276
|
+
# Never pass client-supplied certificate headers to the app
|
|
277
|
+
proxy_set_header X-SSL-Client-Verify "";
|
|
278
|
+
proxy_set_header X-SSL-Client-DN "";
|
|
279
|
+
proxy_set_header X-SSL-Client-Serial "";
|
|
280
|
+
|
|
281
|
+
# WebSocket support
|
|
282
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
283
|
+
proxy_set_header Connection "upgrade";
|
|
284
|
+
|
|
285
|
+
proxy_pass http://127.0.0.1:PORT;
|
|
286
|
+
proxy_http_version 1.1;
|
|
287
|
+
|
|
288
|
+
proxy_read_timeout 86400s;
|
|
289
|
+
proxy_send_timeout 86400s;
|
|
290
|
+
|
|
291
|
+
# Not logged in -> Authelia portal
|
|
292
|
+
error_page 401 =302 https://auth.example.com/?rd=$scheme://$http_host$request_uri;
|
|
293
|
+
# Restricted only: no grant -> Gatekeeper's access-request page
|
|
294
|
+
error_page 403 = /internal/lamaste/authz;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
The `location /internal/lamaste/authz` block is marked `internal`, meaning it cannot be accessed directly by clients. It is only triggered by the `auth_request` directive in the main `location /` block.
|
|
300
|
+
|
|
301
|
+
The `127.0.0.1:PORT` target is also why a tunnel can never use the port of a Lamaste service (3100, 9090, 9091, 9292, 9294): that vhost would publish the internal service. For the panel it would be worse than a leak, because the panel trusts the `X-SSL-Client-*` headers nginx sets as proof of a client certificate — which is also why tunnel vhosts always clear them.
|
|
302
|
+
|
|
303
|
+
`client_max_body_size` comes from the tunnel's `maxBodySizeMb` (1–10240 MiB, default 10; an agent may set at most 100). Requests above it get HTTP 413. Tunnels created before the setting existed carry no directive and so nginx's built-in 1 MiB limit, until a body limit is set on them (`PATCH /api/tunnels/:id` with `maxBodySizeMb`, or **Edit** in the panel). `127.0.0.1:PORT` is the listener Chisel opens on the server for the tunnel's carrying agent — see [Tunneling](tunneling.md#ownership-and-grants).
|
|
304
|
+
|
|
305
|
+
### Tunnel (Chisel) vhost
|
|
306
|
+
|
|
307
|
+
The WebSocket tunnel endpoint at `tunnel.example.com`:
|
|
308
|
+
|
|
309
|
+
```nginx
|
|
310
|
+
server {
|
|
311
|
+
listen 443 ssl;
|
|
312
|
+
server_name tunnel.example.com;
|
|
313
|
+
|
|
314
|
+
ssl_certificate /etc/letsencrypt/live/tunnel.example.com/fullchain.pem;
|
|
315
|
+
ssl_certificate_key /etc/letsencrypt/live/tunnel.example.com/privkey.pem;
|
|
316
|
+
|
|
317
|
+
# ... standard SSL and proxy headers ...
|
|
318
|
+
|
|
319
|
+
location / {
|
|
320
|
+
proxy_pass http://127.0.0.1:9090;
|
|
321
|
+
proxy_http_version 1.1;
|
|
322
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
323
|
+
proxy_set_header Connection "upgrade";
|
|
324
|
+
|
|
325
|
+
# Long timeout for persistent WebSocket connections
|
|
326
|
+
proxy_read_timeout 86400s;
|
|
327
|
+
proxy_send_timeout 86400s;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
The 24-hour timeouts (`86400s`) are essential for the Chisel WebSocket connection, which stays open indefinitely. Without these timeouts, nginx would close idle connections after 60 seconds (the default).
|
|
333
|
+
|
|
334
|
+
### WebSocket upgrade headers
|
|
335
|
+
|
|
336
|
+
WebSocket connections start as HTTP and then "upgrade" to the WebSocket protocol. nginx needs explicit configuration to pass this upgrade through:
|
|
337
|
+
|
|
338
|
+
```nginx
|
|
339
|
+
proxy_http_version 1.1;
|
|
340
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
341
|
+
proxy_set_header Connection $connection_upgrade;
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
The `$connection_upgrade` variable comes from a `map` block defined at the top of the IP panel vhost:
|
|
345
|
+
|
|
346
|
+
```nginx
|
|
347
|
+
map $http_upgrade $connection_upgrade {
|
|
348
|
+
default upgrade;
|
|
349
|
+
'' close;
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
- **`proxy_http_version 1.1`** — WebSocket requires HTTP/1.1 (not 1.0)
|
|
354
|
+
- **`Upgrade`** — forwards the client's upgrade request to the backend
|
|
355
|
+
- **`Connection $connection_upgrade`** — set to `upgrade` when the client requests a WebSocket upgrade, or `close` for regular HTTP requests. This avoids keeping non-WebSocket connections open unnecessarily
|
|
356
|
+
|
|
357
|
+
These headers appear in three places: the panel vhost (for live log streaming), the tunnel vhost (for Chisel), and app vhosts (for apps that use WebSockets).
|
|
358
|
+
|
|
359
|
+
### Proxy headers
|
|
360
|
+
|
|
361
|
+
Every vhost sets standard proxy headers so backend services know about the original request. In tunnel vhosts they are declared inside each `location` — nginx inherits `proxy_set_header` from the server level only into locations that declare none of their own, and every tunnel location declares some — so apps behind a tunnel see the real `Host` and client address:
|
|
362
|
+
|
|
363
|
+
| Header | nginx variable | Purpose |
|
|
364
|
+
| ------------------- | ---------------------------- | --------------------------------- |
|
|
365
|
+
| `Host` | `$host` | Original hostname from the client |
|
|
366
|
+
| `X-Real-IP` | `$remote_addr` | Client's actual IP address |
|
|
367
|
+
| `X-Forwarded-For` | `$proxy_add_x_forwarded_for` | Chain of proxy IPs |
|
|
368
|
+
| `X-Forwarded-Proto` | `$scheme` | Original protocol (http or https) |
|
|
369
|
+
|
|
370
|
+
For mTLS vhosts, three additional headers are set (tunnel vhosts and the panel's public, certificate-less locations set them to empty instead, so a client cannot forge them):
|
|
371
|
+
|
|
372
|
+
| Header | nginx variable | Purpose |
|
|
373
|
+
| --------------------- | -------------------- | -------------------------------- |
|
|
374
|
+
| `X-SSL-Client-Verify` | `$ssl_client_verify` | `SUCCESS`, `FAILED`, or `NONE` |
|
|
375
|
+
| `X-SSL-Client-DN` | `$ssl_client_s_dn` | Client certificate subject DN |
|
|
376
|
+
| `X-SSL-Client-Serial` | `$ssl_client_serial` | Client certificate serial number |
|
|
377
|
+
|
|
378
|
+
### Safe write-with-rollback
|
|
379
|
+
|
|
380
|
+
All vhost writes follow a safe sequence to prevent nginx from entering a broken state:
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
1. Back up existing vhost (if any) → file.bak
|
|
384
|
+
2. Write new vhost to sites-available/
|
|
385
|
+
3. Create symlink in sites-enabled/
|
|
386
|
+
4. Run nginx -t (test configuration)
|
|
387
|
+
5a. If test passes → reload nginx, delete backup
|
|
388
|
+
5b. If test fails → restore backup, remove new file, throw error
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
This pattern is implemented once, as `safeWriteVhost()` in `packages/server/daemon/src/lib/nginx.js`, and shared by every vhost writer (tunnels, static sites, agent panels, the core onboarding vhosts). The panel runs unprivileged, so each file step is a call to the root-owned helper `lamaste-priv`, with the vhost text on stdin:
|
|
392
|
+
|
|
393
|
+
```javascript
|
|
394
|
+
async function safeWriteVhost(name, config, fqdn, { enabled = true } = {}) {
|
|
395
|
+
const existed = await siteExists(name);
|
|
396
|
+
const wasEnabled = await isSiteEnabled(name);
|
|
397
|
+
if (existed) await siteAction('backup', name); // sudo lamaste-priv nginx-site backup <name>
|
|
398
|
+
|
|
399
|
+
try {
|
|
400
|
+
await writeVhostFile(name, config); // nginx-site write <name> (validated, then written)
|
|
401
|
+
await (enabled ? enableSite(name) : disableSite(name));
|
|
402
|
+
const result = await testConfig(); // sudo nginx -t
|
|
403
|
+
if (!result.valid) {
|
|
404
|
+
// restore(): nginx-site restore (or remove), then the previous link state
|
|
405
|
+
throw new Error(`Nginx config test failed after writing vhost for ${fqdn}: ...`);
|
|
406
|
+
}
|
|
407
|
+
await reload(); // sudo systemctl reload nginx
|
|
408
|
+
if (existed) await siteAction('discard-backup', name);
|
|
409
|
+
} catch (err) {
|
|
410
|
+
// Any other error, including a vhost lamaste-priv refuses, is rolled back too
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
`lamaste-priv` accepts only the panel's own site names and only vhosts whose every directive is on its allow-list — nginx's master process runs as root and opens the files a configuration names, so a free-form vhost would be root access. See [nginx Configuration](../03-architecture/nginx-configuration.md#vhost-allow-list).
|
|
416
|
+
|
|
417
|
+
The `nginx -t` command parses the entire configuration and reports syntax errors without affecting the running server. Only after it passes does the code reload nginx.
|
|
418
|
+
|
|
419
|
+
### TLS configuration
|
|
420
|
+
|
|
421
|
+
All vhosts use the same TLS settings:
|
|
422
|
+
|
|
423
|
+
```nginx
|
|
424
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
425
|
+
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
426
|
+
ssl_prefer_server_ciphers on;
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
- **TLSv1.2 and TLSv1.3** — modern protocols only; TLSv1.0 and TLSv1.1 are disabled
|
|
430
|
+
- **`HIGH:!aNULL:!MD5`** — strong cipher suites only, no anonymous or MD5 ciphers
|
|
431
|
+
- **`ssl_prefer_server_ciphers on`** — server chooses the cipher, not the client
|
|
432
|
+
|
|
433
|
+
### Static site vhosts
|
|
434
|
+
|
|
435
|
+
Static sites served directly by nginx (without proxying to a backend) use a different template:
|
|
436
|
+
|
|
437
|
+
```nginx
|
|
438
|
+
server {
|
|
439
|
+
listen 443 ssl;
|
|
440
|
+
server_name blog.example.com;
|
|
441
|
+
|
|
442
|
+
# ... TLS configuration ...
|
|
443
|
+
|
|
444
|
+
root /var/www/lamaste/<site-id>/;
|
|
445
|
+
index index.html;
|
|
446
|
+
|
|
447
|
+
# Security headers
|
|
448
|
+
add_header X-Frame-Options SAMEORIGIN always;
|
|
449
|
+
add_header X-Content-Type-Options nosniff always;
|
|
450
|
+
|
|
451
|
+
location / {
|
|
452
|
+
try_files $uri $uri/ =404;
|
|
453
|
+
# Or for SPAs: try_files $uri $uri/ /index.html;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Static sites can optionally include Authelia forward-auth protection if the `autheliaProtected` flag is set.
|
|
459
|
+
|
|
460
|
+
A custom-domain site can also have **aliases** (for example `www.myblog.net`). They get a second server block on the same certificate that answers with `return 301 https://myblog.net$request_uri;`. A hostname is served by at most one vhost: a tunnel cannot take a name a site or alias already serves, and an alias cannot take a tunnel's or another site's name.
|
|
461
|
+
|
|
462
|
+
### Source files
|
|
463
|
+
|
|
464
|
+
| File | Purpose |
|
|
465
|
+
| --------------------------------------------- | --------------------------------------------------- |
|
|
466
|
+
| `packages/server/daemon/src/lib/nginx.js` | Vhost write, enable/disable, test, reload, rollback |
|
|
467
|
+
| `packages/create-lamaste/src/tasks/nginx.js` | IP-based vhost, mTLS snippet, self-signed cert |
|
|
468
|
+
| `packages/create-lamaste/src/tasks/harden.js` | nginx package installation |
|
|
469
|
+
|
|
470
|
+
## Quick Reference
|
|
471
|
+
|
|
472
|
+
### Vhost files
|
|
473
|
+
|
|
474
|
+
| File | Domain | Auth | Created |
|
|
475
|
+
| -------------------------------- | -------------------- | ----------------- | ------------ |
|
|
476
|
+
| `lamalibre-lamaste-panel-ip` | `_` (any) on `:9292` | mTLS | Installation |
|
|
477
|
+
| `lamalibre-lamaste-panel-domain` | `panel.example.com` | mTLS | Onboarding |
|
|
478
|
+
| `lamalibre-lamaste-auth` | `auth.example.com` | None | Onboarding |
|
|
479
|
+
| `lamalibre-lamaste-tunnel` | `tunnel.example.com` | None | Onboarding |
|
|
480
|
+
| `lamalibre-lamaste-app-<name>` | `<name>.example.com` | Authelia | Per tunnel |
|
|
481
|
+
| `lamalibre-lamaste-site-<uuid>` | Custom FQDN | Optional Authelia | Per site |
|
|
482
|
+
|
|
483
|
+
### Internal service ports
|
|
484
|
+
|
|
485
|
+
| Service | Bind address | Port |
|
|
486
|
+
| ------------- | ------------ | ---- |
|
|
487
|
+
| Panel server | `127.0.0.1` | 3100 |
|
|
488
|
+
| Authelia | `127.0.0.1` | 9091 |
|
|
489
|
+
| Chisel server | `127.0.0.1` | 9090 |
|
|
490
|
+
|
|
491
|
+
### Public ports
|
|
492
|
+
|
|
493
|
+
| Port | Protocol | Purpose |
|
|
494
|
+
| ---- | -------- | ----------------------------------------------- |
|
|
495
|
+
| 443 | HTTPS | Domain-based vhosts (panel, auth, tunnel, apps) |
|
|
496
|
+
| 9292 | HTTPS | IP-based panel access (always available) |
|
|
497
|
+
| 22 | SSH | SSH access (used only during installation) |
|
|
498
|
+
|
|
499
|
+
### nginx commands
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
# Test configuration (always run before reload)
|
|
503
|
+
sudo nginx -t
|
|
504
|
+
|
|
505
|
+
# Reload (apply config changes without restart)
|
|
506
|
+
sudo systemctl reload nginx
|
|
507
|
+
|
|
508
|
+
# Restart (full restart)
|
|
509
|
+
sudo systemctl restart nginx
|
|
510
|
+
|
|
511
|
+
# View status
|
|
512
|
+
systemctl status nginx
|
|
513
|
+
|
|
514
|
+
# View error logs
|
|
515
|
+
sudo tail -f /var/log/nginx/error.log
|
|
516
|
+
|
|
517
|
+
# List enabled Lamaste vhosts
|
|
518
|
+
ls /etc/nginx/sites-enabled/lamaste-*
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Key nginx directives
|
|
522
|
+
|
|
523
|
+
| Directive | Purpose |
|
|
524
|
+
| -------------------------------------- | ------------------------------------------ |
|
|
525
|
+
| `ssl_verify_client on` | Require client certificate (mTLS) |
|
|
526
|
+
| `auth_request /internal/lamaste/authz` | Delegate auth to Gatekeeper subrequest |
|
|
527
|
+
| `client_max_body_size` | Per-tunnel request body limit |
|
|
528
|
+
| `proxy_http_version 1.1` | Required for WebSocket upgrade |
|
|
529
|
+
| `proxy_read_timeout 86400s` | Keep WebSocket connections alive (24h) |
|
|
530
|
+
| `error_page 495 496` | Handle missing/invalid client cert |
|
|
531
|
+
| `error_page 401 =302` | Redirect unauthenticated users to Authelia |
|
|
532
|
+
| `internal` | Location accessible only via subrequests |
|
|
533
|
+
|
|
534
|
+
### Related documentation
|
|
535
|
+
|
|
536
|
+
- [mTLS](mtls.md) — client certificate authentication details
|
|
537
|
+
- [Authentication](authentication.md) — Authelia forward-auth integration
|
|
538
|
+
- [Tunneling](tunneling.md) — WebSocket tunnels proxied by nginx
|
|
539
|
+
- [Certificates](certificates.md) — TLS certificates used by nginx vhosts
|
|
540
|
+
- [Security Model](security-model.md) — nginx as the sole public-facing service
|