Skip to main content
Turnkey Verifiable Cloud is currently in Private Beta. Join the waitlist to request access. Once our team reaches out, share your organization ID to get enabled. If you already have a dedicated Slack channel with us, reach out there directly. Once enabled, you will see a new “Verifiable Cloud” section appear in the top-level navigation.

Prerequisites

This guide assumes you’ve been enabled for Turnkey Verifiable Cloud, and you’ve completed the steps to create an account and an organization as described in the account setup section.

Installation

Install the TVC CLI from crates.io (tvc crate):
cargo install tvc

Create your first verifiable app

1

Login

With your new organization ID ready, login through the CLI.
tvc login
You will be asked to paste in your organization ID, and prompted to add a new generated API key to your organization.
This step generates an operator P256 keypair locally for you. It is stored in ~/.config/turnkey/orgs/<name>/operator.json. The public key will be used in the following steps.
2

Create a new TVC app

Visit the TVC dashboard and click on “Create app”.
Create app button on the TVC dashboard
A modal should appear:
Create app modal
Name your app something identifiable; for this demo it can be "TVC Hello World". Paste in your operator public key from the TVC CLI login step, then click “Create new TVC App” to create your app.
Create a local app template by running
tvc app init --output <my-app-template>.json
This step is purely local, and generates an editable json template for your app to be used during creation. Your template will look something like this when first generated:
{
  "name": "<FILL_IN_APP_NAME>",
  "quorumPublicKey": KNOWN_QUORUM_KEY,
  "externalConnectivity": false,
  "manifestSetId": null,
  "manifestSetParams": {
    "name": "<FILL_IN_MANIFEST_SET_NAME>",
    "threshold": 1,
    "newOperators": [
      {
        "name": "operator-1",
        "publicKey": PUBLIC_KEY_AUTOPOPULATED_FROM_LOGIN
      }
    ],
    "existingOperatorIds": []
  }
}
Name your app something identifiable; for this demo it can be "TVC Hello World". Your manifest set is currently just the public key generated during login; give it an easy to remember name, such as "TVC Manifest".
The CLI has also automatically populated this template with a known quorum key, which is sufficient for running verifiable code but not advised for encrypting sensitive data.
Create your app in TVC by running
tvc app create --config-file my-app-template.json
This creates your app, and saves its quorum key and manifest settings to the Turnkey Verifiable Cloud platform. Check out your new app on the TVC dashboard.
3

Create new TVC deployment

Once your app is created, click into it on the dashboard. Click on “Create deployment” to start a new deployment for your app.Create deployment buttonThis should open a modal with all your deployment settings:
Deployment settings modal
If you do not have your own app, try our helloworld template:
  • Container Image URL: ghcr.io/tkhq/helloworld:latest@sha256:c9c18f78b05d29ebfc2c60ab7143df4b0a808765a34d6a88bbf99523f473cafd
    • TVC requires a single-platform linux/amd64 image digest, not a multi-platform index digest. If you are building your own image, use docker buildx imagetools inspect <image> to find the linux/amd64-specific digest.
    • If you are bringing private container images, TVC supports uploading pull secrets by encrypting them to a known public key. This will be used by TVC infrastructure to access your container images. Read more about pull secrets here.
  • Executable Path: /tvc_app
  • Executable Args: --host 0.0.0.0 --port 3000. These arguments are passed to the executable on startup. Here we are telling the helloworld binary to start on port 3000
  • Public ingress port: 3000. This is the port that will be exposed to the outside world
  • Health check port: 3000. Our tvc_app binary answers healthchecks on /health on the same port (3000)
  • Health check type: HTTP.
  • Executable digest: the hash of the binary file inside the container. For our helloworld example this should be cbe01169428f144086bfaef348bbf3db70f9217628996cafd2ecb85d5f2b47a1. You can compute it locally with:
    # Pull the container image, create a "tmp-extract" container, and extract our helloworld binary
    docker create --name tmp-extract ghcr.io/tkhq/helloworld@sha256:c9c18f78b05d29ebfc2c60ab7143df4b0a808765a34d6a88bbf99523f473cafd /bin/true \
          && docker cp tmp-extract:/tvc_app ./tvc_app \
          && docker rm tmp-extract
    
    # Locally compute the digest of the binary file
    sha256sum ./tvc_app
    cbe01169428f144086bfaef348bbf3db70f9217628996cafd2ecb85d5f2b47a1
    
    This digest will be to ensure TVC is running the code you expect.
When ready, click “Deploy TVC App”!
Start with this local-only step, which generates a deployment template:
tvc deploy init
The generated JSON file is named by its time of creation, but you can name it anything by specifying a name after the --output flag. Open it and fill in each field:
  • appId is populated with the last app you created. You may edit it to be the id of any app you’ve created in the past.
  • qosVersion: the QOS release version to use. Currently the only supported version is v2026.2.6.
  • pivotContainerImageUrl: link to a public image. For this demo, feel free to use
    "ghcr.io/tkhq/helloworld@sha256:c9c18f78b05d29ebfc2c60ab7143df4b0a808765a34d6a88bbf99523f473cafd"
    
  • pivotPath: location of your binary in the container. Use "/tvc_app" for the demo app.
  • pivotArgs: arguments passed to the binary on startup. For the helloworld demo, use ["--host", "0.0.0.0", "--port", "3000"]. Leave empty for your own app unless it requires arguments.
  • expectedPivotDigest: for the demo, use
    "cbe01169428f144086bfaef348bbf3db70f9217628996cafd2ecb85d5f2b47a1"
    
  • pivotContainerEncryptedPullSecret: your pull secret, if your container image isn’t public. Delete this field otherwise.
  • publicIngressPort: 3000
  • healthCheckPort: 3000
  • healthCheckType: TVC_HEALTH_CHECK_TYPE_HTTP For an arbitrary app, compute the expected digest with
    docker create --name tmp-extract <container URL> /bin/true \
      && docker cp tmp-extract:/path/to/binary ./binary \
      && docker rm tmp-extract
    
    sha256sum ./binary
    
Deploy to TVC by running
tvc deploy create --config-file deploy-YYYY-MM-DD.json [--pull-secret <path-to-pull-secret>.json]
On success you’ll see your deployment ID logged to console. Save the deployment ID for the approval step (you can also find it by clicking into your app on the dashboard):
Deployment created successfully!

Deployment ID: <DEPLOYMENT_UUID>
App ID: <APP_UUID>
Config: deploy-YYYY-MM-DD.json
Find the newly created deployment by clicking into your app on the TVC dashboard.
4

Approve deployment

By design, your deployment is not live yet. TVC requires approvals by the manifest set to fully deploy your application. Your app should be at the Approval Required stage on the dashboard:Approve stage on the dashboardFor this demo app, your manifest set is the public key you created at login. To approve your deployment, use the TVC CLI:
tvc deploy approve \
  --deploy-id <DEPLOYMENT_UUID_FROM_CREATING_DEPLOYMENT> \
  --operator-id <OPERATOR_UUID>
You may find your operator ID by clicking into your app, then under Manifest Operators:Manifest Operators in app pageThis command walks you through approving each section of the QOS manifest. On success you’ll see:
========================================
         MANIFEST APPROVAL
========================================

NAMESPACE
─────────────────────────────────────
  Name:       prod/tvc/<APP_UUID>
  Nonce:      <NONCE>
  Quorum Key: <QUORUM_KEY>

...

========================================
    ALL SECTIONS APPROVED
========================================

Posting approval to Turnkey...

Approval posted successfully!

Approval IDs: ["<APPROVAL_UUID>"]
Manifest ID: <MANIFEST_UUID>
Operator ID: <OPERATOR_UUID>
If you didn’t change anything during the demo, that should be the only required approval from your manifest set.In the dashboard you will see “Action Required” transition to “none”. This means everything is done on your side. You can look at the deployment details in the recap table on on the individual deployment page to know whether your deployment is coming up healthy and whether it’s receiving traffic.Deployment details when LIVEOur infrastructure automatically provisions network ingress for your application. You can visit https://app-<YOUR_APP_UUID>.turnkey.cloud to interact with it. If you used our helloworld template, try visiting /time in your browser!
5

Verify your deployment

Once the deployment is live, confirm it is healthy by hitting the /health endpoint. Before doing so, check the deployment details from the previous step and ensure Healthy Replicas reads 3/3. If replicas aren’t fully up yet, the endpoint may return a 404.
curl https://app-<YOUR_APP_UUID>.turnkey.cloud/health
A healthy deployment returns:
{"status":"ok"}

Next steps

Once the deployment is approved, your app can serve traffic and produce App Proofs, which are cryptographic signatures that prove TVC is running the correct, expected software on a legitimate AWS Nitro Enclave. Learn more about app proofs in our documentation. If you are not yet signed up for Turnkey Verifiable Cloud, join the waitlist here!