Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 66 additions & 1 deletion docs/roo-code-cloud/environments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ keywords:
- mise
- Initial Path
- Subdomain Routing
- Proxied Ports
- Direct Port Access
---

# Preview Environments
Expand Down Expand Up @@ -91,6 +93,8 @@ ports:
|-------|-------------|----------|
| `name` | Identifier for the port (used to generate environment variables) | Yes |
| `port` | The port number to expose | Yes |
| `unauthenticated` | Skip authentication for this port's preview URL (`false` by default). See [Public Ports](#public-ports-unauthenticated) | No |
| `proxied` | Whether traffic goes through the auth proxy (`true` by default). Set to `false` for direct port access (see [Direct Port Access](#direct-port-access-non-proxied)) | No |
| `initial_path` | Default path to append to the preview URL | No |
| `subdomain` | Subdomain to set on the `Host` header when forwarding requests to the app | No |

Expand All @@ -113,7 +117,10 @@ The name is converted to uppercase for the environment variable (e.g., `web` bec

### Limits

You can configure up to **4 named ports** per environment.
Port limits depend on whether ports are proxied (default) or non-proxied:

- **Proxied ports** (default): up to **10** per environment. These share a single internal port slot via multiplexing.
- **Non-proxied ports** (`proxied: false`): up to **1** per environment. Each non-proxied port consumes a dedicated port slot.

### Initial Path

Expand Down Expand Up @@ -189,6 +196,64 @@ Invalid examples:
- **Admin panels**: Serve an admin interface on `admin.localhost:3000` while the main app runs on the root domain
- **Subdomain APIs**: Frameworks like Rails can use `api.localhost:3000` to route API requests to a separate controller namespace

### Public Ports (Unauthenticated)

By default, all preview URLs require authentication -- visitors must be signed in to your Roo Code Cloud organization to access them. Setting `unauthenticated: true` on a port disables this auth check while keeping the proxy layer intact.

```yaml
ports:
- name: WEB
port: 3000
- name: API
port: 3001
unauthenticated: true
- name: WEBHOOK
port: 3002
unauthenticated: true
```

Use `unauthenticated: true` when you need:

- **API endpoints** that your frontend or external clients call directly (the auth proxy would otherwise block non-browser requests)
- **Webhook receivers** that need to accept requests from external services (e.g., Stripe, GitHub)
- **Public-facing endpoints** like documentation sites or landing pages
- **Health checks** or status pages accessed by monitoring tools

The port still goes through the proxy, so it benefits from HTTPS termination and domain routing. Only the authentication requirement is removed.

### Direct Port Access (Non-Proxied)

By default, all ports are proxied through an authentication layer that validates requests before forwarding them to your application. Setting `proxied: false` bypasses this proxy entirely and exposes the port directly on the sandbox domain.

:::tip[Try `unauthenticated: true` first]
If you just need to skip authentication (e.g., for a public-facing endpoint or webhook), use `unauthenticated: true` instead. It keeps the proxy in place while disabling the auth check, and doesn't count against the stricter non-proxied port limit. Only reach for `proxied: false` when the proxy itself is the problem.
:::

```yaml
ports:
- name: WEB
port: 3000
- name: METRICS
port: 9090
proxied: false
```

Use `proxied: false` only when the proxy layer itself is incompatible with your use case:

- **WebSocket or streaming connections** that are disrupted by the proxy intermediary
- **Services with custom connection handling** that conflict with the proxy's request processing

:::warning[Warning]
When `proxied` is `false`, the port is **completely exposed without authentication**, regardless of the `unauthenticated` setting. Non-proxied ports also count against a stricter limit (1 per environment vs. 10 for proxied ports). Only use this as a last resort when other options don't work.
:::

The `ROO_<NAME>_HOST` environment variable for a non-proxied port points to the direct sandbox domain instead of the preview proxy URL. Your application code doesn't need to change -- just use the injected variable as usual:

```typescript
// Works the same whether the port is proxied or not
const metricsUrl = process.env.ROO_METRICS_HOST || 'http://localhost:9090';
```

## Using Environment Variables in Your Code

Use the `ROO_<NAME>_HOST` variables instead of hardcoded URLs so your services can find each other in both preview and local environments:
Expand Down