void 0.21.9 → 0.22.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/dist/{account-cmd-DZZGK80W.mjs → account-cmd-CjyxcGkM.mjs} +4 -4
- package/dist/{auth-link-B_CeugBw.mjs → auth-link-BLO4ptzo.mjs} +4 -4
- package/dist/{auth-router-BgEFRuvZ.mjs → auth-router-ZUg9MF_U.mjs} +5 -5
- package/dist/{build-cmd-Dpt0jd-x.mjs → build-cmd-BxR5FROK.mjs} +3 -3
- package/dist/{cache-7_UeZdTk.mjs → cache-D0sWhgKI.mjs} +3 -3
- package/dist/{cancel-deploy-D23R1RXT.mjs → cancel-deploy-D4NUqFbi.mjs} +3 -3
- package/dist/{cf-build-output-CGT03qCD.mjs → cf-build-output-BJ6yGEIS.mjs} +139 -62
- package/dist/cli/cf-compat.mjs +164 -50
- package/dist/cli/cli.mjs +73 -44
- package/dist/cli/env-schema-probe.d.mts +1 -1
- package/dist/{client-QTl6ko_D.mjs → client-BTZ3XkrB.mjs} +25 -0
- package/dist/client-Czz8o5jP.mjs +2 -0
- package/dist/{cloudflare-auth-C4_GPZr0.mjs → cloudflare-auth-DQkqoMYa.mjs} +1 -6
- package/dist/{cloudflare-cmd-bSmZ1d5L.mjs → cloudflare-cmd-BKlfGHAy.mjs} +6 -7
- package/dist/{cloudflare-connect-jAwacxxP.mjs → cloudflare-connect-Ctmrw579.mjs} +3 -3
- package/dist/{cloudflare-operations-sMZXpk_S.mjs → cloudflare-operations-B9tzgjmf.mjs} +10 -39
- package/dist/{cloudflare-operations-BipGMJ5O.mjs → cloudflare-operations-BT6OWFBk.mjs} +1 -1
- package/dist/{config-CafTW6Cz.mjs → config-Br_JZD6u.mjs} +2 -7
- package/dist/{config-s7Xj7tPb.mjs → config-CyQ-wVd7.mjs} +1 -1
- package/dist/{config-CF69HgXc.d.mts → config-VavjpDnp.d.mts} +1 -2
- package/dist/config-entry.d.mts +1 -1
- package/dist/{config-write-BSduPMY8.mjs → config-write-B1f88wJA.mjs} +1 -1
- package/dist/{connect-BsUSRzln.mjs → connect-Dg-WkW-C.mjs} +5 -5
- package/dist/{create-project-BniEV0OW.mjs → create-project-DdoqwFLF.mjs} +1 -1
- package/dist/{create-project-DBfFSZKY.mjs → create-project-l9J7pbtm.mjs} +8 -4
- package/dist/{db-hRrvZaq_.mjs → db-gp2sCXyN.mjs} +14 -14
- package/dist/{delete-D6dZ9B6B.mjs → delete-TTedbH6B.mjs} +3 -3
- package/dist/{deploy-DDz7c8LK.mjs → deploy-B19L2Bra.mjs} +1 -1
- package/dist/{deploy-WaAQez1O.mjs → deploy-CH-o2CaZ.mjs} +47 -36
- package/dist/{dist-BR1quN_w.mjs → dist-AoCzRTJE.mjs} +226 -60
- package/dist/{dist-C5fND3R0.mjs → dist-BuDuKZJv.mjs} +1 -1
- package/dist/{dist-Dn6nn2IU.mjs → dist-CTBk70IR.mjs} +42 -42
- package/dist/{domain-Dmhvb2oU.mjs → domain-JRF59P_r.mjs} +4 -4
- package/dist/{email-DFi-s2t4.mjs → email-Bo6G9LOZ.mjs} +6 -6
- package/dist/{env-Csi-tMbT.mjs → env-BYOrWQnv.mjs} +4 -4
- package/dist/{env-public-D_6u46fX.d.mts → env-public-BxU_0yTL.d.mts} +2 -1
- package/dist/gen-CNJ62MM7.mjs +2 -0
- package/dist/{gen-Dz3X1Qab.mjs → gen-sCtlCOdA.mjs} +3 -3
- package/dist/{github-cmd-BED3_9JD.mjs → github-cmd-0-7PexDq.mjs} +5 -7
- package/dist/{handler-BXJTXd02.d.mts → handler-HEcZsaij.d.mts} +2 -1
- package/dist/{headers-BOg_velo.mjs → headers-DWi2IXWx.mjs} +1 -1
- package/dist/help-CmZzxUba.mjs +2 -0
- package/dist/{help-DC7gdz7L.mjs → help-GKtwl07I.mjs} +124 -4
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +53 -24
- package/dist/{init-WO0JlPx8.mjs → init-FZx3Elvz.mjs} +13 -13
- package/dist/{link-CsHOinF7.mjs → link-BrQfb_CU.mjs} +4 -4
- package/dist/{list-CDb-4bZ1.mjs → list-D44jmIAM.mjs} +4 -4
- package/dist/{live-CKiJilLr.d.mts → live-CKJlvlNp.d.mts} +1 -1
- package/dist/{local-d1-CC8sKFGu.mjs → local-d1-Bg9OzEEO.mjs} +1 -1
- package/dist/{login-DvqXsfGs.mjs → login-CAsAsQ-_.mjs} +4 -4
- package/dist/login-CGcRKEoi.mjs +2 -0
- package/dist/{logs-BdfiOezj.mjs → logs-BjKvFnVM.mjs} +4 -4
- package/dist/{migrate-B8KuoYsO.mjs → migrate-BPITvDJN.mjs} +4 -4
- package/dist/migrate-CYfbKkXh.mjs +2 -0
- package/dist/{node-BM43oz4G.mjs → node-Dt7z256D.mjs} +1 -1
- package/dist/{operator-cmd-03819ATr.mjs → operator-cmd-BK5CCiT9.mjs} +4 -4
- package/dist/output-Dm_A4Tbv.mjs +81 -0
- package/dist/pages/client.d.mts +1 -1
- package/dist/pages/index.d.mts +1 -1
- package/dist/pages/index.mjs +2 -2
- package/dist/pages/islands-plugin.d.mts +16 -6
- package/dist/pages/islands-plugin.mjs +1 -1
- package/dist/pages/protocol.d.mts +2 -2
- package/dist/{output-CCH48AMM.mjs → picocolors-BTps1_gs.mjs} +2 -76
- package/dist/{platform-auth-config-z92h63q5.mjs → platform-auth-config-BlN8xTdD.mjs} +3 -3
- package/dist/{platform-auth-protection-DeE3yr2R.mjs → platform-auth-protection-7d5aV2Jg.mjs} +3 -3
- package/dist/{platform-auth-recovery-o_340Ixx.mjs → platform-auth-recovery-Dxij8ZbR.mjs} +3 -3
- package/dist/{platform-cmd-DNl8WosH.mjs → platform-cmd-B3hwKrFK.mjs} +5 -5
- package/dist/{platform-cmd-C4ZV3Vpy.mjs → platform-cmd-E0FuL212.mjs} +1 -1
- package/dist/{platform-domain-CU1JtJkW.mjs → platform-domain-D6Xcy9ZX.mjs} +36 -9
- package/dist/{platform-lifecycle-Bs2qx1E3.mjs → platform-lifecycle-DMh_qrry.mjs} +1 -1
- package/dist/{platform-lifecycle-Bc047IeT.mjs → platform-lifecycle-k0E0xoxx.mjs} +548 -86
- package/dist/{platform-management-CVpGI9Y5.mjs → platform-management-Brz_BDiT.mjs} +54 -9
- package/dist/{platform-management-C8tt6D8h.mjs → platform-management-DOtss0BN.mjs} +1 -1
- package/dist/{platform-recovery-dvUaptLr.mjs → platform-recovery-BvtcXON5.mjs} +2 -2
- package/dist/prepare-Bm3iq-u4.mjs +2 -0
- package/dist/{prepare-DyZ-Yok5.mjs → prepare-C-6YZyyg.mjs} +3 -3
- package/dist/{prepare-C3kt3Rst.mjs → prepare-CRhJbVrG.mjs} +1 -1
- package/dist/{project-cmd-B44I8J_W.mjs → project-cmd-BZLCqOqw.mjs} +29 -15
- package/dist/{project-team-BkbYIsXN.mjs → project-team-BvgM0WoX.mjs} +3 -3
- package/dist/{project-token-C8xEEQnB.mjs → project-token-l5DqK6Az.mjs} +3 -3
- package/dist/project-zero-trust-v6Mvpp8y.mjs +63 -0
- package/dist/{protocol-ZH3jP4a7.d.mts → protocol-BBa6cstI.d.mts} +1 -1
- package/dist/{provision-BhreDAOS.mjs → provision-C4IGqkBf.mjs} +24 -19
- package/dist/{provision-DNtrtaVD.mjs → provision-Fr9pRqce.mjs} +1 -1
- package/dist/{requests-DFyhBMaf.mjs → requests-DN-BbNiM.mjs} +3 -3
- package/dist/{rollback-DHHxXZiS.mjs → rollback-D7rzSaZM.mjs} +4 -4
- package/dist/runtime/env-public.d.mts +1 -1
- package/dist/runtime/handler.d.mts +1 -1
- package/dist/runtime/live-client.d.mts +1 -1
- package/dist/runtime/live.d.mts +1 -1
- package/dist/runtime/sandbox-container.d.mts +3 -0
- package/dist/runtime/sandbox-container.mjs +2 -0
- package/dist/runtime/sandbox.d.mts +4 -32
- package/dist/runtime/sandbox.mjs +118 -72
- package/dist/runtime/validator.d.mts +1 -1
- package/dist/runtime/ws-server.d.mts +1 -1
- package/dist/runtime/ws.d.mts +1 -1
- package/dist/sandbox-container-4fdqLnyb.mjs +279 -0
- package/dist/sandbox-container-DdNEBfCc.d.mts +72 -0
- package/dist/sandbox-qpNBT8a3.d.mts +49 -0
- package/dist/{secret-DN9sSNiV.mjs → secret-BOtOl_cb.mjs} +4 -4
- package/dist/{skills-O6FUaizK.mjs → skills-D1II1Juz.mjs} +1 -1
- package/dist/{subcommand-prompt-BuGYkAkC.mjs → subcommand-prompt-CY1C4fvl.mjs} +2 -2
- package/dist/{wrangler-BymcxrRa.mjs → wrangler-DQF1vKyf.mjs} +37 -27
- package/dist/{ws-BwcqizuH.d.mts → ws-BoY7vQML.d.mts} +1 -1
- package/package.json +40 -32
- package/sandbox.Dockerfile +4 -0
- package/schema.json +10 -22
- package/skills/void/SKILL.md +2 -0
- package/skills/void/docs/guide/deployment.md +1 -1
- package/skills/void/docs/guide/edge/revalidation.md +1 -1
- package/skills/void/docs/guide/edge/static-assets.md +1 -0
- package/skills/void/docs/guide/platform/administration/zero-trust.md +318 -0
- package/skills/void/docs/guide/platform/development/local.md +2 -2
- package/skills/void/docs/guide/platform/installation/domains.md +1 -1
- package/skills/void/docs/guide/platform/installation/first-deployment.md +4 -0
- package/skills/void/docs/guide/platform/installation/prerequisites.md +1 -1
- package/skills/void/docs/guide/platform/installation/uninstall.md +17 -2
- package/skills/void/docs/guide/platform-administration.md +1 -0
- package/skills/void/docs/guide/sandboxes.md +70 -41
- package/skills/void/docs/integrations/cloudflare.md +1 -1
- package/skills/void/docs/reference/api.md +35 -35
- package/skills/void/docs/reference/cli.md +68 -6
- package/skills/void/docs/reference/config.md +16 -16
- package/dist/client-4cDVv7BO.mjs +0 -2
- package/dist/gen-Vnv2f65C.mjs +0 -2
- package/dist/help-DQMfeKMz.mjs +0 -2
- package/dist/login-DFQk7rbW.mjs +0 -2
- package/dist/migrate-TsHGBnDA.mjs +0 -2
- package/dist/prepare-BZXkjdNe.mjs +0 -2
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
---
|
|
2
|
+
outline: deep
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Project Zero Trust
|
|
6
|
+
|
|
7
|
+
Project Zero Trust puts Cloudflare Access in front of the hostnames of projects deployed to your platform, including custom domains. Visitors sign in with one of your identity providers before they reach a protected project. Each project can still be made public.
|
|
8
|
+
|
|
9
|
+
This is separate from the Access login and protection for the platform API. Projects deployed directly to Cloudflare are not affected.
|
|
10
|
+
|
|
11
|
+
The steps below set it up. [How Protection Works](#how-protection-works) explains what visitors see, which Access applications Void creates, and what happens while settings change.
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- A Cloudflare Zero Trust organization in the account that hosts the platform, with the identity providers and reusable Access policies you want to use. Select at least one Allow policy that matches people by identity. Void rejects Bypass and Service Auth policies, and rules that allow Everyone or any service token.
|
|
16
|
+
- A Cloudflare API token for that account with **Access: Apps and Policies Write** and **Access: Organizations, Identity Providers, and Groups Read**. Void keeps it separate from the platform runtime token, stores it encrypted, and never shows it again.
|
|
17
|
+
- Free Access applications in the account. Cloudflare's default limit is 500 per account. Count the applications you already manage outside Void, then add the ones Void needs, as described in [Access Applications Void Creates](#access-applications-void-creates).
|
|
18
|
+
- Platform API, proxy, and email gateway hostnames outside the project application domain. Configuration is rejected when project protection would cover one of them. Any other hostname under the project application domain also asks for sign-in, except the `/health` path of `void-platform-health.<your domain>`, which Void keeps open for its health checks and never serves from a project. New projects cannot use that name. A project that already uses it keeps every other path, protected or public like any other project.
|
|
19
|
+
|
|
20
|
+
## Enable Zero Trust
|
|
21
|
+
|
|
22
|
+
Open **Zero Trust** in the administrator UI, or use the operator CLI:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
printf '%s' "$ACCESS_API_TOKEN" | void platform zero-trust configure \
|
|
26
|
+
--identity-providers <id[,id...]> \
|
|
27
|
+
--policies <id[,id...]> \
|
|
28
|
+
--existing-projects public \
|
|
29
|
+
--protect-new-projects \
|
|
30
|
+
--token-stdin \
|
|
31
|
+
--yes
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- `--existing-projects protected|public` decides what happens to the projects that already exist. It is required when you enable Zero Trust.
|
|
35
|
+
- `--protect-new-projects` protects projects created from now on. Omit it to make new projects public.
|
|
36
|
+
- Use `--plan` instead of `--yes` to check the change without applying it.
|
|
37
|
+
|
|
38
|
+
To change the identity providers, policies, token, or new-project default later, run the same command without `--existing-projects`. Existing projects keep their protection; use the project overrides below to change one project.
|
|
39
|
+
|
|
40
|
+
## Check Status
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
void platform zero-trust status
|
|
44
|
+
void platform zero-trust status --check
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`status` shows the saved settings, the current operation, and how many projects are protected, public, or waiting. `--check` also compares the settings with Cloudflare Access. In the administrator UI, use **Check with Cloudflare**.
|
|
48
|
+
|
|
49
|
+
## Project Overrides
|
|
50
|
+
|
|
51
|
+
Project owners and project administrators can protect a project or make it public. Readers can see its state.
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
void project zero-trust status
|
|
55
|
+
void project zero-trust protect
|
|
56
|
+
void project zero-trust public
|
|
57
|
+
void project zero-trust reconcile
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`status` also tells you whether protection can be changed right now. Making a project public does not change the default for new projects.
|
|
61
|
+
|
|
62
|
+
Installation administrators can do the same from the project page in the administrator UI or with `void platform zero-trust project-status|project-protect|project-public|project-reconcile <project-id>`.
|
|
63
|
+
|
|
64
|
+
Deploys and rollbacks wait until a project's protection change is finished. If one is refused, run `void project zero-trust status` to see why; the owner or a project administrator can run `void project zero-trust reconcile` before you try again. A protected project can have up to 100 custom domains.
|
|
65
|
+
|
|
66
|
+
## Disable Zero Trust
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
void platform zero-trust disable
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This removes the Access applications Void created and makes all projects public. On large installations it runs in steps; run it again, or check `void platform zero-trust status`, until Zero Trust shows as disabled with no operation running.
|
|
73
|
+
|
|
74
|
+
Uninstalling the platform does not remove these applications. `void platform uninstall` refuses to start while Zero Trust is enabled, a change is still running, or some Void-managed Access applications are left. Its error lists their names. Disable Zero Trust first, then uninstall. Once the uninstall starts turning the platform off, Zero Trust changes and deployments are refused. If it stops after that point, run it again, or bring the platform back with `void platform enable` or `void platform repair`. If a project's applications could not be removed, Void retries every hour while the platform is enabled. If the error says a project deletion stopped partway, run `void project delete` for that project again to remove them.
|
|
75
|
+
|
|
76
|
+
## How Protection Works
|
|
77
|
+
|
|
78
|
+
Every request to a protected project passes two checks before your code runs:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
Visitor
|
|
82
|
+
│
|
|
83
|
+
▼
|
|
84
|
+
Cloudflare Access ─── not signed in ─────────▶ sign-in page
|
|
85
|
+
│ signed in and allowed by your policies
|
|
86
|
+
▼
|
|
87
|
+
Void checks the Access token ─── rejected ───▶ 403 page
|
|
88
|
+
│ token is valid for this hostname
|
|
89
|
+
▼
|
|
90
|
+
Your project: routes, pages, assets, WebSockets
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
A public project skips both. Access lets every visitor through, and Void does not look for a token.
|
|
94
|
+
|
|
95
|
+
### What Visitors See
|
|
96
|
+
|
|
97
|
+
A protected project asks visitors to sign in with one of the identity providers you selected. If you selected exactly one, visitors go straight to it. Otherwise, they pick one of the selected providers. A sign-in lasts 12 hours. After that, Access asks again.
|
|
98
|
+
|
|
99
|
+
Protection follows the project to every hostname it answers on:
|
|
100
|
+
|
|
101
|
+
| Hostname | Protected project | Public project |
|
|
102
|
+
| ----------------------------------------- | ----------------- | -------------- |
|
|
103
|
+
| `<slug>.<your domain>` | Sign-in required | Open to anyone |
|
|
104
|
+
| The project's `workers.dev` testing URL | Sign-in required | Open to anyone |
|
|
105
|
+
| Custom domains, such as `app.example.com` | Sign-in required | Open to anyone |
|
|
106
|
+
|
|
107
|
+
Void only covers the `workers.dev` testing URLs of this installation. Other Workers in the account are not affected. On an installation without a domain, the `workers.dev` testing URL is the only project URL, and the shared project application covers only those URLs.
|
|
108
|
+
|
|
109
|
+
#### The 403 Page
|
|
110
|
+
|
|
111
|
+
Void answers `403 Cloudflare Access authentication required` when a request reaches a protected project without a valid Access token for it. Page requests get a short HTML error page. Requests under `/api`, requests for files, requests that are not `GET` or `HEAD`, and requests that do not accept HTML get the same message as plain text. The response is never cached.
|
|
112
|
+
|
|
113
|
+
Visitors who went through the sign-in page normally never see it. They can see it:
|
|
114
|
+
|
|
115
|
+
- for a short time while the project is switching between protected and public;
|
|
116
|
+
- while a Zero Trust change is still being applied to the project;
|
|
117
|
+
- when a Void-managed Access application was deleted, or its hostnames were changed, in the Cloudflare dashboard. See [Editing Applications in the Dashboard](#editing-applications-in-the-dashboard).
|
|
118
|
+
|
|
119
|
+
#### Every Path Is Covered
|
|
120
|
+
|
|
121
|
+
Protection applies to the whole hostname. There are no path exceptions. `/api/*` routes, static files, hashed assets, `robots.txt`, `favicon.ico`, server-sent events, and WebSockets all require a signed-in visitor.
|
|
122
|
+
|
|
123
|
+
#### Webhooks and Other Non-Browser Clients
|
|
124
|
+
|
|
125
|
+
Void only accepts policies that match people by identity. It rejects Bypass and Service Auth policies, and rules that allow Everyone or any service token. So a machine cannot pass on its own. Payment and Git webhooks, CI jobs, uptime checks, and plain `curl` calls get the sign-in page or the 403 response.
|
|
126
|
+
|
|
127
|
+
If a project must accept such requests:
|
|
128
|
+
|
|
129
|
+
- make the project public with `void project zero-trust public` and check callers in your own code, or
|
|
130
|
+
- move the endpoints that machines call into a separate project, and make only that project public.
|
|
131
|
+
|
|
132
|
+
### Two Checks on Every Request
|
|
133
|
+
|
|
134
|
+
Cloudflare Access is the first check. It runs at Cloudflare's edge, shows the sign-in page, and applies your policies. Only visitors your policies allow get an Access token for the project.
|
|
135
|
+
|
|
136
|
+
Void is the second check. Before a protected project runs, Void confirms that the request carries an Access token that:
|
|
137
|
+
|
|
138
|
+
- was issued by your Zero Trust team;
|
|
139
|
+
- belongs to one of the Access applications Void created for this project's hostname;
|
|
140
|
+
- has not expired.
|
|
141
|
+
|
|
142
|
+
If any of this fails, the visitor gets the [403 page](#the-403-page). Your routes, assets, and caches are never reached.
|
|
143
|
+
|
|
144
|
+
This gives you one guarantee: **deleting a Void-managed Access application, or changing its hostnames, cannot make a protected project public.** If someone deletes Void's application, or points it at other hostnames, visitors are refused instead of let in. Loosening the policies of Void's application in the dashboard does widen who can sign in, until the next update puts Void's policies back.
|
|
145
|
+
|
|
146
|
+
The second check does not look at your policies again. Who may sign in is decided only by the policies in Cloudflare Access. If you loosen a selected policy, the change applies to every protected project.
|
|
147
|
+
|
|
148
|
+
### Access Applications Void Creates
|
|
149
|
+
|
|
150
|
+
Void creates and owns these self-hosted applications in your Zero Trust organization:
|
|
151
|
+
|
|
152
|
+
| Application | Covers | Policy | Exists |
|
|
153
|
+
| -------------------------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
154
|
+
| Shared project application | `*.<your domain>` and this installation's `workers.dev` testing URLs | Your selected policies and identity providers | Once, while Zero Trust is enabled |
|
|
155
|
+
| Public exception | One public project's `<slug>.<your domain>` and `workers.dev` testing URL | A Bypass policy for Everyone, named `Void project is public` | One for each public project |
|
|
156
|
+
| Custom domain application | All custom domains of one protected project | Your selected policies and identity providers | One for each protected project that has custom domains |
|
|
157
|
+
| Health check exception | `void-platform-health.<your domain>/health` | A Bypass policy for Everyone, named `Void platform health check` | Once, while Zero Trust is enabled on an installation with a domain |
|
|
158
|
+
|
|
159
|
+
Custom domains of a public project need no Access application.
|
|
160
|
+
|
|
161
|
+
The number of applications Void needs is:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
2 + public projects + protected projects that have custom domains
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Use 1 instead of 2 on an installation without a domain. For example, 40 projects with 10 public and 5 protected projects that have custom domains need 2 + 10 + 5 = 17 applications. Void stops with an error when the account has more than 500 Access applications.
|
|
168
|
+
|
|
169
|
+
#### Recognizing Void's Applications
|
|
170
|
+
|
|
171
|
+
Void adds no tags. Its application names follow this pattern:
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
void-<installation>-<code>-<random>-project-zero-trust shared project application
|
|
175
|
+
void-<installation>-<code>-<random>-public-<project-id> public exception
|
|
176
|
+
void-<installation>-<code>-<random>-protected-<project-id> custom domain application
|
|
177
|
+
void-<installation>-<code>-<random>-platform-health health check exception
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
- `<installation>` is the start of your installation ID, which begins with your installation name.
|
|
181
|
+
- `<code>` is 16 characters. It is the same for every application of one installation.
|
|
182
|
+
- `<random>` is 32 random characters.
|
|
183
|
+
- `<project-id>` is the project ID, such as `proj_abc123def456`. The project slug is not part of the name.
|
|
184
|
+
|
|
185
|
+
To see the exact names Void recorded, run `void platform zero-trust status` for the shared application and the health check exception, and `void platform zero-trust project-status <project-id>` for a project's applications. There, the public exception is listed as `bypass application name` and the custom domain application as `protected application name`.
|
|
186
|
+
|
|
187
|
+
### Editing Applications in the Dashboard
|
|
188
|
+
|
|
189
|
+
Do not edit, rename, or delete Void's applications in the Cloudflare dashboard. Change the identity providers and policies with `void platform zero-trust configure` instead. See [Enable Zero Trust](#enable-zero-trust).
|
|
190
|
+
|
|
191
|
+
You can still edit the rules inside a selected reusable policy. Void's applications use your policies as they are. Void checks them again during `void platform zero-trust configure` and `void platform zero-trust reconcile`, which stop with an error, and during `status --check`, which reports `present: false`. A policy fails this check when it now allows Everyone or any service token, or uses a Bypass or Service Auth decision.
|
|
192
|
+
|
|
193
|
+
#### What Happens If You Do
|
|
194
|
+
|
|
195
|
+
Void writes an application when it updates it: during platform `configure` or `reconcile`, during a project's `protect`, `public`, or `reconcile`, when a custom domain is added to or removed from that project, and while it retries a project that is not settled. Scheduled maintenance does not look for dashboard changes on settled projects. Until one of these runs, your change stays in effect.
|
|
196
|
+
|
|
197
|
+
| Change in the dashboard | Effect | Repair |
|
|
198
|
+
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
|
|
199
|
+
| Edit hostnames, policies, providers, or session length | Your change stays until the next update, which puts Void's settings back. | Run the reconcile command for that application |
|
|
200
|
+
| Delete the shared project application | Protected projects answer 403 on `<slug>.<your domain>` and `workers.dev` URLs. Their custom domains and public projects keep working. | `void platform zero-trust reconcile` |
|
|
201
|
+
| Delete a public exception | Visitors of that public project are asked to sign in, because the shared application now covers it. | `void project zero-trust reconcile` in that project |
|
|
202
|
+
| Delete a custom domain application | That protected project answers 403 on its custom domains. | `void project zero-trust reconcile` in that project |
|
|
203
|
+
| Delete the health check exception | Platform health checks fail with a redirect to sign-in, so the admin dashboard shows `dispatch` as unhealthy and `void platform upgrade` and `repair` stop at their health check. | `void platform zero-trust reconcile` |
|
|
204
|
+
| Rename an application | Void stops updating or deleting it. Reconcile fails with `The recorded Access application no longer has its Void-owned name.` For the shared application, platform status then shows `error`. | Rename it back to the recorded name, then reconcile |
|
|
205
|
+
| Copy an application with the same name | Void ignores the copy while the original exists, and `disable` does not remove it. If the original is later deleted, reconcile fails with `Multiple Cloudflare Access applications are named <name>.` | Delete the copy, then reconcile |
|
|
206
|
+
|
|
207
|
+
When Void recreates a deleted shared project application, the new application issues different Access tokens. Void then moves each protected project to it. On large installations this runs in steps, and protected projects answer 403 until Void reaches them.
|
|
208
|
+
|
|
209
|
+
#### Checking for Changes
|
|
210
|
+
|
|
211
|
+
```sh
|
|
212
|
+
void platform zero-trust status --check
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
This compares the shared project application and the health check exception with the saved settings, and checks your selected identity providers and policies again. The output includes:
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
checked: true
|
|
219
|
+
live:
|
|
220
|
+
present: true
|
|
221
|
+
drifted: false
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
- `drifted: true` means the shared application or the health check exception no longer matches. Run `void platform zero-trust reconcile`.
|
|
225
|
+
- `present: false` means Void could not read it. The application may be deleted, a selected identity provider or policy may be gone or no longer allowed, or the token may not work. Check the token and selections, then run `void platform zero-trust reconcile`.
|
|
226
|
+
|
|
227
|
+
`--check` only reads. It changes nothing. It does not check public exceptions or custom domain applications. If you think one was changed, run a reconcile command.
|
|
228
|
+
|
|
229
|
+
#### Repair Commands
|
|
230
|
+
|
|
231
|
+
| Command | Rewrites | Who can run it |
|
|
232
|
+
| --------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
233
|
+
| `void platform zero-trust reconcile` | The shared project application, the health check exception, and every project's applications | Installation administrators |
|
|
234
|
+
| `void platform zero-trust project-reconcile <project-id>` | One project's applications | Installation administrators |
|
|
235
|
+
| `void project zero-trust reconcile` | The linked project's applications, or pass `--project <slug>` | The project owner and project administrators |
|
|
236
|
+
|
|
237
|
+
The two project commands work only when platform status is `ready`. While a platform change runs, or after it fails, run `void platform zero-trust reconcile` first.
|
|
238
|
+
|
|
239
|
+
### What Happens During Changes
|
|
240
|
+
|
|
241
|
+
Void orders every change so that a protected project never becomes public by mistake. If a step fails, the project keeps its protection, or refuses visitors with the 403 page, until the change can finish.
|
|
242
|
+
|
|
243
|
+
Void's router can keep a project's previous setting for up to about a minute. During that time, some visitors may see the 403 page instead of the sign-in page.
|
|
244
|
+
|
|
245
|
+
#### Protecting or Making a Project Public
|
|
246
|
+
|
|
247
|
+
`void project zero-trust protect` and `void project zero-trust public` usually finish before the command returns.
|
|
248
|
+
|
|
249
|
+
- **Protect.** Void covers the custom domains first, then turns on its own check, then removes the public exception. Visitors may see the 403 page for a moment before Access starts asking them to sign in.
|
|
250
|
+
- **Public.** Void adds the public exception first, then turns off its own check, then removes the custom domain application. Visitors may see the 403 page for a moment before the project opens.
|
|
251
|
+
|
|
252
|
+
If the command prints `Zero Trust update is still in progress`, run `void project zero-trust reconcile` to continue, or wait for the hourly maintenance. If it fails with `Cloudflare Access could not be updated. Protection remains fail closed.`, fix the cause, then run `void project zero-trust reconcile`. Until then, a project that was protected stays protected. A project you were protecting may already ask for sign-in, or answer with the 403 page, but it is never more open than before. A project you were making public may already be open on some hostnames.
|
|
253
|
+
|
|
254
|
+
Run `void project zero-trust status` to follow a change. `State:` shows `reconciling` while it runs, `error` when it needs attention, and `protected` or `public` when it is done. `Last error:` explains a failure.
|
|
255
|
+
|
|
256
|
+
#### Enabling and Disabling Zero Trust
|
|
257
|
+
|
|
258
|
+
Large changes run in steps. Platform status shows `configuring` or `disabling`, and project owners see `Available: no`. Scheduled maintenance continues within a few minutes.
|
|
259
|
+
|
|
260
|
+
When you **enable** Zero Trust:
|
|
261
|
+
|
|
262
|
+
1. Void adds the public exception for each project that stays public. These projects never ask visitors to sign in.
|
|
263
|
+
2. Void creates the health check exception, then the shared project application. From here, the `<slug>.<your domain>` and `workers.dev` URLs of protected projects require sign-in.
|
|
264
|
+
3. Void goes through the protected projects and covers their custom domains. A project's custom domains stay open until Void reaches it.
|
|
265
|
+
|
|
266
|
+
If Void cannot add a project's public exception, the project shows `error`, and its visitors are asked to sign in until the next retry succeeds. Void retries every hour, or run `void project zero-trust reconcile` once platform status is `ready`.
|
|
267
|
+
|
|
268
|
+
When you **disable** Zero Trust:
|
|
269
|
+
|
|
270
|
+
1. Void turns off its own check for each protected project and removes its custom domain application. Custom domains open here.
|
|
271
|
+
2. Void deletes the shared project application, then the health check exception. `<slug>.<your domain>` and `workers.dev` URLs open here.
|
|
272
|
+
3. Void deletes the public exceptions. Public projects stay open the whole time.
|
|
273
|
+
|
|
274
|
+
#### Custom Domains
|
|
275
|
+
|
|
276
|
+
A custom domain on a protected project goes live only after Void adds it to the project's custom domain application. If Access cannot be updated, the domain stays pending and is not reachable. Void tries again each time it checks the domain.
|
|
277
|
+
|
|
278
|
+
When you remove a custom domain, Void removes it from the project first, then from the Access application. If the Access update fails, the project shows `reconciling` or `error` and Void retries every hour. A protected project can have up to 100 custom domains. Custom domains on public projects need no Access change.
|
|
279
|
+
|
|
280
|
+
#### New Projects
|
|
281
|
+
|
|
282
|
+
A new project starts protected or public based on the default for new projects. If Void cannot set up its protection, creating the project still succeeds with a warning. See [Recovery](#recovery).
|
|
283
|
+
|
|
284
|
+
#### Deploys and Rollbacks
|
|
285
|
+
|
|
286
|
+
Deploys and rollbacks wait while a project's protection is not settled, so a deploy cannot publish a project before its protection is in place. They are refused with `Zero Trust protection for this project is not ready`, followed by the reason:
|
|
287
|
+
|
|
288
|
+
- `Project Zero Trust is still being initialized.`
|
|
289
|
+
- `The project public exception is still reconciling.`
|
|
290
|
+
- `Project Zero Trust is still reconciling.`
|
|
291
|
+
|
|
292
|
+
If the saved platform configuration is invalid, they are refused with `The platform Zero Trust configuration is invalid.` instead. Ask a platform administrator to repair it.
|
|
293
|
+
|
|
294
|
+
A project that is already protected can still deploy during a platform-wide change. While it is being made public, deploys wait until that finishes. See [Project Overrides](#project-overrides) for what to do when a deploy is refused.
|
|
295
|
+
|
|
296
|
+
### Caching
|
|
297
|
+
|
|
298
|
+
Responses for signed-in visitors are never shared between visitors. Void skips its shared caches for every request that carries an Access token: [ISR](/guide/edge/revalidation#cache-bypass) and the [static asset edge cache](/guide/edge/static-assets#non-hashed-assets). Each visitor gets a response made for their request.
|
|
299
|
+
|
|
300
|
+
On a protected project, this means:
|
|
301
|
+
|
|
302
|
+
- pages render on every request, and ISR never serves a cached page;
|
|
303
|
+
- static files and hashed assets skip the edge cache;
|
|
304
|
+
- the project handles more requests and may respond more slowly than a public project.
|
|
305
|
+
|
|
306
|
+
Public projects keep using the shared caches as usual.
|
|
307
|
+
|
|
308
|
+
## Recovery
|
|
309
|
+
|
|
310
|
+
A project never becomes public by mistake while a change is in progress. See [What Happens During Changes](#what-happens-during-changes).
|
|
311
|
+
|
|
312
|
+
- **Status stays `configuring` or `disabling`.** Large changes run in steps. Scheduled maintenance continues them within a few minutes, or run `void platform zero-trust reconcile`.
|
|
313
|
+
- **Status shows an error.** Fix the cause shown, such as token permissions or the application limit, then run `void platform zero-trust reconcile`. Otherwise Void retries every hour.
|
|
314
|
+
- **One project shows an error.** The rest of the change still finishes. Void retries the project every hour, or its owner or a project administrator can run `void project zero-trust reconcile`. Until then, a project that was already protected stays protected, and a project being newly protected is never more open than before.
|
|
315
|
+
- **Adding a domain stays pending because of a project.** Void publishes the new domain only after every project is ready for it. Platform status shows an error that names the projects it could not update. Check each one with `void platform zero-trust project-status <project-id>`, fix the cause, then run `void platform zero-trust reconcile` or rerun the domain command. Void also retries every hour. Your `workers.dev` URLs keep working meanwhile.
|
|
316
|
+
- **A new project could not be set up.** Creating the project still succeeds with a warning. Void retries every hour, or run `void project zero-trust reconcile`.
|
|
317
|
+
- **The saved API token expired or was revoked.** Run `void platform zero-trust configure --token-stdin` with a replacement token and the same identity providers, policies, and `--protect-new-projects` choice. Omit `--existing-projects`. Void continues the unfinished change, including an unfinished disable. Finish it before changing other settings.
|
|
318
|
+
- **A selected identity provider or policy was deleted.** Run `void platform zero-trust disable` to stop the unfinished setup and remove its applications. This makes projects public. Then configure Zero Trust again with the new selections.
|
|
@@ -51,7 +51,7 @@ The command disables the optional build containers, so basic API and admin work
|
|
|
51
51
|
does not require Docker. To develop managed builds, install Docker and run the
|
|
52
52
|
API with containers enabled.
|
|
53
53
|
|
|
54
|
-
Open `http://localhost:8787/admin/`. Setup writes local
|
|
54
|
+
Open `http://localhost:8787/admin/`. Setup writes the API's local database connection and development authentication bypass to `platform/packages/api/.dev.vars`. It configures `platform/packages/dashboard/.env` for the separate dashboard. Both files are ignored by Git. Production installations get separate credentials through the installer.
|
|
55
55
|
|
|
56
56
|
The API's development bypass lets you work on the browser admin UI without setting up OAuth. Operator CLI sessions still require administrator authentication; they do not use the browser bypass.
|
|
57
57
|
|
|
@@ -63,7 +63,7 @@ The dashboard is a separate source app. After API setup, start it in another ter
|
|
|
63
63
|
vp run --filter @voidcloud/dashboard dev
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
Setup points the dashboard's local `.env` at the API you started:
|
|
67
67
|
|
|
68
68
|
```dotenv
|
|
69
69
|
API_URL=http://localhost:8787
|
|
@@ -15,7 +15,7 @@ void platform domain set example.app
|
|
|
15
15
|
|
|
16
16
|
The command selects your installed platform (or offers a picker), finds or creates its zone, sets up DNS and routing, and verifies HTTPS before publishing the new application URLs. Set the management token as described in [installation setup](/guide/platform/installation/setup) when creating DNS or a zone. Grant the existing runtime token **Cache Purge: Purge** on the new zone; Void checks that permission through the running platform without asking you to paste its token again.
|
|
17
17
|
|
|
18
|
-
If nameservers or
|
|
18
|
+
If nameservers, certificates, or project Zero Trust protection are pending, follow the printed guidance and rerun the same command. Void preserves each project's public or protected setting before making the new URLs available. Your workers.dev app URLs continue working during and after setup. Projects, deployments, secrets, and the platform API URL stay the same, so developers do not reconnect and configured login callbacks do not change. DNS and configuration changes may take time to propagate.
|
|
19
19
|
|
|
20
20
|
Use `--installation <id>` to select an installation explicitly, `--zone example.com` for an app domain such as `apps.example.com`, or `--dedicated-zone` for catch-all routing on a dedicated zone. Nested domains still need the wildcard certificate described below. This command adds the first domain; replacing an existing application domain is not currently supported. It uses the installed runtime and does not require `--runtime` or an app redeploy.
|
|
21
21
|
|
|
@@ -80,3 +80,7 @@ Void shows the proposed access change and asks you to confirm it. Once approved,
|
|
|
80
80
|
To see who can join, run `void platform signup show`. You can also allow an email address or a domain such as `*@example.com`. For an OIDC user without verified email, use `void platform signup allow identity <connection-id> <subject>`; the subject match is exact and the provider's domain or group restrictions still apply. Remove that grant with `void platform signup disallow identity <connection-id> <subject>`. `void platform signup open` permits public signup; `void platform signup restrict` requires an allowlist match again.
|
|
81
81
|
|
|
82
82
|
Your administrator session lasts for one hour. Use it to inspect users, projects, logs, and platform health. The [Platform Administration guide](/guide/platform-administration) walks through those workflows, previews, and automation. You can also open `<API origin>/admin/login` to use the browser admin UI.
|
|
83
|
+
|
|
84
|
+
### Protect Project Hostnames with Zero Trust
|
|
85
|
+
|
|
86
|
+
After installation, an administrator can require Cloudflare Access on new project hostnames while allowing each project owner or project administrator to opt out. This is independent of Access login and protection for the platform API itself, and it needs its own Cloudflare API token. See [Project Zero Trust](/guide/platform/administration/zero-trust) for the requirements, setup command, and recovery.
|
|
@@ -73,7 +73,7 @@ Void does not require a particular database provider. Use an existing PostgreSQL
|
|
|
73
73
|
|
|
74
74
|
1. Create a fresh database or project dedicated to the platform, with no existing application tables. Use a database role that can create and manage its tables and schemas.
|
|
75
75
|
2. Open the provider's connection details and select the primary database. Use a direct connection or a session-mode pooler, not transaction pooling. The connection must work from both your computer and Cloudflare.
|
|
76
|
-
3. Copy the PostgreSQL connection URL, including the password and SSL settings, into your password manager. Paste only the URL—not a surrounding `psql` command—into Void's `PostgreSQL DATABASE_URL` prompt.
|
|
76
|
+
3. Copy the PostgreSQL connection URL, including the password and SSL settings, into your password manager. Paste only the URL—not a surrounding `psql` command—into Void's `PostgreSQL DATABASE_URL` prompt, as the provider gives it, including SSL settings such as `sslmode=verify-full`. A Hyperdrive that Void creates trusts only public certificate authorities, so if your database uses a private certificate authority, use a separately managed Hyperdrive, as described below.
|
|
77
77
|
|
|
78
78
|
| Provider | Connection setup |
|
|
79
79
|
| ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -31,7 +31,7 @@ void platform uninstall [id] --plan
|
|
|
31
31
|
void platform uninstall [id]
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Uninstall blocks platform traffic, removes
|
|
34
|
+
Uninstall blocks platform traffic, removes Queues that no remaining platform Worker uses, and records the resources left for you to review. By default, Workers, the Queues they use, KV, R2, Hyperdrive, the dispatch namespace, and AI Gateway remain in your account. Adopted resources, external PostgreSQL, zones, DNS records, routes, custom domains, and Cloudflare Access resources are always retained.
|
|
35
35
|
|
|
36
36
|
To also remove eligible data resources owned by the installer:
|
|
37
37
|
|
|
@@ -39,10 +39,25 @@ To also remove eligible data resources owned by the installer:
|
|
|
39
39
|
void platform uninstall [id] --purge-data
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
Even with `--purge-data`, Void retains Workers, R2, AI Gateway, DNS records, routes, custom domains, Access resources, adopted resources, external PostgreSQL, and zones. Review those in the Cloudflare dashboard if you want to remove them.
|
|
42
|
+
Even with `--purge-data`, Void retains Workers, the Queues they use, R2, AI Gateway, DNS records, routes, custom domains, Access resources, adopted resources, external PostgreSQL, and zones. Review those in the Cloudflare dashboard if you want to remove them.
|
|
43
|
+
|
|
44
|
+
### Remove retained resources
|
|
45
|
+
|
|
46
|
+
Cloudflare refuses to delete a resource while a platform Worker still uses it. In the Cloudflare dashboard, remove what is left in this order, skipping anything already gone:
|
|
47
|
+
|
|
48
|
+
1. Delete the platform DNS record, Worker routes, and custom domains.
|
|
49
|
+
2. Open each platform Queue and remove the platform API Worker from its consumers.
|
|
50
|
+
3. Delete the platform Workers.
|
|
51
|
+
4. Delete the platform Queues.
|
|
52
|
+
5. Delete the application Workers in the dispatch namespace, then delete the namespace.
|
|
53
|
+
6. Delete the platform KV namespaces and Hyperdrive configuration.
|
|
54
|
+
7. Empty the R2 bucket, then delete it.
|
|
55
|
+
8. Delete the AI Gateway.
|
|
43
56
|
|
|
44
57
|
If installation configured Cloudflare Access, the uninstall plan lists its recorded applications and service tokens with their ownership and IDs. Review them in Zero Trust after uninstall. Remove installer-created resources only when nothing else uses them; resources connected from an existing company setup remain under their owner's control.
|
|
45
58
|
|
|
59
|
+
Uninstall does not remove the applications created for [project Zero Trust](/guide/platform/administration/zero-trust). While Zero Trust is enabled or still has Access applications, uninstall and `--plan` stop before any change and list those applications. Run `void platform zero-trust disable` first. Uninstall reads this from the installation database, so it also stops when the database cannot be reached.
|
|
60
|
+
|
|
46
61
|
::: details Why some resources require manual cleanup
|
|
47
62
|
|
|
48
63
|
Resources that may have been shared or repurposed require manual review before deletion. Void verifies ownership, keeps those resources in place, and blocks platform traffic.
|
|
@@ -12,5 +12,6 @@ The operator commands for users, projects, deployments, and system status requir
|
|
|
12
12
|
|
|
13
13
|
- [Sign-in and Access](/guide/platform/administration/access)
|
|
14
14
|
- [Users and Projects](/guide/platform/administration/projects)
|
|
15
|
+
- [Project Zero Trust](/guide/platform/administration/zero-trust)
|
|
15
16
|
- [Email](/guide/platform/administration/email)
|
|
16
17
|
- [Operations](/guide/platform/administration/operations)
|
|
@@ -4,82 +4,111 @@ outline: deep
|
|
|
4
4
|
|
|
5
5
|
# Sandboxes
|
|
6
6
|
|
|
7
|
-
Use a Cloudflare Sandbox to run commands, work with files, and
|
|
7
|
+
Use a Cloudflare Sandbox to run commands, work with files, and connect to servers from server code. Each Sandbox ID selects an isolated container.
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
import { defineHandler } from 'void';
|
|
11
11
|
import { getSandbox } from 'void/sandbox';
|
|
12
12
|
|
|
13
13
|
export const POST = defineHandler(async (c) => {
|
|
14
|
-
const { command } = await c.req.json<{ command: string }>();
|
|
15
14
|
const sandbox = await getSandbox('default');
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const process = await sandbox.exec(['node', '--version']);
|
|
16
|
+
const result = await process.output();
|
|
17
|
+
|
|
18
|
+
return c.json({
|
|
19
|
+
exitCode: result.exitCode,
|
|
20
|
+
stdout: new TextDecoder().decode(result.stdout),
|
|
21
|
+
stderr: new TextDecoder().decode(result.stderr),
|
|
22
|
+
});
|
|
19
23
|
});
|
|
20
24
|
```
|
|
21
25
|
|
|
22
|
-
Importing from `void/sandbox` enables the required
|
|
26
|
+
Importing from `void/sandbox` enables the required resources. Local development, native Cloudflare deployments, and Void Platform share the same runtime API.
|
|
23
27
|
|
|
24
28
|
## Configuration
|
|
25
29
|
|
|
26
|
-
Most apps do not need config. The default binding is `SANDBOX`, the Durable Object class is `
|
|
30
|
+
Most apps do not need config. The default binding is `SANDBOX`, the Durable Object class is `SandboxV1`, and the default environment provides Node.js 24 on Debian Trixie. Local development and native deploys build Void's packaged Dockerfile, so Docker must be running. Managed platform deploys use Cloudflare's managed Node.js image.
|
|
27
31
|
|
|
28
32
|
Use `void.config.ts` when you need a custom image or container size:
|
|
29
33
|
|
|
30
|
-
```
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
34
|
+
```ts
|
|
35
|
+
import { defineConfig } from 'void/config';
|
|
36
|
+
|
|
37
|
+
export default defineConfig({
|
|
38
|
+
sandbox: {
|
|
39
|
+
image: './Dockerfile.sandbox',
|
|
40
|
+
platformImage: 'registry.cloudflare.com/<account-id>/sandbox@sha256:<digest>',
|
|
41
|
+
instanceType: 'standard-1',
|
|
42
|
+
},
|
|
43
|
+
});
|
|
39
44
|
```
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
| Field | Default | Description |
|
|
47
|
+
| ------------------- | --------------------------- | -------------------------------------------------------------------- |
|
|
48
|
+
| `binding` | `SANDBOX` | Binding name for local and native Cloudflare use |
|
|
49
|
+
| `className` | `SandboxV1` | Durable Object class for local and native Cloudflare use |
|
|
50
|
+
| `containerName` | `void-sandbox-v1` | Cloudflare container application name |
|
|
51
|
+
| `image` | Packaged Node.js Dockerfile | Dockerfile or digest-pinned Cloudflare registry image for native use |
|
|
52
|
+
| `imageBuildContext` | Directory of `image` | Docker build context |
|
|
53
|
+
| `platformImage` | `cloudflare/debian-trixie` | Image used by managed platform deploys |
|
|
54
|
+
| `instanceType` | `lite` | `lite`, `standard-1`, `standard-2`, `standard-3`, or `standard-4` |
|
|
55
|
+
|
|
56
|
+
Custom images must include the helper matching Void's installed Sandbox SDK version. The SDK image supplies this binary, but is not a runnable environment itself:
|
|
57
|
+
|
|
58
|
+
```dockerfile
|
|
59
|
+
FROM node:24.21.0-trixie-slim
|
|
60
|
+
COPY --from=docker.io/cloudflare/sandbox:1.0.0 /usr/local/bin/sandbox-shim /usr/local/bin/sandbox-shim
|
|
61
|
+
WORKDIR /workspace
|
|
62
|
+
CMD ["sleep", "infinity"]
|
|
63
|
+
```
|
|
42
64
|
|
|
43
|
-
|
|
44
|
-
| ------------------- | -------------------------- | --------------------------------------------------------------------- |
|
|
45
|
-
| `binding` | `SANDBOX` | Binding name for local and native Cloudflare use |
|
|
46
|
-
| `className` | `Sandbox` | Durable Object class for local and native Cloudflare use |
|
|
47
|
-
| `containerName` | `void-sandbox` | Cloudflare container app name |
|
|
48
|
-
| `image` | Matching sandbox SDK image | Dockerfile path or registry image for local and native Cloudflare use |
|
|
49
|
-
| `imageBuildContext` | Directory of `image` | Docker build context for local and native Cloudflare use |
|
|
50
|
-
| `platformImage` | Matching sandbox SDK image | Registry image used by `void deploy` |
|
|
51
|
-
| `instanceType` | `lite` on Void deploy | Container size, such as `lite`, `basic`, `standard-1` |
|
|
52
|
-
| `maxInstances` | `20` on Void deploy | Maximum number of container instances |
|
|
65
|
+
For a managed platform, push your custom image to that platform account's Cloudflare registry and set `platformImage` to its digest-pinned reference. If `image` is already a Cloudflare registry reference, it also becomes the default `platformImage`. External registry references and mutable tags are not supported by the new scheduling policy. See [Cloudflare's image management guide](https://developers.cloudflare.com/containers/guides/image-management/#push-images-to-the-cloudflare-registry).
|
|
53
66
|
|
|
54
67
|
## Runtime API
|
|
55
68
|
|
|
56
|
-
`getSandbox(id, options)`
|
|
69
|
+
`getSandbox(id, options)` resolves a Sandbox without starting it. The first command, file operation, or port request starts the container. IDs contain 1–63 characters and are lowercased by default; pass `normalizeId: false` to preserve case.
|
|
57
70
|
|
|
58
71
|
```ts
|
|
59
72
|
import { getSandbox } from 'void/sandbox';
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
const sandbox = await getSandbox(`user-${user.id}`, {
|
|
75
|
+
inactivityTimeoutMs: 10 * 60 * 1000,
|
|
76
|
+
enableInternet: false,
|
|
77
|
+
});
|
|
78
|
+
await sandbox.files.writeFile('/workspace/input.txt', 'hello');
|
|
79
|
+
const process = await sandbox.exec(['cat', '/workspace/input.txt'], {
|
|
80
|
+
signal: AbortSignal.timeout(5_000),
|
|
81
|
+
});
|
|
82
|
+
const { stdout, exitCode } = await process.output();
|
|
83
|
+
const text = new TextDecoder().decode(stdout);
|
|
65
84
|
```
|
|
66
85
|
|
|
67
|
-
|
|
86
|
+
Commands take an executable and arguments as an array. For shell syntax, explicitly run `['sh', '-c', command]`. Execution options include `cwd` (default `/workspace`), `env`, `user`, `signal`, `pty`, `stdin`, `stdout`, and `stderr`.
|
|
68
87
|
|
|
69
|
-
|
|
88
|
+
`exec()` returns a process immediately after it starts. Read its `stdout` and `stderr` streams, or call `output()` to collect both as `ArrayBuffer`s together with the exit code. `exitCode` is a promise; `kill(signal?)` and `resize(cols, rows)` are asynchronous. Use `stdin: 'pipe'` to receive a writable `stdin` stream. A process can continue running after a request returns, until it exits or its container stops. When streaming output from a long command, await `process.exitCode` alongside consuming its streams. This keeps an explicit command wait active even while the command produces no output; unattended background commands can stop when the Sandbox becomes idle.
|
|
70
89
|
|
|
71
|
-
|
|
90
|
+
File operations live under `sandbox.files`: `readFile`, `writeFile`, `stat`, `lstat`, `readDirectory`, `mkdir`, `rename`, and `remove`. `readFile()` returns a streaming `Response`; use `.text()`, `.arrayBuffer()`, or `.body`. `writeFile()` accepts text, binary data, or a byte stream. Relative file paths require an explicit `cwd` option.
|
|
72
91
|
|
|
73
|
-
|
|
92
|
+
To reach a server inside the container, call `sandbox.fetch(port, new Request(url))`. `sandbox.running()` checks whether the container is running; `sandbox.destroy()` stops it.
|
|
74
93
|
|
|
75
|
-
|
|
94
|
+
`getSandbox()` options include `inactivityTimeoutMs` (default ten minutes, maximum six hours), `enableInternet` (default `false`), and string `labels`. Internet access and labels take effect on the next container start. `binding` selects a custom native binding; managed platforms use the configured binding.
|
|
76
95
|
|
|
77
|
-
|
|
96
|
+
For code that runs on both deployment targets, use `getSandbox()`. Direct access through `c.env.SANDBOX` is available only on local and native Cloudflare deployments.
|
|
97
|
+
|
|
98
|
+
## State persistence
|
|
99
|
+
|
|
100
|
+
`getSandbox(id)` selects the same Durable Object for that ID within a deployment. Native Cloudflare deployments preserve that namespace across Worker versions. Each managed platform deployment has its own namespace; rolling back to a retained deployment reconnects to that deployment's namespace.
|
|
101
|
+
|
|
102
|
+
Files, running processes, and listening servers last only as long as the container. It can stop after inactivity, crash, or restart. Save anything you need to keep in your database, KV, or R2. For custom Durable Object implementations, `void/sandbox` also exports the SDK's `Files`, `DirectoryBackup`, `DirectoryBackupGateway`, `S3Mount`, and `S3Gateway` helpers. Deleting a project on a Void platform removes both its Durable Objects and containers.
|
|
78
103
|
|
|
79
104
|
## Deployment
|
|
80
105
|
|
|
81
|
-
|
|
106
|
+
Sandboxes require [Workers Paid](https://dash.cloudflare.com/?to=/:account/workers/plans) and Containers access. Void checks this before provisioning or building. A managed platform's runtime token needs Account / Containers: Edit and Account / Cloudchamber: Edit. Applications without Sandbox do not require Containers or perform this entitlement check.
|
|
107
|
+
|
|
108
|
+
`void deploy --platform cloudflare` builds native images and deploys the Sandbox alongside the application. `void deploy` on a connected Void Platform creates a deployment-scoped Sandbox controller, which enforces concurrency and runtime limits. Upgrade the platform before deploying an application built with this Sandbox API.
|
|
109
|
+
|
|
110
|
+
## Moving from Sandbox SDK 0.x
|
|
82
111
|
|
|
83
|
-
|
|
112
|
+
Update string commands to argument arrays, move file calls under `.files`, and consume process output and file responses as shown above. Replace `sleepAfter` and `keepAlive` with `inactivityTimeoutMs`; remove `maxInstances` from configuration. The old `Sandbox` export, sessions, code interpreter, process-list helpers, and preview-URL helpers are no longer part of this API.
|
|
84
113
|
|
|
85
|
-
|
|
114
|
+
Existing native 0.x Sandboxes need a new Worker configuration and namespace. Back up container files and any Durable Object data, choose a fresh `worker.name`, and remove the old Sandbox bindings, containers, and migrations from that new configuration before deploying. The new default class is `SandboxV1`; existing state does not transfer automatically. Retain the old Worker until you have validated the replacement and restored your data, then clean up its resources. See [Cloudflare's scheduling-policy migration guide](https://developers.cloudflare.com/containers/guides/migrate-to-durable-object-scheduling-policy/).
|
|
@@ -360,7 +360,7 @@ ISR uses the shared cache protocol. Entries are scoped to a deployment and hostn
|
|
|
360
360
|
|
|
361
361
|
With Cloudflare selected, `void secret`, `void domain`, `void project status|list|logs|rollback`, and remote `void db` commands use the saved Worker and account. Database commands operate on the selected D1 database. Logs are a live tail; Void doesn't provide hosted log history for direct deploys.
|
|
362
362
|
|
|
363
|
-
Custom domain changes update routes immediately without rewriting schedules, queues, or workflows. Removing the final custom domain
|
|
363
|
+
Custom domain changes update routes immediately without rewriting schedules, queues, or workflows. Removing the final custom domain uses your browser session from `void cloudflare login` or an API token with Workers Scripts: Edit permission.
|
|
364
364
|
|
|
365
365
|
`void project delete` doesn't remove direct Cloudflare resources, which may be shared. Review their use and remove them explicitly in Cloudflare.
|
|
366
366
|
|