-
Notifications
You must be signed in to change notification settings - Fork 9
Document private browser networking #500
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| --- | ||
| title: "Private Networking" | ||
| description: "Route browser traffic to private services through a VPN or tunnel in the browser session" | ||
| --- | ||
|
|
||
| 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. | ||
|
|
||
| This is useful for services reachable through Tailscale, a corporate VPN, or another tunnel running inside the browser session. | ||
|
|
||
| <Info> | ||
| `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. | ||
| </Info> | ||
|
|
||
| ## Configure a browser | ||
|
|
||
| Set private hosts when you create the browser. You can't change the network configuration after creation. | ||
|
|
||
| <CodeGroup> | ||
| ```typescript TypeScript | ||
| import Kernel from '@onkernel/sdk'; | ||
|
|
||
| const kernel = new Kernel(); | ||
|
|
||
| const browser = await kernel.browsers.create({ | ||
| network: { | ||
| private_hosts: [ | ||
| '*.services.example.ts.net', | ||
| '100.64.0.0/10', | ||
| ], | ||
| }, | ||
| }); | ||
|
|
||
| console.log(browser.session_id); | ||
| ``` | ||
|
|
||
| ```python Python | ||
| from kernel import Kernel | ||
|
|
||
| kernel = Kernel() | ||
|
|
||
| browser = kernel.browsers.create( | ||
| network={ | ||
| "private_hosts": [ | ||
| "*.services.example.ts.net", | ||
| "100.64.0.0/10", | ||
| ] | ||
| } | ||
| ) | ||
|
|
||
| print(browser.session_id) | ||
| ``` | ||
|
|
||
| ```go Go | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
|
|
||
| "github.com/kernel/kernel-go-sdk" | ||
| ) | ||
|
|
||
| func main() { | ||
| client := kernel.NewClient() | ||
|
|
||
| browser, err := client.Browsers.New(context.Background(), kernel.BrowserNewParams{ | ||
| Network: kernel.BrowserNetworkConfigParam{ | ||
| PrivateHosts: []string{ | ||
| "*.services.example.ts.net", | ||
| "100.64.0.0/10", | ||
| }, | ||
| }, | ||
| }) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
|
|
||
| fmt.Println(browser.SessionID) | ||
| } | ||
| ``` | ||
|
|
||
| ```bash CLI | ||
| kernel browsers create \ | ||
| --private-host '*.services.example.ts.net' \ | ||
| --private-host '100.64.0.0/10' | ||
| ``` | ||
| </CodeGroup> | ||
|
|
||
| ## Default private routes | ||
|
|
||
| When you omit `network.private_hosts`, Kernel routes these private IP ranges through the session network by default: | ||
|
|
||
| - RFC1918: `10.0.0.0/8`, `172.16.0.0/12`, and `192.168.0.0/16` | ||
| - CGNAT and Tailscale: `100.64.0.0/10` | ||
| - IPv6 unique local addresses: `fc00::/7` | ||
|
|
||
| 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: | ||
|
|
||
| ```json | ||
| { | ||
| "network": { | ||
| "private_hosts": ["api.services.example.ts.net"] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| <Warning> | ||
| Providing `private_hosts` replaces the default list; it doesn't add to it. Include any default CIDRs you still need alongside your hostname rules. | ||
| </Warning> | ||
|
|
||
| To disable direct private routing and send all traffic through Kernel-managed egress, provide an explicit empty list: | ||
|
|
||
| <CodeGroup> | ||
| ```typescript TypeScript | ||
| const browser = await kernel.browsers.create({ | ||
| network: { private_hosts: [] }, | ||
| }); | ||
| ``` | ||
|
|
||
| ```python Python | ||
| browser = kernel.browsers.create( | ||
| network={"private_hosts": []} | ||
| ) | ||
| ``` | ||
| </CodeGroup> | ||
|
|
||
| ## Supported entries | ||
|
|
||
| You can provide up to 32 entries, each no longer than 255 characters: | ||
|
|
||
| - Exact hostnames: `api.services.example.ts.net` | ||
| - A single leading wildcard: `*.services.example.ts.net` | ||
| - Private IPv4 addresses: `10.1.30.63` | ||
| - Bracketed private IPv6 addresses: `[fd00::1]` | ||
| - Canonical private CIDRs: `100.64.0.0/10` or `fd00::/8` | ||
| - Hostnames or exact IP addresses with ports: `api.services.example.ts.net:8443` | ||
|
|
||
| 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. | ||
|
|
||
| ## Configure a browser pool | ||
|
|
||
| Put the network configuration on a browser pool when every browser in the pool needs the same private routes. | ||
|
|
||
| <CodeGroup> | ||
| ```typescript TypeScript | ||
| const pool = await kernel.browserPools.create({ | ||
| name: 'private-services', | ||
| size: 5, | ||
| network: { | ||
| private_hosts: ['*.services.example.ts.net'], | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ```python Python | ||
| pool = kernel.browser_pools.create( | ||
| name="private-services", | ||
| size=5, | ||
| network={ | ||
| "private_hosts": ["*.services.example.ts.net"], | ||
| }, | ||
| ) | ||
| ``` | ||
|
|
||
| ```bash CLI | ||
| kernel browser-pools create private-services \ | ||
| --size 5 \ | ||
| --private-host '*.services.example.ts.net' | ||
| ``` | ||
| </CodeGroup> | ||
|
|
||
| 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. | ||
|
|
||
| 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: []`. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.