# Networking & Previews

Proxy buffered HTTP requests into VM services with `httpRequest` and create time-limited, actor-only preview URLs (with configurable expiration, revocation, and CORS), all carried over one transport (the kernel socket table) that is loopback-only by default under a three-layer confinement model.

## Run an HTTP server in the VM

Guest code runs a normal Node HTTP server: it binds a loopback port inside the VM exactly like any Node process. Write the server file and spawn it.

examples/networking/client-run-server.ts:

```ts
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";

const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });
const agent = client.vm.getOrCreate("my-agent");

// Write a simple Node HTTP server and run it inside the VM. It binds a loopback
// port (3000) exactly like any normal Node process.
await agent.filesystem.writeFile(
  "/home/agentos/server.js",
  `const http = require("http");
http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "text/plain" });
  res.end("Hello from inside the VM");
}).listen(3000, () => console.log("listening on http://127.0.0.1:3000"));`,
);
const { pid } = await agent.process.spawn("node", ["/home/agentos/server.js"]);
console.log("server pid:", pid);
```

examples/networking/server.ts:

```ts
import { agentOS, setup } from "@rivet-dev/agentos";

const vm = agentOS({ software: [] });

export const registry = setup({ use: { vm } });
registry.start();
```

## Fetch from a VM service

With the HTTP server running in the VM (above), send requests to it with `httpRequest`, including custom methods, headers, and body.

examples/networking/client-fetch.ts:

```ts
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";

const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });
const agent = client.vm.getOrCreate("my-agent");

// Fetch from the VM service started above.
const response = await agent.network.httpRequest({ port: 3000, path: "/" });
console.log("Status:", response.status);
console.log("Body:", new TextDecoder().decode(response.body));
```

examples/networking/client-fetch-options.ts:

```ts
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";

const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });

const response = await client.vm.getOrCreate("my-agent").network.httpRequest({
  port: 3000,
  path: "/api/data",
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ key: "value" }),
});

console.log("Status:", response.status, response.statusText);
console.log("Headers:", response.headers);
console.log("Body:", new TextDecoder().decode(response.body));
```

examples/networking/server.ts:

```ts
import { agentOS, setup } from "@rivet-dev/agentos";

const vm = agentOS({ software: [] });

export const registry = setup({ use: { vm } });
registry.start();
```

## Preview URLs

Preview URLs are port forwarding for VM services: a time-limited, public URL that proxies HTTP to a port inside the VM, for browser or external access (use `httpRequest` for server-to-server). Preview creation is intentionally actor-only through the native `createPreviewUrl` and `expirePreviewUrl` actions; tokens survive sleep/wake and CORS is enabled. See [Security](/agentos/docs/security-model) for details.

### Create a preview URL

Token lifetimes are configured under the `preview` key:

examples/networking/server-preview.ts:

```ts
import { agentOS, setup } from "@rivet-dev/agentos";

const vm = agentOS({
  software: [],
  preview: {
    defaultExpiresInSeconds: 3600, // 1 hour default
    maxExpiresInSeconds: 86400, // 24 hour maximum
  },
});

export const registry = setup({ use: { vm } });
registry.start();
```

examples/networking/client-preview.ts:

```ts
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";

const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });
const agent = client.vm.getOrCreate("my-agent");

// Start a web app in the VM
await agent.process.spawn("node", ["/home/agentos/app.js"]);

// Create a preview URL for port 3000, valid for 1 hour
const preview = await agent.createPreviewUrl(3000, 3600);
console.log("Preview path:", preview.path);
console.log("Token:", preview.token);
console.log("Expires at:", new Date(preview.expiresAt));

// Create a preview URL with a shorter expiration
const shortPreview = await agent.createPreviewUrl(3000, 300); // 5 minutes
console.log("Short-lived preview:", shortPreview.path);
```

### Revoke a preview URL

Mint short-lived preview tokens so access expires automatically; the lifetime is capped by `preview.maxExpiresInSeconds`.

examples/networking/client-revoke.ts:

```ts
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";

const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });

// Mint a short-lived preview token so access expires automatically.
const agent = client.vm.getOrCreate("my-agent");
const preview = await agent.createPreviewUrl(3000, 300); // 5 minutes
console.log("Preview path:", preview.path);
console.log("Expires at:", new Date(preview.expiresAt));
```

examples/networking/server.ts:

```ts
import { agentOS, setup } from "@rivet-dev/agentos";

const vm = agentOS({ software: [] });

export const registry = setup({ use: { vm } });
registry.start();
```

## Permissions

Network access is governed by the VM permission policy. By default the guest cannot reach the network; grant it, or allow only specific destinations:

```ts
const vm = agentOS({
  permissions: {
    network: {
      default: "deny",
      rules: [{ mode: "allow", operations: ["*"], patterns: ["api.example.com"] }],
    },
  },
});
```

See [Permissions](/agentos/docs/permissions) for the full configuration.
