Skip to main content
This guide shows common workflows for using the tensor9 CLI to manage your apps, stacks, and appliances.

Prerequisites

Before starting, ensure you have:
  • Installed the tensor9 CLI
  • Set your API key: export T9_API_KEY=<your-key>
  • Configured AWS credentials for your Tensor9 AWS account

Initial setup workflow

Set up Tensor9 in your AWS account for the first time.
1

Set up your control plane

Run the interactive setup:
Or provide all parameters:
This creates your Tensor9 control plane in your AWS account. It takes several minutes to complete.
2

Verify setup

Check that your control plane is ready:
You should see your vendor information displayed.
3

Create your first app

Your app is now created and ready to have a stack bound to it.

Publish and bind your origin stack

Publish an origin stack and bind it to your app.

For Terraform stacks

1

Publish your Terraform stack

From your Terraform workspace directory:
This uploads your Terraform files and returns a native stack ID like:
2

Bind the stack to your app

Your stack is now bound to your app.

For Docker container stacks

1

Push your container image to ECR

First, authenticate to your Tensor9 AWS account’s ECR:
Tag and push your image:
The native stack ID is the image URI:
2

Bind the container to your app

Your container is now bound to your app.

For Docker Compose stacks

Before publishing your Docker Compose file, ensure all container images referenced in your compose file are pushed to their registries (ECR, Docker Hub, etc.). These images must be available when you create a release.
1

Publish your Docker Compose file

Returns a native stack ID like:
2

Bind the stack to your app

For CloudFormation stacks

1

Deploy your CloudFormation stack

Deploy your CloudFormation stack using the AWS CLI:
2

Get the stack ARN

This returns an ARN like:
3

Bind the CloudFormation stack


Create a test appliance

Create a test appliance for testing your releases before deploying to customers.
1

Create a test appliance

The test appliance will be created asynchronously.
2

Monitor appliance creation

Check the status periodically:
Wait until the test appliance status shows “Live”. This typically takes 10-15 minutes.

Deploy to a test appliance

Deploy your stack to a test appliance to verify it works before releasing to customers.
1

Create a release

Create a release for your test appliance:
After a few minutes, the deployment stack downloads to a directory named my-test-appliance, alongside a companion my-test-appliance.audit directory containing the audit stack for pre-deployment review.
2

Review the audit stack (optional)

Before deploying, you can scan the audit stack with your standard IaC security and policy tooling. The audit stack is a Tensor9-free copy of the deployment stack - same application infrastructure, without any Tensor9 providers or runtime plumbing - so scanners can plan and inspect it standalone:
The audit stack is for review only. Do not apply it. Only the deployment stack (in my-test-appliance) provisions a working install.
3

Deploy the release

Your application is now deployed in the test appliance.
4

Verify the deployment

Check the deployed resources:
For services with external ports, get the load balancer endpoint:
Access your application through the load balancer URL.

Create a customer appliance

Enable your customer to create an appliance for your app in their environment.
1

Generate signup link

Generate a signup link for your customer:
Send the generated URL to your customer. They’ll use it to create their appliance.
2

Customer creates appliance

The customer uses the signup link to:
  1. Sign up and create their organization (if they haven’t already)
  2. Select their cloud provider and region
  3. Complete the setup to create their appliance
Their appliance will be provisioned automatically in their cloud account.
3

Monitor appliance creation

Check when the customer’s appliance is ready:
Wait until their appliance status shows “Live”.
4

Create a release for the customer

Once their appliance is ready:
The deployment stack downloads to a directory named after their appliance.
5

Deploy to the customer's appliance

Deploy the release to the customer’s appliance:
This deploys your application into the customer’s appliance.

Release to a customer appliance

Release infrastructure or code changes to your customer appliances.
1

Update your origin stack

Make changes to your Terraform files, docker-compose.yml, or CloudFormation template.
2

Republish the stack

For Terraform:
For Docker Compose:
For CloudFormation:
You don’t need to re-bind the stack. Tensor9 will use the updated version for new releases.
3

Test in test appliance

Create a release to your test appliance:
4

Deploy and verify

Verify the changes work as expected.
5

Release to customers

After testing, release to your customers:

Manage multiple form factors

Deploy your app to different cloud providers or connectivity modes.
1

Create form factors

Create form factors for different environments:
2

Test each form factor

Create test appliances for each form factor:
3

Release to each test appliance


Onboard your vendor controller to Tailscale

By default, the listeners your CLI and Terraform use to reach the vendor controller are exposed on a public network load balancer with mTLS protection. If you operate a Tailscale tailnet for your engineering team, you can have the vendor controller join that tailnet and (optionally) remove the public path entirely. See Connectivity for the broader picture. This workflow rolls out in two phases: first attach the controller to your tailnet and verify operator access, then optionally enforce tunnel-only by removing the public listeners.

Phase 1: attach the vendor controller to your tailnet

1

Ensure your tailnet ACL has the required tags and rules

This step is idempotent. It adds the tag:tensor9-vctrl (vendor controller) and tag:tensor9-customer-ctrl (appliance controller) tags, the group:tensor9-operators group, and the rules that allow operators and customer appliances to reach the vendor controller. Existing ACL entries are preserved.
If you maintain ACLs in HuJSON via the dashboard, the command prints a copy-pasteable snippet you can apply by hand. Otherwise answer y at the confirmation prompt to have the CLI POST the change for you (a local backup is written under ~/.tensor9/tailscale-acl-backups/).See tensor9 tailscale acl setup for full options.
2

Generate a pre-auth key for the vendor controller

The key is tagged so the ACL applies the right rules to the resulting node. Keep it single-use (the default) for production:
Save the printed tskey-auth-... value; you will pass it to the next command. See tensor9 tailscale key generate for full options.Add operators to the group:operators group in the Tailscale dashboard so they can reach the controller’s listeners over the tailnet.
3

Attach the vendor controller to the tailnet

The command installs the Tailscale daemon on the vendor controller, joins it to the tailnet, and stamps the resulting tailnet hostname onto the controller’s configuration. The controller’s existing public listeners stay in place.See tensor9 vendor tailscale onboard for full options.
4

Verify operator access over the tailnet

With your operator account in group:operators and connected to the tailnet, run a read-only command:
Your CLI should be able to reach the vendor controller over the tailnet without any extra flags. The controller is still reachable over the public path too, so this step proves the tailnet route is working while leaving you a fallback.The endpoint used with Terraform/OpenTofu plan and apply operations is defined in the tensor9 provider block of the compiled deployment stack. Compilation emits the publicly available listener to this block when it is available, even if you have a tunnel configured, to be compatible with CI deployments. For testing, you can manually modify the compiled stack to change the endpoint address to be the vendor controller’s address on the tailnet and try a plan. Follow phase 2, below, to remove the TF endpoint from the public load balancer and re-compile your deployment stacks to enforce using the Tailscale for communication between your local Terraform/OpenTofu CLI and the vendor controller.

Phase 2: remove the public listeners

Once you are satisfied that operators and Terraform-driven deploys work over the tailnet, you can enforce tunnel-only and tear the public listeners down. Roll this out per listener group rather than all at once so you can pause if something is missed.
1

Mark the operator listeners as tunnel-only

The tunnel enforce command mutates the controller’s configuration; the listener teardown happens on the next infrastructure upgrade.
See tensor9 vendor tunnel enforce for full options. If you also want to remove the appliance-facing public listener, the command checks first that no customer appliance still depends on it; see the pre-flight notes in the reference.
2

Apply the change

Run an infrastructure upgrade to remove the now-redundant listeners from your network load balancer:
After this completes, the only way to reach the enforced listeners is over the tailnet.
Make sure every operator and every CI runner that drives tensor9 or terraform against the vendor controller is on the tailnet before you run tunnel enforce -add CLI / Terraform. After the next infrastructure upgrade, anything off the tailnet will be locked out.
To roll back, run tensor9 vendor tunnel enforce -remove CLI,Terraform followed by tensor9 vendor upgrade -kind Infrastructure. The public listeners are recreated.

Use stack tuning documents

Customize resource allocations per customer or environment.
1

Create a tuning document

Create a JSON file with resource overrides:
Save as enterprise-tuning.json.
2

Release with tuning document

The deployment stack will use the tuned resource specifications.

Monitor appliances

Check the status of your apps, appliances, and releases.

View comprehensive report

This shows:
  • All your apps and their stacks
  • All test appliances and their status
  • All customer appliances and their status
  • Active releases

View detailed report

List all appliances

Use the web portal

Start a local web interface:
This opens a browser with a visual dashboard of your apps and appliances.

Retire a test appliance

Remove a test appliance when no longer needed.
This permanently deletes the test appliance and all its infrastructure. It may take several minutes to fully deprovision.

Manage your vendor team

Tensor9 distinguishes two kinds of vendor accounts:
  • The root account is created automatically when you run vendor setup. It is the singleton account for your vendor and the only one that can invite, list, or revoke other accounts. If you lose your root cert, you can re-issue it from your control plane’s seed bundle in your AWS account (iam account recover).
  • Operator accounts are everyone else: teammates the root account invites by email. They get a long-lived mTLS cert pinned by your control plane after redeeming a one-time enrollment bundle. They can run ordinary vendor commands but cannot manage other accounts. If an operator loses their cert, the root account re-invites them.
See IAM Commands in the reference for the full surface and authorization details.

Invite a teammate

1

Mint an enrollment bundle

From your laptop (root account), invite by email:
This writes a single-use bundle to ./[email protected]. The bundle is valid for 48 hours by default. Use -ttl PT24H (or any ISO-8601 duration) to set a different window.
2

Send the bundle out-of-band

Send the file to your teammate via Slack, encrypted email, or a similar channel. The bundle contains a one-time secret, so treat it as sensitive until redeemed.
3

Have your teammate redeem it

On their machine, your teammate runs:
This trades the bundle for a long-lived mTLS cert pinned by your control plane, persists it locally, and writes a CLI profile so subsequent tensor9 commands authenticate automatically.

List your team

Shows the root account plus every invited operator with their enrollment status (Enrolled, Invited, or Revoked).

Revoke access

To remove an operator’s access, find their account ID and revoke:
Revocation is two-stage on the server: any in-flight enrollment bundles are killed, and the leaf-fingerprint pin is dropped so the user’s cached cert stops authenticating on its next handshake.
The root account cannot revoke itself. Use tensor9 iam account recover to rotate the root cert.

Recover the root account

If you lose your laptop or wipe ~/.tensor9/, recover by re-issuing the root cert from your control plane’s seed bundle:
The command reads your control plane’s seed bundle directly from your AWS Secrets Manager / Parameter Store. Access to that secret-store path is the actual gate, so make sure the IAM policy on it is scoped tightly. For non-root operator account recovery, ask your root account to re-invite you with iam user invite. Operator tokens are single-use, so there’s no equivalent self-service recovery path on the operator side.

Troubleshoot common issues

Problem: tofu apply fails when deploying a release.Solution:
  1. Check the Terraform error messages
  2. Verify your origin stack is valid: tofu validate in your workspace
  3. Check appliance status: tensor9 report
  4. Review deployment stack variables and configuration
  5. Check AWS credentials and permissions
Problem: Test appliance remains in “Creating” status for a long time.Solution:
  1. Wait 15-20 minutes (appliance creation can take time)
  2. Check tensor9 report -detailed for error messages
  3. Verify AWS quotas are sufficient for EKS, VPCs, etc.
  4. Check CloudFormation console in AWS for stack creation issues
  5. Contact support if stuck for more than 30 minutes
Problem: tensor9 stack publish fails with upload errors.Solution:
  1. Verify AWS credentials: aws sts get-caller-identity --profile <profile>
  2. Check that no .terraform directories are in your workspace
  3. Ensure you have write permissions to the control plane S3 bucket
  4. For large stacks, check your network connection
Problem: Customer reports they can’t reach their deployed application.Solution:
  1. Verify deployment completed: Check with customer that tofu apply succeeded
  2. Check load balancer: kubectl get service shows external IP/hostname
  3. Verify DNS configuration if using custom domains
  4. Check security groups/firewall rules in customer’s cloud
  5. Review application logs: kubectl logs <pod-name>
Problem: After creating a release, the deployment stack doesn’t download.Solution:
  1. Wait a few minutes (compilation takes time)
  2. Check release status: tensor9 report
  3. Verify appliance is in “Live” status
  4. Check for stack validation errors in the report
  5. Review control plane CloudWatch logs for compilation errors

Best practices

Use semantic versioning for your releases:
  • 1.0.0 - Initial release
  • 1.0.1 - Patch (bug fixes)
  • 1.1.0 - Minor (new features, backward compatible)
  • 2.0.0 - Major (breaking changes)
This helps customers understand the impact of updates.
Always create a release to a test appliance before releasing to customers:
  1. Create release to test appliance
  2. Deploy and verify functionality
  3. Test upgrade path from previous version
  4. Only then release to customers
Write clear, customer-facing release notes:
Your customers see these notes when deploying.
Keep your origin stacks in version control and use consistent naming:
  • Use Git to track changes to origin stacks
  • Tag releases in Git: git tag v1.0.0
  • Use the same version in Git and Tensor9 releases
  • Document infrastructure changes in commit messages
Regularly check appliance status:
Set up alerts for customer appliance issues.

Next steps