You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
proxy: dial the tunnel through an HTTP proxy when the guest requires one
The tunnel client (`proxy run --url`) used the runtime's native WebSocket,
which ignores HTTP(S)_PROXY and always dials direct. In a sandbox whose only
egress is an explicit proxy gateway (e.g. Docker Sandboxes), the broker was
unreachable without an external socat shim.
When a proxy applies to the tunnel URL (HTTP_PROXY/HTTPS_PROXY/ALL_PROXY,
honoring NO_PROXY), the client now establishes an HTTP CONNECT tunnel through
it, optional TLS for wss://, and the WS handshake itself, then speaks RFC 6455
over the socket. This hand-rolled path is runtime-agnostic (net/tls/crypto), so
it behaves identically under Node and the compiled Bun binary; the direct dial
is unchanged. Adds a Docker Sandboxes guide.
proxy run --url now dials its tunnel through an HTTP proxy (HTTP(S)_PROXY/NO_PROXY), so a sandboxed agent whose only egress is a proxy gateway (e.g. Docker Sandboxes) can reach a broker
Copy file name to clipboardExpand all lines: packages/varlock-website/src/content/docs/guides/proxy/running.mdx
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -43,6 +43,8 @@ node agent.js # now routed through the proxy
43
43
44
44
The workload does not have to be on the same machine. `proxy start --expose` makes the proxy reachable off-loopback and serves a built-in WebSocket tunnel, gated by a per-session data-plane token, and `proxy run --url wss://<host>` runs a command through that broker from anywhere, self-wiring the placeholder env and CA certs over the tunnel. The token is a credential: pin it with `VARLOCK_PROXY_TOKEN` or read it back with `varlock proxy token`, and prefer passing it to clients as an env var rather than a `--token` argument. This is how cloud sandboxes reach a broker; see the [E2B](/sandboxes/e2b/) and [Fly.io](/sandboxes/flyio/) guides for full recipes and the [proxy CLI reference](/reference/cli/proxy/) for the flags.
45
45
46
+
When the guest's only egress is an explicit HTTP proxy (a corporate proxy, or a sandbox gateway like [Docker Sandboxes](/sandboxes/docker-sandboxes/)), `proxy run --url` dials the tunnel through it automatically: it honors `HTTP_PROXY` / `HTTPS_PROXY` / `ALL_PROXY` and `NO_PROXY` (a loopback or `NO_PROXY`-matched broker still dials direct). Only HTTP `CONNECT` proxies are supported, not SOCKS. The tunnel carries TLS end to end, so an intermediate proxy that terminates TLS only ever sees the encrypted tunnel.
47
+
46
48
## Sessions
47
49
48
50
Every `varlock proxy` command operates on a **session**: one running proxy with its own short id (printed by `proxy start`, listed by `proxy status`). You target a session in one of two ways:
description: Using varlock with Docker Sandboxes (sbx), so an agent in a local microVM routes through the varlock credential proxy and holds only placeholders.
4
+
---
5
+
6
+
[Docker Sandboxes](https://docs.docker.com/ai/sandboxes/) (the `sbx` CLI) runs agents in local microVMs. Each sandbox gets its own Docker daemon, filesystem, and network, and all egress is forced through a host-side gateway with a deny-by-default domain allowlist (`sbx policy`). That gateway is the seam varlock plugs into: point the agent at a varlock broker, allow the broker in policy, and the agent holds only [placeholders](/guides/proxy/rules/#placeholders) while varlock injects real secrets at the wire.
7
+
8
+
The recommended shape for local development is a **broker on your own machine**: secrets, resolver [plugins](/guides/plugins/), biometric unlock, and the interactive request log all stay on the host, and the sandbox reaches the broker through the sbx gateway. To share one broker across a fleet, run it on [infrastructure you operate](#remote-broker) and reach it at a public URL instead.
9
+
10
+
## How sbx egress works
11
+
12
+
Two facts about the gateway shape the setup:
13
+
14
+
-**Everything goes through the gateway.** Inside a sandbox, `HTTP_PROXY` / `HTTPS_PROXY` point at `gateway.docker.internal:3128`, the sbx CA is in the trust store, and non-allowed domains do not even resolve. `varlock proxy run --url`[honors those proxy env vars](/guides/proxy/running/#remote-proxy-start---expose--proxy-run---url) and dials its tunnel through the gateway automatically, so no shim is needed.
15
+
-**The gateway can reach a host-local service** when you allow it in policy. This is what makes a host broker reachable from the microVM.
16
+
17
+
## Broker on your machine
18
+
19
+
```
20
+
[sbx microVM] [your host]
21
+
varlock proxy run --url varlock proxy start --expose
└──▶ gateway.docker.internal:3128 ────┘ (allowed by sbx policy)
25
+
```
26
+
27
+
### 1. Schema
28
+
29
+
Mark the secrets your agent uses with [`@proxy(domain=...)`](/reference/item-decorators/#proxy) and give each an explicit [`@placeholder`](/reference/item-decorators/#placeholder):
Egress is permissive by default (unmatched hosts pass through untouched, which is fine because the agent holds only placeholders). To make the broker refuse anything without a rule, set [`@proxyConfig={egress="strict"}`](/guides/proxy/rules/#egress-modes) in the schema header.
38
+
39
+
### 2. Start the broker on the host
40
+
41
+
`--expose` binds off-loopback and serves the [tunnel](/guides/proxy/running/#remote-proxy-start---expose--proxy-run---url), minting a data-plane token. Pin the token so you can hand the same value to the agent:
42
+
43
+
```bash
44
+
export VARLOCK_PROXY_TOKEN=$(uuidgen)
45
+
varlock proxy start --expose --port 8080
46
+
```
47
+
48
+
### 3. Allow the broker in sbx policy
49
+
50
+
The gateway rewrites `host.docker.internal` to `localhost` before evaluating policy, so the rule that matches is for **`localhost`**, even though the agent connects to `host.docker.internal`:
51
+
52
+
```bash
53
+
sbx policy allow network "localhost:8080"
54
+
```
55
+
56
+
:::caution[sbx quirk]
57
+
Allowing `host.docker.internal:8080` does **not** work (and `sbx policy check` will misleadingly say it is allowed). Allow `localhost:8080`. This is a Docker Sandboxes behavior, not a varlock one.
58
+
:::
59
+
60
+
### 4. Run the agent through the broker
61
+
62
+
Install varlock in the sandbox, then wrap the agent command with `proxy run --url`. The agent connects to the broker at `host.docker.internal`, and varlock self-wires its placeholder env and CA certs over the tunnel:
63
+
64
+
```bash
65
+
# in a shell sandbox (sbx create shell . && sbx exec <name> -- ...):
66
+
curl -sSfL https://varlock.dev/install.sh | sh -s
67
+
68
+
VARLOCK_PROXY_TOKEN=$YOUR_TOKEN \
69
+
varlock proxy run --url ws://host.docker.internal:8080 -- your-agent-command
70
+
```
71
+
72
+
That is the whole path: the agent holds placeholders, the broker on your host injects real values only on verified TLS connections to hosts your schema allows, and every request is checked against your [`@proxy` rules](/guides/proxy/rules/#routing-rules) and recorded in the [audit log](/guides/proxy/running/#auditing).
73
+
74
+
:::note[Installing varlock in the sandbox]
75
+
The install script drops a self-contained binary and works on any template. Templates on Node 22.3+ (the `shell` template is) can instead `npm i -g varlock`, a lighter install. Baking varlock into a [custom template](https://docs.docker.com/ai/sandboxes/customize/) skips the per-sandbox install, which matters for a fleet. Pass the token via the environment (`sbx exec -e` or a template default), not on the command line, so it stays out of process listings.
76
+
:::
77
+
78
+
## Remote broker
79
+
80
+
To share one broker across machines or a fleet, run it on infrastructure you operate and expose it at a URL that carries WebSockets. Because sbx allows direct TLS to allowlisted domains, the agent reaches a public `wss://` broker directly (no gateway asymmetry), so you only allow the broker's domain:
81
+
82
+
```bash
83
+
sbx policy allow network "broker.example.com"
84
+
# in the sandbox:
85
+
VARLOCK_PROXY_TOKEN=$YOUR_TOKEN \
86
+
varlock proxy run --url wss://broker.example.com -- your-agent-command
87
+
```
88
+
89
+
The data-plane token gates the tunnel and the tunnel carries TLS end to end, so a public URL is safe and any intermediary only sees ciphertext. See the [topologies overview](/sandboxes/overview/#topologies) and the [E2B](/sandboxes/e2b/) / [Fly.io](/sandboxes/flyio/) guides for the same broker shape on cloud providers.
90
+
91
+
## varlock proxy vs sbx secrets
92
+
93
+
Docker Sandboxes ships its own credential injection (`sbx secret`): the gateway substitutes a stored keychain value into request headers for a matching host. It covers the basic case. Route through a varlock broker when you want:
94
+
95
+
-**Custody in your secret manager.** Secrets come from wherever you already keep them through [plugins](/guides/plugins/) (1Password, Vault, AWS, Doppler, ...) and stay in your custody, instead of being copied into another store.
96
+
-**One schema.** Your `.env.schema` describes every value, its type, and its routing in one declarative layer, legible to people and agents alike.
97
+
-**Response scrubbing.** varlock scans response bodies and redacts injected secret values, so an allowlisted endpoint that echoes a request header cannot hand the real secret back to the agent.
98
+
-**Policy and audit.** Match on path and method, [hot-reload](/guides/proxy/running/#editing-the-schema-while-a-session-is-running) the schema, and keep your own [audit log](/guides/proxy/running/#auditing).
99
+
100
+
The two compose: sbx provides microVM isolation and deny-by-default egress; the varlock broker provides custody, injection, and scrubbing.
101
+
102
+
## Trust model
103
+
104
+
The broker holds real secrets on whatever machine runs it. For a host broker in local development, that is your own machine, the same place the secrets already live. The agent's microVM never holds them: a compromised or prompt-injected agent yields placeholders and only the requests your rules and egress mode allow. Keep sbx policy tight (allow just the broker, plus whatever hosts the agent legitimately needs), and treat the data-plane token like any shared secret (rotate by restarting the broker with a new one).
Copy file name to clipboardExpand all lines: packages/varlock-website/src/content/docs/sandboxes/overview.mdx
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -28,6 +28,7 @@ Cloud sandbox providers run the agent in a remote VM, so the proxy is reached ov
28
28
<CardGrid>
29
29
<LinkCardtitle="E2B"href="/sandboxes/e2b/"description="Broker sandbox or tunnel to your machine; egress lockdown via network rules" />
30
30
<LinkCardtitle="Fly.io"href="/sandboxes/flyio/"description="Broker sprite or tunnel to your machine; egress lockdown via network policy" />
31
+
<LinkCardtitle="Docker Sandboxes"href="/sandboxes/docker-sandboxes/"description="Local microVMs (sbx); reach a host or remote broker through the gateway" />
31
32
</CardGrid>
32
33
33
34
## Local tools
@@ -41,4 +42,4 @@ Cloud sandbox providers run the agent in a remote VM, so the proxy is reached ov
41
42
<LinkCardtitle="MXC"href="/sandboxes/mxc/"description="Windows AppContainer (processcontainer). Windows 11" />
42
43
</CardGrid>
43
44
44
-
Tools that already broker credentials at the network boundary (Docker Sandboxes, microsandbox, Anthropic `srt` credential `mask`, and similar) are out of scope here. Use those on their own, or wait for varlock host bridging if you want varlock as the broker inside a microVM that cannot reach host loopback.
45
+
Some tools already broker credentials at their own network boundary (microsandbox, Anthropic `srt` credential `mask`, and similar). You can use those on their own; varlock adds schema-driven policy, response scrubbing, your own audit log, and custody in your secret manager on top. [Docker Sandboxes](/sandboxes/docker-sandboxes/) has such a gateway but also lets its policy reach a varlock broker, so it gets its own guide above (host broker or remote broker, with varlock as the injector).
0 commit comments