Skip to content

Commit 1c323c7

Browse files
authored
Document private browser networking (#500)
* Document private browser networking * Keep private host disable behavior SDK-only
1 parent 2b9371d commit 1c323c7

4 files changed

Lines changed: 181 additions & 2 deletions

File tree

browsers/pools.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: "Browser Pools"
33
description: "Configure a pool of ready-to-use browsers for instant acquisition"
44
---
55

6-
A browser pool is a fixed set of identical browsers that Kernel keeps running for you. Configure it once — stealth, proxies, extensions, viewport, a [profile](#profiles-with-browser-pools) — then acquire a browser whenever a task needs one and release it when you're done.
6+
A browser pool is a fixed set of identical browsers that Kernel keeps running for you. Configure it once — stealth, proxies, [private networking](/browsers/private-networking), extensions, viewport, a [profile](#profiles-with-browser-pools) — then acquire a browser whenever a task needs one and release it when you're done.
77

88
Acquiring is faster than creating an on-demand browser because the browser is already running: you skip start-up, including the [Chromium restart](/browsers/performance#troubleshooting-latency) that some settings trigger, and you aren't subject to the [rate limit](/info/pricing#rate-limiting) on browser creation.
99

browsers/private-networking.mdx

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
---
2+
title: "Private Networking"
3+
description: "Route browser traffic to private services through a VPN or tunnel in the browser session"
4+
---
5+
6+
Use `network.private_hosts` when a browser session joins a VPN or tunnel and must reach private services through that connection. Matching destinations bypass Kernel-managed egress and use the session's network routes and DNS instead.
7+
8+
This is useful for services reachable through Tailscale, a corporate VPN, or another tunnel running inside the browser session.
9+
10+
<Info>
11+
`network.private_hosts` is different from a proxy's [`bypass_hosts`](/proxies/overview#bypass-hosts). Proxy bypass rules choose between your upstream proxy and Kernel-managed direct egress. Private hosts bypass Kernel-managed egress so traffic can follow routes inside the browser session, including VPN and tunnel routes.
12+
</Info>
13+
14+
## Configure a browser
15+
16+
Set private hosts when you create the browser. You can't change the network configuration after creation.
17+
18+
<CodeGroup>
19+
```typescript TypeScript
20+
import Kernel from '@onkernel/sdk';
21+
22+
const kernel = new Kernel();
23+
24+
const browser = await kernel.browsers.create({
25+
network: {
26+
private_hosts: [
27+
'*.services.example.ts.net',
28+
'100.64.0.0/10',
29+
],
30+
},
31+
});
32+
33+
console.log(browser.session_id);
34+
```
35+
36+
```python Python
37+
from kernel import Kernel
38+
39+
kernel = Kernel()
40+
41+
browser = kernel.browsers.create(
42+
network={
43+
"private_hosts": [
44+
"*.services.example.ts.net",
45+
"100.64.0.0/10",
46+
]
47+
}
48+
)
49+
50+
print(browser.session_id)
51+
```
52+
53+
```go Go
54+
package main
55+
56+
import (
57+
"context"
58+
"fmt"
59+
60+
"github.com/kernel/kernel-go-sdk"
61+
)
62+
63+
func main() {
64+
client := kernel.NewClient()
65+
66+
browser, err := client.Browsers.New(context.Background(), kernel.BrowserNewParams{
67+
Network: kernel.BrowserNetworkConfigParam{
68+
PrivateHosts: []string{
69+
"*.services.example.ts.net",
70+
"100.64.0.0/10",
71+
},
72+
},
73+
})
74+
if err != nil {
75+
panic(err)
76+
}
77+
78+
fmt.Println(browser.SessionID)
79+
}
80+
```
81+
82+
```bash CLI
83+
kernel browsers create \
84+
--private-host '*.services.example.ts.net' \
85+
--private-host '100.64.0.0/10'
86+
```
87+
</CodeGroup>
88+
89+
## Default private routes
90+
91+
When you omit `network.private_hosts`, Kernel routes these private IP ranges through the session network by default:
92+
93+
- RFC1918: `10.0.0.0/8`, `172.16.0.0/12`, and `192.168.0.0/16`
94+
- CGNAT and Tailscale: `100.64.0.0/10`
95+
- IPv6 unique local addresses: `fc00::/7`
96+
97+
These CIDR rules only match URLs that use literal IP addresses. They don't match a hostname after DNS resolution. Add private DNS names explicitly, even when they resolve to an address in a default range:
98+
99+
```json
100+
{
101+
"network": {
102+
"private_hosts": ["api.services.example.ts.net"]
103+
}
104+
}
105+
```
106+
107+
<Warning>
108+
Providing `private_hosts` replaces the default list; it doesn't add to it. Include any default CIDRs you still need alongside your hostname rules.
109+
</Warning>
110+
111+
To disable direct private routing and send all traffic through Kernel-managed egress, provide an explicit empty list:
112+
113+
<CodeGroup>
114+
```typescript TypeScript
115+
const browser = await kernel.browsers.create({
116+
network: { private_hosts: [] },
117+
});
118+
```
119+
120+
```python Python
121+
browser = kernel.browsers.create(
122+
network={"private_hosts": []}
123+
)
124+
```
125+
</CodeGroup>
126+
127+
## Supported entries
128+
129+
You can provide up to 32 entries, each no longer than 255 characters:
130+
131+
- Exact hostnames: `api.services.example.ts.net`
132+
- A single leading wildcard: `*.services.example.ts.net`
133+
- Private IPv4 addresses: `10.1.30.63`
134+
- Bracketed private IPv6 addresses: `[fd00::1]`
135+
- Canonical private CIDRs: `100.64.0.0/10` or `fd00::/8`
136+
- Hostnames or exact IP addresses with ports: `api.services.example.ts.net:8443`
137+
138+
Kernel rejects public IP ranges, loopback and link-local ranges, URL schemes, paths, catch-all wildcards, ports on CIDRs, and non-canonical CIDRs. Hostnames aren't resolved during validation, so only add names that identify private destinations.
139+
140+
## Configure a browser pool
141+
142+
Put the network configuration on a browser pool when every browser in the pool needs the same private routes.
143+
144+
<CodeGroup>
145+
```typescript TypeScript
146+
const pool = await kernel.browserPools.create({
147+
name: 'private-services',
148+
size: 5,
149+
network: {
150+
private_hosts: ['*.services.example.ts.net'],
151+
},
152+
});
153+
```
154+
155+
```python Python
156+
pool = kernel.browser_pools.create(
157+
name="private-services",
158+
size=5,
159+
network={
160+
"private_hosts": ["*.services.example.ts.net"],
161+
},
162+
)
163+
```
164+
165+
```bash CLI
166+
kernel browser-pools create private-services \
167+
--size 5 \
168+
--private-host '*.services.example.ts.net'
169+
```
170+
</CodeGroup>
171+
172+
A browser-pool update applies only to browsers created after the update. Pass `discard_all_idle: true` in an SDK request, or `--discard-all-idle` in the CLI, to immediately replace idle browsers with the new configuration. Acquired browsers keep their original configuration until you release them with reuse disabled.
173+
174+
Use `kernel browser-pools update private-services --clear-private-hosts --discard-all-idle` to remove a pool override and restore the default private IP ranges. To configure an explicit empty list, use an SDK request with `network.private_hosts: []`.

docs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
]
160160
},
161161
"browsers/extensions",
162+
"browsers/private-networking",
162163
"browsers/chrome-policies",
163164
{
164165
"group": "Telemetry",

proxies/overview.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,11 @@ For ISP and datacenter proxies the exit IP is stable, so a successful check agai
241241

242242
## Bypass hosts
243243

244-
Configure specific hostnames to bypass the proxy and connect directly. This is useful for accessing internal services, metadata endpoints, or reducing latency for trusted domains.
244+
Configure specific hostnames to bypass the proxy and connect through Kernel-managed direct egress. This is useful for metadata endpoints or reducing latency for trusted domains.
245+
246+
<Note>
247+
To reach a private service through a VPN or tunnel inside the browser session, use [`network.private_hosts`](/browsers/private-networking) instead. Proxy bypass rules don't route traffic into the session's private network.
248+
</Note>
245249

246250
<CodeGroup>
247251
```typescript Typescript/Javascript

0 commit comments

Comments
 (0)