Skip to content
Merged
Show file tree
Hide file tree
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
44 changes: 41 additions & 3 deletions .doc-review/state.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Documentation review state — tracks audit progress and terminology decisions.
# Managed by /doc-review skill. Committed to version control.
version: 1
last_run: 2026-03-26T12:00:00Z
last_run: 2026-04-10T14:00:00Z
docs_root: .
phase: 3
documents:
Expand Down Expand Up @@ -114,9 +114,14 @@ documents:
- "CVM not introduced on first use (acceptable for reference page)"
- "Replay protection buried in accordion"
phala-cloud/references/error-codes.mdx:
phase: 0
phase: 3
baseline: 2026-03-24T16:00:00Z
issues: 4
structure: 2026-04-10T12:00:00Z
copy: 2026-04-10T12:00:00Z
consistency: 2026-04-10T12:00:00Z
issues: 0
deferred:
- "HTTP status codes not shown as separate column — embedded in descriptions for non-standard codes only (400 is default for unlisted errors)"
phala-cloud/references/cloud-js-sdk/overview.mdx:
phase: 0
baseline: 2026-03-24T16:00:00Z
Expand Down Expand Up @@ -208,6 +213,39 @@ documents:
consistency: 2026-03-26T12:00:00Z
issues: 0
deferred: []
phala-cloud/references/cloud-js-sdk/add-compose-hash.mdx:
phase: 4
baseline: 2026-04-10T12:00:00Z
copy: 2026-04-10T12:00:00Z
issues: 0
deferred: []
phala-cloud/references/cloud-js-sdk/cvm-configuration.mdx:
phase: 4
baseline: 2026-04-10T12:00:00Z
copy: 2026-04-10T12:00:00Z
issues: 0
deferred: []
phala-cloud/key-management/deploying-with-onchain-kms.mdx:
phase: 2
baseline: 2026-04-10T12:00:00Z
structure: 2026-04-10T12:00:00Z
copy: 2026-04-10T12:00:00Z
issues: 0
deferred: []
phala-cloud/key-management/device-management.mdx:
phase: 2
baseline: 2026-04-10T12:00:00Z
structure: 2026-04-10T12:00:00Z
copy: 2026-04-10T12:00:00Z
issues: 0
deferred: []
phala-cloud/key-management/multisig-governance.mdx:
phase: 2
baseline: 2026-04-10T12:00:00Z
structure: 2026-04-10T12:00:00Z
copy: 2026-04-10T12:00:00Z
issues: 0
deferred: []
terminology:
preferred:
"Phala Cloud": []
Expand Down
24 changes: 19 additions & 5 deletions docs.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"$schema": "https://mintlify.com/docs.json",
"openapi": "openapi.json",
"colors": {
"dark": "#9FDC00",
"light": "#E8FF7A",
Expand Down Expand Up @@ -195,6 +194,7 @@
"/phala-cloud/cvm/set-secure-environment-variables",
"/phala-cloud/cvm/create-with-private-docker-image",
"/phala-cloud/cvm/multi-replica-scaling",
"/phala-cloud/cvm/replicating-cvms",
"/phala-cloud/cvm/deployment-cheat-sheet",
"/phala-cloud/cvm/image/overview",
"/phala-cloud/storage/access-database",
Expand Down Expand Up @@ -326,13 +326,22 @@
]
},
{
"group": "Key Management",
"group": "Onchain KMS",
"pages": [
"/phala-cloud/key-management/key-management-protocol",
"/phala-cloud/key-management/cloud-vs-onchain-kms",
"/phala-cloud/references/cloud-js-sdk/on-chain-kms-guide",
"/phala-cloud/key-management/get-a-key",
"/phala-cloud/key-management/create-crypto-wallet"
"/phala-cloud/key-management/understanding-onchain-kms",
"/phala-cloud/key-management/deploying-with-onchain-kms",
"/phala-cloud/key-management/updating-with-onchain-kms",
"/phala-cloud/key-management/device-management",
"/phala-cloud/key-management/multisig-governance",
{
"group": "Derived Keys",
"pages": [
"/phala-cloud/key-management/get-a-key",
"/phala-cloud/key-management/create-crypto-wallet"
]
}
]
},
{
Expand Down Expand Up @@ -781,7 +790,12 @@
}
]
},
"openapi": "openapi.json",
"redirects": [
{
"destination": "/phala-cloud/key-management/deploying-with-onchain-kms",
"source": "/phala-cloud/references/cloud-js-sdk/on-chain-kms-guide"
},
{
"destination": "/phala-cloud/phala-cloud-cli/login",
"source": "/phala-cloud/references/phala-cloud-cli/phala/auth"
Expand Down
Binary file added images/cloud/app-overview-onchain-kms.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cloud/app-overview-pending-update.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cloud/deploy-wizard-kms-provider-base.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cloud/device-allowlist.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cloud/webhook-created-signing-secret.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cloud/webhook-deliveries.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cloud/webhooks-list.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cloud/workspace-home-deploy-button.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion phala-cloud/cvm/create-with-docker-compose.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Create and manage Confidential Virtual Machines (CVMs) on Phala Cloud.
description: Deploy a CVM from a docker-compose.yml file using the Phala Cloud dashboard.
title: CVM with Docker Compose
---

Expand Down
2 changes: 1 addition & 1 deletion phala-cloud/cvm/create-with-private-docker-image.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ title: Private Container Registry

Phala Cloud supports private image pulls during CVM startup. Registry credentials are passed as encrypted environment variables and only used at runtime inside the trusted boot flow.

## Method 1: Configure in Cloud UI
## Method 1: Configure from the Dashboard

1. Open CVM creation and go to **Advanced Features**.
2. Open **Private Container Registry**.
Expand Down
2 changes: 1 addition & 1 deletion phala-cloud/cvm/deployment-cheat-sheet.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Create and manage Confidential Virtual Machines (CVMs) on Phala Cloud.
description: Common gotchas and quick fixes when deploying CVMs, including cross-architecture image builds and Docker log sizing.
title: Deployment Cheat Sheet
---

Expand Down
209 changes: 43 additions & 166 deletions phala-cloud/cvm/multi-replica-scaling.mdx
Original file line number Diff line number Diff line change
@@ -1,197 +1,74 @@
---
title: Scale with Multiple Replicas
description: Run multiple copies of your CVM for availability and load distribution using Terraform, SDKs, or the CLI.
description: Understand when replicas make sense, what you get from them, and where they fall short. For concrete replication steps, see Replicating CVMs.
---

Replicas let you run multiple copies of the same application across different TEE nodes. Each replica is an independent CVM that shares the same Docker Compose configuration and environment variables, but runs in its own isolated TEE enclave. This gives you both horizontal scaling and fault tolerance.
Replicas let you run several copies of the same application side by side on Phala Cloud. This page covers the concepts and the decision criteria. For concrete dashboard and CLI steps, see [Replicating CVMs](/phala-cloud/cvm/replicating-cvms).

## How Replicas Work
## What a Replica Is

When you create replicas of an app, Phala Cloud provisions separate CVMs that share a single `app_id`. All replicas use the same compose file and encrypted secrets. If you update the compose or environment, every replica picks up the change.
A replica is an independent CVM instance provisioned from an existing source CVM. Replicas of the same app share an `app_id` and the same compose hash, but each replica has its own:

Each replica gets its own CVM ID, endpoint URL, and TEE attestation. Traffic is not automatically load-balanced between replicas — add an external load balancer or DNS-based routing to distribute requests.
- `vm_uuid`, endpoint URL, and internal IP
- TEE attestation report
- Process state, memory, and local disk
- Billing meter

## Deploy with Terraform
Replicas are created one at a time from an existing source, not as an atomic group. If you ask for three replicas, Phala Cloud creates three independent CVMs whose only formal relationship is the shared `app_id`.

Terraform is the most straightforward way to manage replicas declaratively. Set the `replicas` attribute on a `phala_app` resource and Terraform handles creation, updates, and teardown.
## What Replicas Give You

```hcl
resource "phala_app" "api" {
name = "api-service"
size = "tdx.medium"
region = "US-WEST-1"
image = "dstack-dev-0.5.7-9b6a5239"
disk_size = 40
replicas = 3
**Horizontal capacity.** More replicas serve more concurrent traffic, assuming your workload is stateless or has a shared data layer behind it.

docker_compose = <<-YAML
services:
api:
image: myregistry/api:latest
ports:
- "8080:8080"
YAML
**Failure isolation.** If one replica's node goes down for maintenance, the others keep serving. A single CVM has no such fallback.

wait_for_ready = true
wait_timeout_seconds = 900
}
**Regional placement.** You can pin different replicas to nodes in different regions by passing a `node_id` when you replicate, which reduces latency for geographically distributed users.

output "cvm_ids" {
value = phala_app.api.cvm_ids
}
**Independent attestation.** Each replica produces its own TDX quote. A relying party can verify any individual replica without trusting the others, which matters when the attestation is part of your security story.

output "endpoint" {
value = phala_app.api.endpoint
}
```
## What Replicas Do Not Give You

To scale up or down, change the `replicas` value and run `terraform apply`. The provider adds or removes CVMs to match.
**Load balancing.** Phala Cloud does not distribute traffic across replicas. Each replica gets its own public endpoint. You need an external load balancer, DNS round-robin, or service mesh to split traffic.

```bash
# Scale from 3 to 5 replicas
terraform apply -var="replica_count=5" -auto-approve
```
**Shared state.** Replicas do not share filesystems, memory, or any in-process state. Two replicas writing to their local disks write to two separate disks. If your app keeps state locally, replicating it will cause divergence.

<Note>
Scaling down deletes the newest replicas. Make sure your application handles graceful shutdown, since in-flight requests on removed replicas will be interrupted.
</Note>
**Automatic propagation of compose updates.** Updating the compose of one replica does not update the others. Each replica is its own CVM and must be updated individually. See [Upgrade Application](/phala-cloud/update/upgrade-application) for the update flow.

## Deploy with SDKs
**Linear performance scaling.** Two replicas do not automatically serve twice the throughput. The upstream bottleneck (database, queue, external API) often dominates. Measure before assuming.

The SDKs expose a `replicateCvm` method that creates a copy of an existing CVM. Call it multiple times to create the number of replicas you need.

<CodeGroup>

```typescript JavaScript
import { createClient } from "@phala/cloud";

const client = createClient({ apiKey: process.env.PHALA_CLOUD_API_KEY });

// Create 2 replicas of an existing CVM
const sourceCvmId = "app_abc123";

const replica1 = await client.replicateCvm({
id: sourceCvmId,
name: "api-replica-1",
});

const replica2 = await client.replicateCvm({
id: sourceCvmId,
name: "api-replica-2",
});

console.log("Replica 1:", replica1);
console.log("Replica 2:", replica2);
```

```python Python
from phala_cloud import create_client

client = create_client()

source_cvm_id = "app_abc123"

replica1 = client.replicate_cvm({
"id": source_cvm_id,
"node_id": 5, # optionally pin to a specific node
})

replica2 = client.replicate_cvm({
"id": source_cvm_id,
"node_id": 7,
})

print("Replica 1:", replica1)
print("Replica 2:", replica2)
```

```go Go
package main

import (
"context"
"fmt"
"log"

phala "github.com/Phala-Network/phala-cloud/sdks/go"
)

func main() {
client, err := phala.NewClient()
if err != nil {
log.Fatal(err)
}

ctx := context.Background()
sourceCvmID := "app_abc123"

replica1, err := client.ReplicateCVM(ctx, sourceCvmID, nil)
if err != nil {
log.Fatal(err)
}

replica2, err := client.ReplicateCVM(ctx, sourceCvmID, nil)
if err != nil {
log.Fatal(err)
}

fmt.Printf("Replica 1: %+v\n", replica1)
fmt.Printf("Replica 2: %+v\n", replica2)
}
```

</CodeGroup>

## Deploy with CLI

The CLI doesn't have a dedicated replica command, but you can deploy the same compose file multiple times with different names. Each deployment creates an independent CVM.

```bash
export PHALA_CLOUD_API_KEY="phak_your_key"

phala deploy -n api-primary -t tdx.medium --wait
phala deploy -n api-replica-1 -t tdx.medium --wait
phala deploy -n api-replica-2 -t tdx.medium --wait
```

To replicate from an existing CVM programmatically, use the SDK or Terraform approach instead.

## Monitor Replica Health
## When to Use Replicas

Once your replicas are running, check their status from the dashboard or CLI.
Use replicas when:

**Dashboard:** Navigate to your app in the CVMs page. Each replica appears as a separate CVM entry with its own status indicator.
- The workload is **stateless**, or reads and writes go to a shared backing store (managed Postgres, object storage, an external queue).
- You need **high availability** and one CVM outage would be unacceptable.
- You want to **distribute traffic geographically** and you have a way to route users to the nearest replica.
- The attestation model assumes **independent instances** — each replica must be verifiable on its own.

**CLI:**
Avoid replicas when:

```bash
# List all CVMs and filter by name pattern
phala cvms list
```
- The workload keeps **state on local disk** and you have no replication layer. Two divergent copies of the same database do not make a cluster.
- The workload assumes it is the **only writer** to an external resource (a singleton job scheduler, a leader-elected worker).
- You are trying to solve a **vertical scaling** problem. If one replica is slow because it is CPU- or memory-bound, bigger instance types often help more than more copies. See [Resize Resources](/phala-cloud/update/resize-resource).

**SDK (polling):**
## Cost Model

```typescript
const client = createClient({ apiKey: process.env.PHALA_CLOUD_API_KEY });
Each replica is billed as an independent CVM at the full rate of its instance type. Three `tdx.medium` replicas cost three times one `tdx.medium`. There is no bulk discount for adding replicas. Factor this into your scaling budget before raising the replica count.

const cvms = await client.getCvmList();
for (const cvm of cvms.items) {
const state = await client.getCvmState({ id: cvm.id });
console.log(`${cvm.name}: ${state.status}`);
}
```
Stopping a replica pauses compute billing but keeps its disk allocation, which is billed separately. Deleting a replica releases both.

<Warning>
Each replica consumes its own resources and billing. Three replicas of a `tdx.medium` instance cost three times the single-instance price.
</Warning>
## How to Create Replicas

## When to Use Replicas
The concrete steps live in [Replicating CVMs](/phala-cloud/cvm/replicating-cvms), which covers:

Replicas are useful when you need high availability or want to distribute workloads across regions. They work best for stateless services like APIs, proxies, and workers. For stateful applications, consider whether your data layer supports multi-instance access before scaling out.
- The dashboard **Scale** dialog on the app detail page
- The `phala cvms replicate` CLI command
- Onchain KMS workflows for contract-governed apps
- The replicate API for custom integrations

## Related
## Related Documentation

- [Terraform `phala_app` Resource](/phala-cloud/references/terraform-provider/app-resource) — full attribute reference including `replicas`
- [CVM Lifecycle (JS SDK)](/phala-cloud/references/cloud-js-sdk/cvm-lifecycle) — `replicateCvm` method reference
- [CVM Lifecycle (Python SDK)](/phala-cloud/references/cloud-python-sdk/cvm-lifecycle) — `replicate_cvm` method reference
- [Deploy Your First CVM](/phala-cloud/getting-started/deploy-first-cvm) — getting started with a single CVM
- [Replicating CVMs](/phala-cloud/cvm/replicating-cvms) — concrete dashboard, CLI, and API steps.
- [Upgrade Application](/phala-cloud/update/upgrade-application) — how to update compose or environment, including across replicas.
- [Resize Resources](/phala-cloud/update/resize-resource) — vertical scaling when more replicas is not the answer.
- [Deploy Your First CVM](/phala-cloud/getting-started/deploy-first-cvm) — single-CVM getting started.
Loading
Loading