VM Networking
Oblien VMs 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 VM can reach any other VM - even within the same account. Network paths must be explicitly opened.
This page explains the isolation model, how to connect VMs, and when direct VM-to-VM communication is useful.
Network isolation by default
Every VM 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 VM can make outbound requests to the internet (install packages, call external APIs), but nothing can connect to it - not the gateway, not other VMs, not even VMs owned by the same account.
Inbound access requires explicit configuration:
- Gateway access (external) → enable
public_access: true+ open port - VM-to-VM (internal) → create a private link + open port
How the firewall works
Each VM has a per-VM 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 VM 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 VM cannot reach the internet, other VMs, or any external service
- Internal-only VMs that need to be called must receive inbound links instead
VM-to-VM communication
When VM A needs to call VM 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 vm 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 VM 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 VM A's ID to B's private_link_ids. The platform resolves A's VM 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 VM A can now reach B directly over the private network.
// Running inside vm 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 VM 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 VM 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 VM-to-VM
Agent orchestration
An orchestrator VM delegates tasks to worker VMs. Each worker runs in its own isolated VM - a task crash or resource exhaustion doesn't affect the orchestrator or other workers.
The orchestrator creates private links to each worker, sends commands via the Exec API, and streams output via SSE.
Microservice testing
Spin up separate VMs 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 VM. A central service VM connects to each tenant's VM 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 VM. The pipeline controller VM 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 (vm.oblien.com) | Direct (10.x.x.x:9990) | |
|---|---|---|
| From | Anywhere on the internet | Inside another VM |
| 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 | VM-to-VM 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 VM 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
- Runtime API - Use the VM runtime APIs (files, exec, terminal, search)
- Security & Privacy - Full isolation model, encryption, and operational security