refactor: update frontend state handling and adjust related documentation
Kim committed
May 29, 2026 at 17:47 UTC
9bf89268ed24c9626f7b9024ecf176703dc0dfba
8 files changed
+16
-15
.dockerignore
-1
@@ -13,7 +13,6 @@ docs/
13
14
# Local relay/tunnel state
15
.portal-certs/
16
-.portal-frontend-state/
16
*identity.json
17
18
# IDE
.env.example
+1
@@ -58,6 +58,7 @@ TRUST_PROXY_HEADERS=false
58
TRUSTED_PROXY_CIDRS=
59
60
# Frontend-owned presentation state.
61
+# Bundled Compose stores the saved override under ./.portal-certs/frontend-state/state.json.
62
LANDING_PAGE_ENABLED=false
63
64
# Optional: auto-generated thumbnail screenshots for tunnel apps without a thumbnail.
.gitignore
-1
@@ -147,5 +147,4 @@ keyless_tls/
147
148
# Local relay/tunnel state
149
.portal-certs/
150
-.portal-frontend-state/
150
*identity.json
docker-compose.yml
+2
-2
@@ -19,12 +19,12 @@ services:
19
PORT: 8081
20
PORTAL_API_BASE_URL: https://portal:4017
21
LANDING_PAGE_ENABLED: ${LANDING_PAGE_ENABLED:-false}
22
- PORTAL_FRONTEND_STATE_PATH: /portal-frontend-state/state.json
22
+ PORTAL_FRONTEND_STATE_PATH: /frontend-state/state.json
23
# Leave empty to disable generated screenshots without removing the service.
24
HEADLESS_SHELL_URL: ${HEADLESS_SHELL_URL:-}
25
# HEADLESS_SHELL_URL: ${HEADLESS_SHELL_URL:-ws://headless-shell:9222}
26
volumes:
27
- - ./.portal-frontend-state:/portal-frontend-state
27
+ - ./.portal-certs/frontend-state:/frontend-state
28
restart: unless-stopped
29
30
portal-frontend:
docs/src/routes/configuration/+page.md
+1
-1
@@ -80,7 +80,7 @@ variables:
80
| `PORT` | `8081` | int | Frontend API HTTP listen port |
81
| `PORTAL_API_BASE_URL` | `https://portal:4017` | string | Relay API base URL used to compose frontend-owned state |
82
| `LANDING_PAGE_ENABLED` | `false` | bool | Default landing page flag when no frontend state has been saved yet |
83
-| `PORTAL_FRONTEND_STATE_PATH` | `""` | string | Optional JSON file path for persisted frontend-owned state |
83
+| `PORTAL_FRONTEND_STATE_PATH` | `""` | string | Optional JSON file path for persisted frontend-owned state; bundled Compose stores this under `./.portal-certs/frontend-state/state.json` |
84
| `HEADLESS_SHELL_URL` | `""` | string | Headless Chrome CDP WebSocket URL; leave empty to disable generated thumbnails |
85
86
### Cloudflare
docs/src/routes/deployment/+page.md
+2
-2
@@ -178,7 +178,7 @@ Leave `TRUSTED_PROXY_CIDRS` empty for the default private and loopback proxy ran
178
Create the state directories:
179
180
```bash
181
-mkdir -p ./.portal-certs ./.portal-frontend-state ./certs
181
+mkdir -p ./.portal-certs/frontend-state ./certs
182
sudo chown 65532:65532 ./.portal-certs
183
chmod 755 ./.portal-certs
184
```
@@ -350,7 +350,7 @@ It owns:
350
- `/policy/*` composition, while relay-enforced policy changes are still forwarded to `portal`.
351
- `/service/status`, derived from relay state for quick-start UI checks.
352
- `/thumbnail/<hostname>`, when optional screenshot generation is enabled.
353
-- The landing-page flag persisted at `PORTAL_FRONTEND_STATE_PATH`.
353
+- The landing-page flag persisted at `PORTAL_FRONTEND_STATE_PATH`; the bundled Compose files store it under `./.portal-certs/frontend-state/state.json`.
354
355
The Go relay remains the owner of authentication, policy enforcement, lease state, tunnel ingress, install scripts, discovery, and x402 facilitator paths.
356
docs/static/examples/nginx-proxy-multi-service/docker-compose.yaml
+5
-4
@@ -17,8 +17,9 @@
17
# - app_a_fullchain.pem, app_a_privkey.pem for app-a.example.com
18
# - app_b_fullchain.pem, app_b_privkey.pem for app-b.example.com
19
# Portal also needs API TLS material in ./.portal-certs unless ACME_DNS_PROVIDER is configured.
20
-# 3. Create the .portal-certs directory with correct ownership (UID 65532 = nonroot):
21
-# mkdir -p ./.portal-certs
20
+# 3. Create the .portal-certs directory with correct ownership (UID 65532 = nonroot).
21
+# Frontend presentation state is stored under ./.portal-certs/frontend-state:
22
+# mkdir -p ./.portal-certs/frontend-state
23
# sudo chown 65532:65532 ./.portal-certs
24
# chmod 755 ./.portal-certs
25
# 4. Start all services:
@@ -119,11 +120,11 @@ services:
120
PORT: 8081
121
PORTAL_API_BASE_URL: "https://portal:${API_PORT:-4017}"
122
LANDING_PAGE_ENABLED: ${LANDING_PAGE_ENABLED:-false}
122
- PORTAL_FRONTEND_STATE_PATH: /portal-frontend-state/state.json
123
+ PORTAL_FRONTEND_STATE_PATH: /frontend-state/state.json
124
HEADLESS_SHELL_URL: ${HEADLESS_SHELL_URL:-}
125
# HEADLESS_SHELL_URL: ${HEADLESS_SHELL_URL:-ws://headless-shell:9222}
126
volumes:
126
- - ./.portal-frontend-state:/portal-frontend-state
127
+ - ./.portal-certs/frontend-state:/frontend-state
128
restart: unless-stopped
129
130
app-a-api:
docs/static/examples/nginx-proxy/docker-compose.yaml
+5
-4
@@ -16,8 +16,9 @@
16
# 2. Place the root-domain TLS certificate files for nginx in ./certs/:
17
# ./certs/fullchain.pem
18
# ./certs/privkey.pem
19
-# 3. Create the .portal-certs directory with correct ownership (UID 65532 = nonroot):
20
-# mkdir -p ./.portal-certs
19
+# 3. Create the .portal-certs directory with correct ownership (UID 65532 = nonroot).
20
+# Frontend presentation state is stored under ./.portal-certs/frontend-state:
21
+# mkdir -p ./.portal-certs/frontend-state
22
# sudo chown 65532:65532 ./.portal-certs
23
# chmod 755 ./.portal-certs
24
# Portal also needs API TLS material in ./.portal-certs unless ACME_DNS_PROVIDER is configured.
@@ -115,9 +116,9 @@ services:
116
PORT: 8081
117
PORTAL_API_BASE_URL: "https://portal:${API_PORT:-4017}"
118
LANDING_PAGE_ENABLED: ${LANDING_PAGE_ENABLED:-false}
118
- PORTAL_FRONTEND_STATE_PATH: /portal-frontend-state/state.json
119
+ PORTAL_FRONTEND_STATE_PATH: /frontend-state/state.json
120
HEADLESS_SHELL_URL: ${HEADLESS_SHELL_URL:-}
121
# HEADLESS_SHELL_URL: ${HEADLESS_SHELL_URL:-ws://headless-shell:9222}
122
volumes:
122
- - ./.portal-frontend-state:/portal-frontend-state
123
+ - ./.portal-certs/frontend-state:/frontend-state
124
restart: unless-stopped