---
title: Port Forwarding for Web Apps
description: "Expose dev servers from sandboxes and share preview URLs with your team."
---

# Port Forwarding for Web Apps

When an agent builds a web app inside a sandbox, Caged automatically detects the running server and provides a public preview URL. This recipe shows how to use it for development, demos, and reviews.

## Prerequisites

- Caged CLI installed
- A running sandbox with a web app

## Basic: Agent Builds and Previews a Web App

```bash
# Create sandbox with a Next.js project
caged up --template node-20 --repo https://github.com/your-org/web-app

# Let the agent build and start the dev server
caged exec cage-a1b2c3d4 "npm install && npm run dev"

# Check detected ports
caged ports cage-a1b2c3d4
```

Output:

```
PORT   PROTOCOL   PREVIEW URL                                        PROTECTED
3000   http       https://cage-a1b2c3d4-3000.preview.caged.dev      no
```

Open `https://cage-a1b2c3d4-3000.preview.caged.dev` in your browser to see the app live.

## Agent-Driven UI Development

Tell the agent to build a UI and verify it via the preview:

```yaml
# .caged.yaml
template: node-20
resources:
  cpu: 2
  memory: 2048
budget: 10.00
secrets:
  - ANTHROPIC_API_KEY
init_script: npm install
network_mode: allowlist
allowed_hosts:
  - api.anthropic.com
  - registry.npmjs.org
```

```bash
caged up
caged exec cage-a1b2c3d4 "claude 'Create a React dashboard with a sidebar, header, and three chart widgets. Start the dev server when done.'"

# Get the preview URL
caged ports cage-a1b2c3d4
# → https://cage-a1b2c3d4-3000.preview.caged.dev
```

## Password-Protected Previews

Share previews with stakeholders while keeping them private:

```bash
# Add password protection
curl -X POST https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/ports/3000/protect \
  -H "Authorization: Bearer caged_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"password": "demo-review-2024"}'
```

Now visitors see a password prompt before accessing the preview. Share the URL + password with your team.

## Multiple Services

Run a full-stack app with multiple services — each gets its own preview URL:

```bash
# Start frontend and backend
caged exec cage-a1b2c3d4 "cd frontend && npm run dev &"
caged exec cage-a1b2c3d4 "cd backend && npm run start &"

# Check all ports
caged ports cage-a1b2c3d4
```

```
PORT   PROTOCOL   PREVIEW URL                                        PROTECTED
3000   http       https://cage-a1b2c3d4-3000.preview.caged.dev      no
8080   http       https://cage-a1b2c3d4-8080.preview.caged.dev      no
5432   tcp        —                                                   no
```

## E2E Testing with Preview URLs

Use the preview URL for automated E2E tests:

```bash
#!/bin/bash
# e2e-in-sandbox.sh

# Create sandbox and start the app
SANDBOX_ID=$(caged run --template node-20 --repo https://github.com/your-org/app \
  --budget 5 --json | jq -r '.id')

caged exec "$SANDBOX_ID" "npm install && npm run dev &"

# Wait for server to start
sleep 5

# Get the preview URL
PREVIEW_URL=$(caged ports "$SANDBOX_ID" --json | jq -r '.[0].preview_url')

# Run Playwright tests against the preview
npx playwright test --config=e2e.config.ts \
  --base-url="$PREVIEW_URL"

# Cleanup
caged destroy "$SANDBOX_ID" --force
```

## Live Collaboration: Agent + Human

1. Agent starts building in a sandbox
2. You open the preview URL and watch progress live
3. Give the agent feedback based on what you see

```bash
# Agent builds the UI
caged exec cage-a1b2c3d4 "claude 'Build a landing page for a developer tool. Start the dev server.'"

# You check the preview and want changes
caged exec cage-a1b2c3d4 "claude 'The hero section needs more contrast. Make the CTA button green and larger.'"

# Preview updates live — just refresh your browser
```

## Custom Domain Preview (API)

Map a custom domain to a sandbox port for client demos:

```bash
curl -X POST https://api.caged.dev/v1/sandboxes/cage-a1b2c3d4/ports/3000/domain \
  -H "Authorization: Bearer caged_sk_..." \
  -d '{"domain": "demo.your-startup.com"}'
```

<Note>
Custom domains require DNS configuration. Point a CNAME record to `preview.caged.dev`.
</Note>

## Tips

<Tip>
**Ports are auto-detected**: You don't need to declare ports. Caged scans for new listeners every 2 seconds.
</Tip>

<Tip>
**HTTPS everywhere**: All preview URLs use HTTPS automatically — no certificate configuration needed.
</Tip>

<Tip>
**Hot reload works**: If your dev server supports hot reload (Next.js, Vite, etc.), changes appear instantly in the preview URL.
</Tip>

<Tip>
**Share with non-technical stakeholders**: Preview URLs are just regular web URLs. Send them to designers, PMs, or clients — no CLI or account needed.
</Tip>
