---
sidebar_position: 2
title: Deploy your first app
---

# Deploy your first app

A complete walk-through — from `zibby app templates` to a running instance behind a stable URL — in under two minutes.

## Prerequisites

You'll need the CLI installed and authenticated:

```bash
npm install -g @zibby/cli
zibby login                # OAuth in browser, saves session to ~/.zibby/config.json
```

You also need a project. If you don't have one yet, deploy an agent first or create one in the [Zibby dashboard](https://studio.zibby.dev) — apps are scoped to projects so per-instance EFS volumes can be isolated per team.

## Browse the catalog

```bash
zibby app templates
```

```
ID              Display name            Tier        Rate          Description
grafana         Grafana                 Light       $0.05/hr      Dashboards for metrics, logs, traces.
uptime-kuma     Uptime Kuma             Light       $0.05/hr      Self-hosted Pingdom-alt.
drawio          draw.io                 Light       $0.05/hr      Client-side diagram editor.
gastown         Gas Town                Light       $0.05/hr      Multi-agent workspace.
open-webui      Open WebUI              Heavy       $0.25/hr      ChatGPT-style UI for Ollama / OpenAI.
openhands       OpenHands               Heavy       $0.25/hr      AI software-engineer agent (V1).
docmost         Docmost                 Heavy       $0.25/hr      Wiki + collaboration (multi-service).
… (20 entries total — see `zibby app templates` for the full list)
```

## Deploy from the catalog

```bash
zibby app deploy grafana --project <project-id> --name metrics
```

On success:

```
↑ Provisioning grafana on Fargate…
  ECS service + EFS volume + ALB target group
  agent-ops sidecar starting…
✔ Deployed (instanceId: a1b2c3d4)
→ Public URL: https://a1b2c3d4.apps.zibby.dev
```

`--project` is interactive-prompted if omitted (CLI walks you through your project list).
`--name` controls the **display name** — what shows in `zibby app list` and the dashboard. The subdomain is a separate opaque identifier (the instance ID), stable for the life of the instance.

The provisioning steps:

1. **Allocate an instance ID** — short hex token used as the subdomain
2. **Create EFS access point** — per-instance volume, encrypted at rest, AZ-pinned
3. **Register task definition** — pinned to the catalog entry's image(s) + your resource tier; one container per `services[]` entry for multi-service apps
4. **Spin up ECS service** — desired count 1, agent-ops sidecar bundled alongside the app container(s)
5. **Wire the ALB** — listener rule routes `<id>.apps.zibby.dev` to the new target group
6. **Health-check loop** — the first agent-ops tick fires once the container is up

Wall-clock: ~45-90 seconds for catalog deploys. The CLI streams progress and prints the public URL the moment the ALB is responsive.

## Verify

```bash
zibby app status a1b2c3d4
```

```
● metrics (grafana v10.4.2)
┌ status    running (1/1) ✓
├ resources 0.5 vCPU · 1 GB RAM ✓
└ hourly    $0.05/hr ✓

Public URL: https://a1b2c3d4.apps.zibby.dev

Last agent-ops run: 14:00:01  hourly_health_check  ok (1.2s)
```

Open the URL in a browser — Grafana's login screen renders, you sign in with the default `admin / admin` (and immediately rotate it — or better, follow the next section and put basic auth in front of the whole thing). The data sits on the EFS volume, encrypted and isolated; no other Zibby customer can reach it.

## Deploying with auth from day one

Most self-hosted dashboards (Grafana, Uptime Kuma, n8n on the free tier) either have weak default credentials or no app-level auth at all. The fix is the **auth proxy** — opt in at deploy time and a Caddy sidecar fronts the ALB:

```bash
zibby app deploy grafana \
  --project <project-id> \
  --name metrics \
  --auth-type basic \
  --auth-user admin \
  --auth-password 'S0me-long-passphrase!'
```

Verify it sticks:

```bash
curl -I https://a1b2c3d4.apps.zibby.dev
# HTTP/2 401  ← unauthenticated request is bounced by Caddy

curl -I -u 'admin:S0me-long-passphrase!' https://a1b2c3d4.apps.zibby.dev
# HTTP/2 302  ← Grafana sees the request and redirects to /login
```

Token-based auth is also supported (for webhook receivers, machine-to-machine access):

```bash
zibby app deploy gotify --project <id> --name notify --auth-type token
# Backend auto-generates a 32-char URL-safe token and prints it ONCE.
```

You can also pass `--auth-token <yours>` to use your own value. Full details + the password-rotation flow are in [Auth proxy](./auth).

## Deploying anything else (goal-mode)

If the app you want isn't in the catalog — or its license forbids us shipping a one-click bundle — use **goal-mode**. You describe the install in plain English, Claude writes a bash script, agent-ops runs and supervises it inside the container until the app is responding on a port.

```bash
zibby app deploy --goal "Install n8n on port 5678 with sqlite persistence" \
  --project <project-id> \
  --name automations \
  --max-turns 40 \
  --timeout-min 30
```

Output streams the planner's progress + the supervisor's verdicts every ~30s:

```
↑ Goal-mode deploy: "Install n8n on port 5678 with sqlite persistence"
  phase 1: planning install script (Claude write+read tools)…
  phase 2: executing /tmp/install.sh under supervision…
    [30s ] supervisor: continue — npm install in progress
    [60s ] supervisor: continue — npm install complete, starting n8n
    [90s ] auto-short-circuit: process exit 0, port 5678 returns 200
✔ Deployed (instanceId: f1e2d3c4)
→ Public URL: https://f1e2d3c4.apps.zibby.dev
```

License terms of whatever you install are yours, not Zibby's — same model as deploying on your own EC2. Full architecture + cost expectations: [Goal-mode deploys](./goal-mode).

## Choosing your model

Goal-mode deploys (and the cheatsheet-mode catalog entries that have a planner step) call Claude inside the container. You can pick which model:

```bash
zibby app deploy --goal "..." --model claude-sonnet-4-6
zibby app deploy --goal "..." --model claude-opus-4-8     # heavier installs
zibby app deploy --goal "..." --model claude-haiku-4-5-20251001  # cheaper, faster
```

Rule of thumb:

- **Sonnet** (default) — most installs fit. Good speed/cost balance.
- **Opus** — bump up for installs that hit lots of intervene loops (heavy native compilation, weird init systems, anything where the first plan tends to be wrong).
- **Haiku** — fine for installs you've already run once and know are reliable.

Token spend per deploy is typically $0.05 - $0.30 on Sonnet. Opus can go to ~$1.00 on a deploy that takes 5 intervene iterations.

## Watch logs while it warms up

If the app behaves oddly on first launch, tail logs:

```bash
zibby app logs a1b2c3d4 -t
```

Logs cover both the app container **and** the agent-ops sidecar. Container logs are color-coded by source:

```
14:00:00.122 [grafana]    Listening on port 3000
14:00:01.044 [agent-ops]  hourly_health_check: HTTP 200 in 1.2s
14:00:01.061 [agent-ops]  ✓ instance healthy — next tick in 60m
```

For multi-service apps (e.g. docmost), scope to one container with `--service`:

```bash
zibby app logs <id> -t --service db        # just the postgres container
zibby app logs <id> -t --service web       # just the docmost web container
```

`Ctrl+C` exits tail mode; logs persist in CloudWatch with 30-day retention.

## What's actually private vs shared

Mental model that lines up with what the bill shows:

| Resource | Per-instance? |
|---|---|
| Subdomain (`<id>.apps.zibby.dev`) | Yours |
| EFS volume | Yours, encrypted |
| ALB target group | Yours |
| ECS task definition | Yours (revisions tracked) |
| Fargate task | Yours |
| ALB itself | Shared — pooled across all tenants |
| ECS cluster | Shared |
| EFS file system | Shared, but per-instance access points enforce isolation |

The shared bits are why per-minute pricing can be $0.05/hr instead of $30/mo — economies of scale on the platform side.

→ Next: [Manage instances](./managing)
