# Dev Servers

Previews, user-written request handlers, and generated web apps all need code
that keeps running and answers requests. Secure Exec runs that server inside a
VM and lets your backend talk to it, without opening a port on the host.

## Start the server

secure-exec/examples/dev-server/src/index.ts:

```ts
import { createVm } from "secure-exec";

// The server is user-authored code, so it runs in a VM. Guest listeners stay on
// the VM's virtual network and do not need external network access.
const vm = await createVm();

// `spawn` returns as soon as the process starts, instead of waiting for the
// code to finish. The server prints a line once it is listening, so the host
// knows when it can send requests.
const ready = Promise.withResolvers<void>();
const decoder = new TextDecoder();
const server = await vm.javascript.spawn(
	`
	import { createServer } from "node:http";

	createServer((request, response) => {
		response.setHeader("content-type", "application/json");
		response.end(JSON.stringify({ path: request.url, pid: process.pid }));
	}).listen(3000, () => console.log("listening"));
	`,
	{
		onStdout: (chunk) => {
			if (decoder.decode(chunk).includes("listening")) ready.resolve();
		},
	},
);
console.log("server pid:", server.pid);
await ready.promise;
```

## Proxy requests to it

Forward requests from your own route to the guest, and return what it answers.

secure-exec/examples/dev-server/src/index.ts:

```ts
// Send requests from the host to the port inside the VM. Nothing is exposed on
// the host's own network.
const response = await vm.network.httpRequest({ port: 3000, path: "/hello" });
console.log(new TextDecoder().decode(response.body)); // {"path":"/hello","pid":...}
```

- **No host port.** The server listens on the VM's virtual network. Only your
  process can reach it, through `vm.network.httpRequest`.
- **One VM per preview.** Each preview gets its own filesystem and
  [limits](/secure-exec/docs/resource-limits).
- **Bring a project.** Write files with `vm.filesystem`, install
  dependencies with [npm](/secure-exec/docs/npm), then spawn the entry point.

## Stop it

secure-exec/examples/dev-server/src/index.ts:

```ts
// Stop the server, then dispose the VM.
await vm.process.kill(server.pid);
const exit = await vm.process.wait(server.pid);
console.log("server exited:", exit);
await vm.dispose();
```

Read more in [Long-Running Processes](/secure-exec/docs/long-running-code).
