Workspace Networking
Oblien workspaces run as isolated microVMs. Each VM gets its own virtual network interface and private IP on the 10.x.x.x internal network. By default, no workspace can reach any other workspace - even within the same account. Network paths must be explicitly opened.
This page explains the isolation model, how to connect workspaces, and when direct VM-to-VM communication is useful.
Network isolation by default
Every workspace starts network-dark on the inbound side:
| Setting | Default | Effect |
|---|---|---|
ingress | [] | No inbound sources allowed |
ingress_ports | [] | No inbound ports open |
public_access | false | Gateway/internet cannot reach the VM |
allow_internet | true | Outbound internet is allowed |
egress | [] | Unrestricted outbound (when internet is on) |
This means a freshly created workspace can make outbound requests to the internet (install packages, call external APIs), but nothing can connect to it - not the gateway, not other workspaces, not even workspaces owned by the same account.
Inbound access requires explicit configuration:
- Gateway access (external) → enable
public_access: true+ open port - Workspace-to-workspace (internal) → create a private link + open port
How the firewall works
Each VM has a per-workspace firewall enforced at the host level. The firewall controls:
Ingress (inbound)
Traffic is dropped unless all of the following match:
- Source is in the
ingresslist - either a specific IP, a CIDR range, or thehostkeyword (set automatically whenpublic_access: true) - Port is in the
ingress_portslist - only ports you explicitly open are reachable
If either condition fails, the connection is dropped. The workspace is invisible to the caller.
Egress (outbound)
When allow_internet is true:
- All outbound traffic is allowed by default
- If
egresscontains entries, only those hosts are reachable - DNS resolution still works regardless of egress rules
When allow_internet is false:
- All outbound traffic is blocked
- The workspace cannot reach the internet, other workspaces, or any external service
- Internal-only workspaces that need to be called must receive inbound links instead
Workspace-to-workspace communication
When workspace A needs to call workspace B (run commands, read files, query an API), you set up a private link from A to B. This is a directed network rule - it tells B's firewall to accept connections from A's IP.
Setup flow
1. Enable the internal server on workspace B
2. Create a private link: A → B (on B's network config)
3. Get B's raw connection token and private IP
4. From inside A, call B directly at http://10.x.x.x:9990What happens at each step
Step 1 - Enable the server on workspace B. This starts the HTTP server on port 9990 inside B's VM and automatically opens port 9990 in B's ingress_ports.
await ws.apiAccess.enable('ws_b');Step 2 - Create a private link. Add workspace A's ID to B's private_link_ids. The platform resolves A's workspace ID to its internal IP and adds it to B's firewall ingress list.
await ws.network.update('ws_b', {
private_link_ids: ['ws_a'],
});Step 3 - Get the connection details. Retrieve B's raw token and private IP so A can authenticate.
const raw = await ws.apiAccess.rawToken('ws_b');
// raw.token = "a1b2c3d4e5f6..."
// raw.ip = "10.40.0.12"
// raw.port = 9990Step 4 - Call from inside A. Code running inside workspace A can now reach B directly over the private network.
// Running inside workspace A
const res = await fetch('http://10.40.0.12:9990/exec', {
method: 'POST',
headers: {
'Authorization': `Bearer ${raw.token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ cmd: ['npm', 'test'] }),
});What's protected
| Layer | Protection |
|---|---|
| Network | Firewall drops traffic unless source IP is in ingress and port is in ingress_ports |
| Authentication | Every request requires Authorization: Bearer <token> - even on the private network |
| Direction | Links are one-directional. A → B does not imply B → A |
| Isolation | VMs run in separate KVM instances. No shared memory, filesystem, or process space |
| Resolution | You send workspace IDs, not raw IPs. The platform resolves and configures the firewall automatically |
Links are one-directional
Adding ws_a to B's private_link_ids means A can reach B. It does not mean B can reach A. If you need bidirectional communication, create links in both directions:
// A can reach B
await ws.network.update('ws_b', { private_link_ids: ['ws_a'] });
// B can reach A
await ws.network.update('ws_a', { private_link_ids: ['ws_b'] });Multiple links
A workspace can receive connections from multiple sources:
await ws.network.update('ws_target', {
private_link_ids: ['ws_agent_1', 'ws_agent_2', 'ws_orchestrator'],
});The firewall adds all resolved IPs to the ingress list. Any of them can reach the target.
When to use workspace-to-workspace
Agent orchestration
An orchestrator workspace delegates tasks to worker workspaces. Each worker runs in its own isolated VM - a task crash or resource exhaustion doesn't affect the orchestrator or other workers.
Orchestrator (ws_orch)
├── Worker A (ws_a) - running tests
├── Worker B (ws_b) - building container
└── Worker C (ws_c) - deployingThe orchestrator creates private links to each worker, sends commands via the Exec API, and streams output via SSE.
Microservice testing
Spin up separate workspaces for frontend, backend, and database. Link them together and test the full stack with real network boundaries - not localhost aliases.
Multi-tenant isolation
Give each tenant their own workspace. A central service workspace connects to each tenant's workspace on demand, runs operations, and disconnects. Tenants never see each other's IPs or data.
CI/CD pipeline stages
Each pipeline stage runs in a separate workspace. The pipeline controller workspace links to each stage, pushes code, runs builds, and collects artifacts - each stage is fully isolated and disposable.
Gateway vs. direct - when to use which
Gateway (workspace.oblien.com) | Direct (10.x.x.x:9990) | |
|---|---|---|
| From | Anywhere on the internet | Inside another workspace |
| Latency | Higher (gateway decodes JWT, routes to VM) | Lower (direct TCP, no intermediary) |
| Auth | Gateway JWT (signed, contains routing info) | Raw connection token (simple hex string) |
| Network requirement | public_access: true on target | Private link from caller to target |
| Use case | External apps, SDK, CI/CD, MCP servers | Workspace-to-workspace orchestration |
| IP exposure | Never - JWT embeds the IP internally | You get the IP from the raw token endpoint |
Use the gateway when calling from outside the Oblien network (your app, CI pipeline, local development). Use direct connections when calling from inside another workspace for lower latency and no gateway overhead.
Further reading
- Network API - Configure firewall rules and private links
- API Access - Enable the internal server and manage tokens
- Internal API - Use the workspace runtime APIs (files, exec, terminal, search)
- Security & Privacy - Full isolation model, encryption, and operational security