# SecretVM TEE quickstart

Source: https://nodedocs.mor.org/providers/full/secretvm-quickstart

This guide walks you through deploying a Morpheus TEE-hardened provider node on [SecretVM](https://secretai.scrtlabs.com) (SCRT Labs' confidential VM platform). By the end you'll have a provider running inside a hardware-secured Intel TDX enclave that consumers can cryptographically verify before sending prompts.

Most of the operator work after deploy is **graphical**: [MyProvider](https://myprovider.mor.org) against your SecretVM HTTPS URL, plus looking up models on [active.mor.org/status](https://active.mor.org/status). Swagger remains a fallback.

For deeper details (cosign verification, RTMR3 recomputation, attestation manifest inspection) see [TEE reference](/providers/full/tee-reference). For the trust-chain conceptual picture see [TEE overview](/concepts/tee-overview).

## What you'll need

- A **funded wallet** with MOR + ETH on Base Mainnet (or Base Sepolia for testnet).
- The wallet's **private key** — this stays encrypted inside the TEE.
- An **RPC endpoint** for Base Mainnet (e.g. `wss://base-mainnet.g.alchemy.com/v2/<your_key>`).
- Your **AI model backend** reachable via a private URL (e.g. `http://my-model:8080/v1/chat/completions`).
- A **SecretVM account** at https://secretai.scrtlabs.com — sign up to get an API key.
- *(Recommended)* `secretvm-cli`: `sudo npm install --global secretvm-cli`.
- *(Recommended)* [MyProvider](https://myprovider.mor.org) for registration and bidding after the VM is healthy.

## Step 0: Pick the model you will serve

Before minting anything on chain, see what already exists and at what price:

```bash
curl -sS https://active.mor.org/active_models.json \
  | jq '.models[] | select(.Name | test("your-model-name"; "i")) | {Name, Id, Tags, bidDetail}'

curl -sS https://active.mor.org/active_bids.json \
  | jq '[.bids[] | select(.ModelName | test("your-model-name"; "i"))] | sort_by(.PricePerSecond | tonumber) | .[:5]'
```

- If a matching model `Id` already exists **and** (for TEE) it carries a `tee` tag — plan to **bid on that `Id`** and put it in `MODELS_CONFIG_CONTENT` below.
- If you need TEE and no suitable `tee`-tagged model exists — you will register a new model with tag `tee` after deploy (Step 5).
- Or browse the human UI: [active.mor.org/status](https://active.mor.org/status).

Full decision table: [Register on chain → Step 0](/providers/full/register-onchain#step-0--look-up-models-before-you-mint).

## Step 1: Get the Docker Compose file

Each CI/CD build produces a deployed compose file pinning the TEE image by SHA-256 digest — that's what SecretVM uses to compute RTMR3.

Download `docker-compose.tee.deployed.yml` from the [latest GitHub Release](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases) — the digest is already filled in. You can also use the template at [`proxy-router/docker-compose.tee.yml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docker-compose.tee.yml) and replace the image tag yourself.

The compose includes a Traefik TLS sidecar that uses SecretVM's auto-generated certs to serve the API on HTTPS port 443. The full compose body is reproduced in [TEE reference → Step 1](/providers/full/tee-reference#step-1-prepare-the-docker-compose-file).

<Warning>
**Use the digest-pinned version.** Tags like `:latest` are mutable; the digest is not. Using the digest ensures RTMR3 will match the CI/CD-computed golden value.
</Warning>

## Step 2: Prepare your secrets

Create a `.env` file with your 5 provider-specific secrets:

```bash
WALLET_PRIVATE_KEY=<your_private_key>
ETH_NODE_ADDRESS=wss://base-mainnet.g.alchemy.com/v2/<your_alchemy_key>
MODELS_CONFIG_CONTENT={"models":[{"modelId":"0x<your_model_id>","modelName":"your-model-name","apiType":"openai","apiUrl":"http://your-model:8080/v1/chat/completions","concurrentSlots":6,"capacityPolicy":"simple"}]}
WEB_PUBLIC_URL=https://your-public-domain.com
COOKIE_CONTENT=admin:<your_secure_password>
```

`MODELS_CONFIG_CONTENT` must be single-line JSON. Schema: [models-config.json](/reference/models-config).

If Step 0 already gave you an existing on-chain `Id`, put that value in `modelId` now. If you will mint a new `tee` model after deploy, use a placeholder and replace it via MyProvider **Model Configuration Sync** (Step 5) before posting a bid you care about.

## Step 3: Deploy on SecretVM

<Tabs>
  <Tab title="Web portal">
    1. Go to https://secretai.scrtlabs.com/secret-vms/create
    2. **Docker Compose**: paste the contents of your compose file.
    3. **Encrypted Secrets**: enter your 5 variables.
    4. **Advanced features**:

    | Setting | Recommended | Notes |
    |---------|-------------|-------|
    | **Platform** | Intel TDX | Required to match CI/CD golden values |
    | **Additional Files** | Empty | Adding files changes RTMR3 |
    | **Enable Persistence** | On | Preserves data across reboots |
    | **Enable Upgrades** | On | Allows updates without reprovisioning |
    | **Hide Runtime Info** | Off | Keeps the `/docker-compose` endpoint accessible for verification |

    5. Click **Deploy**.
  </Tab>
  <Tab title="CLI (recommended)">
    ```bash
    secretvm-cli auth login

    secretvm-cli -k <your_api_key> vm create \
      --name morpheus-provider \
      --type small \
      --persistence \
      --upgradeability \
      --docker-compose proxy-router/docker-compose.tee.yml \
      --env path/to/your/.env \
      --platform tdx

    secretvm-cli -k <your_api_key> vm list
    ```

    Full CLI reference: [SecretVM CLI docs](https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines/secretvm-cli).
  </Tab>
</Tabs>

## Step 4: Verify the node is running

Once provisioned (typically 2-3 minutes):

```bash
curl https://<your-secretvm-url>/healthcheck
```

The API is served on HTTPS port 443 via Traefik. Expected:

```json
{ "status": "healthy", "version": "v7.0.0", "uptime": "1m30s" }
```

Verify the attestation endpoint (separate port, direct from SecretVM):

```bash
curl -k https://<your-secretvm-url>:29343/cpu | head -c 100
```

Returns a long hex string — your hardware-signed TDX attestation quote.

## Step 5: Register via MyProvider (recommended)

SecretVM already terminates TLS on port 443, so the hosted GUI at [myprovider.mor.org](https://myprovider.mor.org) can talk to your node without mixed-content issues.

<Steps>
  <Step title="Open MyProvider">
    Go to [myprovider.mor.org](https://myprovider.mor.org). Connect with:
    - **URL:** `https://<your-secretvm-url>/`
    - **Username / password:** from `COOKIE_CONTENT` (e.g. `admin:yourpassword`)
  </Step>
  <Step title="Register provider">
    **Provider** tab → verify the public `:3333` endpoint → create provider (min `0.2` MOR stake). Approve Diamond spend if prompted.
  </Step>
  <Step title="Bid — prefer an existing model">
    If Step 0 found a suitable model (including `tee` when you need TEE): **Models & Bids → Available Models → Add Bid** using that `Id`. Set price from the competitor check.
  </Step>
  <Step title="Only if needed — create a tee-tagged model">
    If no suitable `tee` model exists, use **Create Model & Bid** and include tag `tee` (comma-separated tags field). The `tee` tag is what triggers consumer-side attestation; without it, consumers treat you as a standard provider.
  </Step>
  <Step title="Sync models-config">
    Use **Model Configuration Sync** to generate updated `MODELS_CONFIG_CONTENT`, then update SecretVM encrypted secrets and redeploy/restart if the on-chain `modelId` changed from your Step 2 placeholder. Details: [MyProvider GUI](/providers/full/myprovider-gui).
  </Step>
</Steps>

Swagger fallback: `https://<your-secretvm-url>/swagger/index.html` — same contract calls as [Register on chain](/providers/full/register-onchain).

## Step 6: Verify your attestation

### Quick check (SecretVM portal)

1. Go to https://secretai.scrtlabs.com/attestation
2. Paste your compose file contents.
3. Enter your VM URL.
4. Click **Verify**.

Three layers must pass: hardware (genuine Intel TDX), VM (known SecretVM firmware/kernel), software/RTMR3 (your image + compose match what CI/CD built).

### Programmatic check (cosign)

```bash
cosign verify \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \
  ghcr.io/morpheusais/morpheus-lumerin-node-tee:<your-version>

cosign verify-attestation \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \
  --type https://morpheusais.github.io/tee-attestation/v1 \
  ghcr.io/morpheusais/morpheus-lumerin-node-tee:<your-version> \
  2>/dev/null | jq -r '.payload' | base64 -d | jq '.predicate'
```

## What consumers see, what your P-Node does

The two-hop trust chain — see [TEE overview](/concepts/tee-overview) for the full conceptual breakdown.

```
C-Node (v6.0.0+) ─Phase 1─▶ P-Node (-tee, v7.0.0+) ─Phase 2─▶ Backend LLM (SecretVM)
```

- **Phase 1** (consumer ↔ your P-Node): the consumer's proxy-router fetches your `:29343/cpu` quote, verifies via SecretAI portal, checks TLS binding, compares RTMR3 against the cosign-signed golden values, and re-checks with a ~50 ms fast path on every prompt.
- **Phase 2** (your P-Node ↔ backend): your P-Node fetches the backend's `:29343/cpu`, pins TLS, replays workload RTMR3 from `:29343/docker-compose`, verifies GPU evidence via NVIDIA NRAS, and re-checks per prompt. Per-model state is exposed at `GET /v1/models/attestation`.

Forward compatibility: a v6.0.0+ C-Node only needs to understand Phase 1; Phase 2 is your P-Node's job. Any v6+ consumer works with any v7+ provider, gaining Phase 2 transparently.

## Troubleshooting

| Symptom | Likely cause | Fix |
|---------|-------------|-----|
| Healthcheck returns nothing | VM still provisioning | Wait 2-3 min, check `secretvm-cli vm list` |
| Attestation quote empty | Port 29343 not exposed | SecretVM exposes it automatically — check VM status |
| RTMR3 mismatch | Wrong compose content or rootfs version | Use the exact deployed compose from CI/CD artifacts (byte-for-byte) |
| TLS binding fails | Using a proxy/CDN that terminates TLS | The consumer must connect directly — no TLS-terminating intermediaries on `:29343` |
| `tee` model not getting sessions | Consumers on older versions | Consumers need v6.0.0+ for Phase 1 |
| Phase 2 failing silently on consumer | Phase 2 runs in **your** P-Node | Check `GET /v1/models/attestation` on your node |

## Updating your node

```bash
secretvm-cli -k <your_api_key> vm edit <your_vm_uuid> \
  --docker-compose path/to/new/docker-compose.tee.yml
```

The VM reboots with the new image. Verify with `/healthcheck` and the attestation portal.

## Further reading

| Resource | Link |
|----------|------|
| MyProvider (operator GUI) | [MyProvider GUI](/providers/full/myprovider-gui) |
| Discover models / bid | [Register on chain](/providers/full/register-onchain) |
| Live marketplace | [active.mor.org/status](https://active.mor.org/status) |
| Full TEE reference | [tee-reference](/providers/full/tee-reference) |
| Conceptual TEE overview | [TEE overview](/concepts/tee-overview) |
| models-config.json | [reference](/reference/models-config) |
| Verify end-to-end | [Verify setup](/providers/full/verify-setup) |
| Standard Docker (non-TEE) | [proxy-router-docker](/providers/full/proxy-router-docker) |
| SecretVM documentation | https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines |
| SecretVM CLI | https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines/secretvm-cli |
| TEE images on GHCR | https://github.com/orgs/MorpheusAIs/packages?repo_name=Morpheus-Lumerin-Node |
