Tunnels and exposing services

A tunnel publishes a port on one of your hosts at a MIOSA-managed address. The host keeps dialing out to MIOSA; MIOSA routes inbound requests back down that session to your service.

An outbound management session and a publicly reachable application tunnel are different things. Connecting a host does not expose anything. A tunnel is an explicit, separate exposure with its own access policy.

Create a tunnel

miosa host tunnel new <host> --port 3000 --slug my-app-dev --access organization
miosa host tunnel list <host>
miosa host tunnel get <host> <tunnel>
miosa host tunnel rm <host> <tunnel> --yes
FlagMeaning
--port intPort on the host to expose
--slug stringAddress name (default: generated)
--access stringWho may open it: organization (default) or public

The same call over REST:

curl --fail-with-body -sS 
  -X POST "https://api.miosa.ai/api/v1/opencomputers/hosts/$HOST_ID/tunnels" 
  -H "Authorization: Bearer $MIOSA_API_KEY" 
  -H "Content-Type: application/json" 
  -d '{"target_port":3000,"auth_mode":"tenant_only","slug":"my-app-dev"}'
FieldTypeRequiredDescription
target_portintegerYesLocal port to expose, 1 to 65535
auth_modestringNopublic | tenant_only | password (default: tenant_only)
slugstringNoAddress name, 4 to 63 lowercase alphanumeric or hyphen characters
target_hoststringNoHost to dial from the agent (default: 127.0.0.1)
passwordstringNoRequired in practice when auth_mode is password; hashed, never returned
{
  "id": "tun_abc",
  "host_id": "host_abc123",
  "slug": "my-app-dev",
  "target_port": 3000,
  "auth_mode": "tenant_only",
  "public_url": "https://<public-host>/t/my-app-dev",
  "enabled": true,
  "created_at": "2026-01-01T00:00:00Z",
  "updated_at": "2026-01-01T00:00:00Z"
}

Use the returned public_url. Do not construct a hostname yourself: the routing domain is set per environment, so read it from the response instead of hardcoding one.

Change or disable a tunnel

miosa host tunnel new <host> --port 8080 --slug my-app-dev   # re-create with a new port or slug

Over REST, PATCH /api/v1/opencomputers/hosts/{id}/tunnels/{tunnel_id} changes a tunnel in place:

FieldTypeDescription
statestringactive, paused, or revoked
auth_modestringChange the access mode
target_hoststringChange the host the agent dials
slugstringChange the address name
rotate_slugbooleanGenerate a new slug
passwordstringSet a new password (re-hashed)

DELETE /api/v1/opencomputers/hosts/{id}/tunnels/{tunnel_id} returns 204 No Content and revokes the tunnel.

The response adds live counters you can use to check that traffic is flowing: state, custom_domain, request_count, lifetime_bytes_ingress, and lifetime_bytes_egress.

Access modes

ModeWho can open it
organizationMembers of your MIOSA organization only (CLI default)
tenant_onlyThe tenant that owns the host
publicAnyone with the URL (API default)

Expose a device port

miosa device expose publishes a port for any device kind, including a host:

miosa device expose <device> 3000

Use the typed miosa host tunnel command when you want the fuller surface - list, get, access mode, and slug control.

What a tunnel does not do

  • It does not change who owns the application. Your service still runs on your machine, under your process supervision.
  • It does not remove the need for the service to be listening. The tunnel reaches a port; it does not start anything.
  • It does not make the traffic private in transit beyond the transport MIOSA terminates. Set the access mode and the application’s own authentication to match the data you serve.
Was this page helpful?