> ## Documentation Index
> Fetch the complete documentation index at: https://docs.streamly.watch/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy (Node)

> Run Streamly on any Node.js 20+ server or Docker/OCI — build, start, reverse proxy, and cron.

Use this path when you want a classic Node process behind Nginx, Caddy, or your host’s load balancer. For the production edge path used at `streamly.watch`, see [Deploy Cloudflare](/getting-started/deploy-cloudflare).

## When to use this

| Goal                        | Use                                                     |
| --------------------------- | ------------------------------------------------------- |
| VM / bare metal / Node PaaS | This guide (Option A)                                   |
| Docker / OCI                | Option B below                                          |
| Cloudflare Workers          | [Deploy Cloudflare](/getting-started/deploy-cloudflare) |

## Option A — Node.js server

```bash theme={null}
corepack enable
pnpm install --frozen-lockfile
pnpm run build
PORT=3000 pnpm run start
```

Set process env (systemd, host UI) — do not bake service-role keys into client bundles:

```bash theme={null}
NEXT_PUBLIC_APP_URL=https://your.domain
NEXT_PUBLIC_PLATFORM_HOST=your.domain
NEXT_PUBLIC_STREAMLY_API_BASE=https://your.domain/api/v1
NEXT_PUBLIC_SUPABASE_URL=...
NEXT_PUBLIC_SUPABASE_ANON_KEY=...
SUPABASE_SERVICE_ROLE_KEY=...
TENANT_SECRETS_MASTER_KEY=...
STREAMLY_CRON_SECRET=...
ENVATO_PERSONAL_TOKEN=...
RESEND_API_KEY=...
STREAMLY_FROM_EMAIL=Streamly <no-reply@your.domain>
```

Put a reverse proxy in front of port 3000 and preserve the original `Host` and forwarded-protocol headers (tenant resolution depends on `Host`).

## Option B — Docker / OCI

The included `Dockerfile` builds Next.js standalone output and runs as a non-root user.

```bash theme={null}
docker build \
  --build-arg NEXT_PUBLIC_APP_URL=https://streamly.example \
  --build-arg NEXT_PUBLIC_PLATFORM_HOST=streamly.example \
  --build-arg NEXT_PUBLIC_STREAMLY_API_BASE=https://streamly.example/api/v1 \
  --build-arg NEXT_PUBLIC_SUPABASE_URL=https://PROJECT.supabase.co \
  --build-arg NEXT_PUBLIC_SUPABASE_ANON_KEY=PUBLIC_ANON_KEY \
  -t streamly-platform .

docker run --rm -p 3000:3000 \
  --env-file /secure/path/streamly-runtime.env \
  streamly-platform
```

<Warning>
  Only pass `NEXT_PUBLIC_*` (and other intentional public build inputs) as `--build-arg`. Keep `SUPABASE_SERVICE_ROLE_KEY`, `TENANT_SECRETS_MASTER_KEY`, cron, email, and plugin secrets in the runtime `--env-file` — never as build args.
</Warning>

## Scheduled jobs (Node / Docker)

Cloudflare Cron is unavailable here. Point your scheduler at:

```text theme={null}
POST /api/internal/jobs/run
X-Streamly-Cron-Secret: <STREAMLY_CRON_SECRET>
Content-Type: application/json
```

Payloads: `maintenance`, `provider_health`, `domain_sync`, `metadata_sync`.

## After deploy

| Check          | Expect                        |
| -------------- | ----------------------------- |
| `/`            | Storefront loads              |
| `/admin/login` | Operator activation / sign-in |
| `/api/docs`    | OpenAPI available             |
| Custom domain  | Correct tenant branding       |

## Related

* [Deploy Cloudflare](/getting-started/deploy-cloudflare)
* [First Launch Checklist](/getting-started/first-launch-checklist)
* [Domain](/configuration/domain)
