Web Terminal
Add interactive web-based terminals to your VMs.
The Web Terminal integration installs ttyd, a terminal sharing tool, and provides helper methods for exposing terminals via public URLs.
Installation
npm install @freestyle-sh/with-web-terminal freestyle-sandboxesUsage
import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmWebTerminal } from "@freestyle-sh/with-web-terminal";
const { vm } = await freestyle.vms.create({
spec: new VmSpec({
with: {
terminal: new VmWebTerminal([
{ id: "main" }
] as const),
},
}),
});
// Expose the terminal on a public domain
await vm.terminal.main.route({
domain: "my-terminal.style.dev"
});Use as const when defining terminals to enable type-safe access to terminal IDs like vm.terminal.main.
Options
Each terminal in the array accepts the following options:
new VmWebTerminal([
{
id: "main", // Required: unique identifier
port: 7682, // Optional: port for ttyd (auto-assigned by default)
command: "bash -l", // Optional: shell or command to run
cwd: "/root", // Optional: working directory
credential: { // Optional: basic auth
username: "admin",
password: "secret"
},
title: "My Terminal", // Optional: browser tab title
readOnly: false, // Optional: disable input
}
] as const)| Option | Type | Default | Description |
|---|---|---|---|
id | string | Required | Unique identifier for the terminal |
port | number | Auto (7682+) | Port for ttyd to listen on |
command | string | "bash -l" | Shell or command to execute |
cwd | string | "/root" | Working directory |
credential | object | undefined | Basic auth credentials |
title | string | Terminal ID | Browser tab title |
readOnly | boolean | false | Disable input (display-only) |
API
vm.terminal.[id].route({ domain })
Exposes the terminal on a public domain.
await vm.terminal.main.route({
domain: "my-terminal.style.dev"
});Parameters:
| Option | Type | Description |
|---|---|---|
domain | string | Domain to route the terminal to |
Returns: Promise<void>
Terminal Properties
Each terminal instance has the following properties:
vm.terminal.main.id // "main"
vm.terminal.main.port // 7682
vm.terminal.main.command // "bash -l"Example: Multiple Terminals
Create multiple terminals with different configurations:
import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmWebTerminal } from "@freestyle-sh/with-web-terminal";
const { vm } = await freestyle.vms.create({
spec: new VmSpec({
with: {
terminal: new VmWebTerminal([
{ id: "public" },
{ id: "admin", credential: { username: "admin", password: "secret" } }
] as const),
},
}),
});
const id = crypto.randomUUID();
// Public terminal (no auth)
await vm.terminal.public.route({
domain: `${id}-public.style.dev`
});
// Protected terminal (requires login)
await vm.terminal.admin.route({
domain: `${id}-admin.style.dev`
});Example: Read-Only Display
Create a terminal that displays output but doesn't accept input:
import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmWebTerminal } from "@freestyle-sh/with-web-terminal";
const { vm } = await freestyle.vms.create({
spec: new VmSpec({
with: {
terminal: new VmWebTerminal([
{
id: "logs",
command: "tail -f /var/log/syslog",
readOnly: true,
}
] as const),
},
}),
});
await vm.terminal.logs.route({
domain: "logs.style.dev"
});Example: Custom Command
Run a specific command instead of a shell:
import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmWebTerminal } from "@freestyle-sh/with-web-terminal";
const { vm } = await freestyle.vms.create({
spec: new VmSpec({
with: {
terminal: new VmWebTerminal([
{
id: "app",
command: "bash -lc 'cd /app && npm start'",
}
] as const),
},
}),
});
await vm.terminal.app.route({
domain: "app-terminal.style.dev"
});