LogoFreestyle

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-sandboxes

Usage

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)
OptionTypeDefaultDescription
idstringRequiredUnique identifier for the terminal
portnumberAuto (7682+)Port for ttyd to listen on
commandstring"bash -l"Shell or command to execute
cwdstring"/root"Working directory
credentialobjectundefinedBasic auth credentials
titlestringTerminal IDBrowser tab title
readOnlybooleanfalseDisable 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:

OptionTypeDescription
domainstringDomain 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"
});

On this page

Freestyle AI

Documentation assistant

Experimental: AI responses may not always be accurate—please verify important details with the official documentation.

How can I help?

Ask me about Freestyle while you browse the docs.