Tensor9 manages DNS hostnames, load balancers, and TLS certificates across cloud and Kubernetes environments. When you define these resources in your origin stack, Tensor9 compiles them to the appropriate service equivalent for the target form factor. This includes private Kubernetes clusters where cloud-managed services aren’t available. You can also assign publicly-accessible custom DNS hostnames to deployed appliances by configuring a vanity domain for your app. This enables touch-free SSL certificate generation and branded endpoints for your customers. There are two ways to assign vanity domains to appliances:Documentation Index
Fetch the complete documentation index at: https://docs.tensor9.com/llms.txt
Use this file to discover all available pages before exploring further.
- Vendor-Supplied: Tensor9 automatically assigns subdomains of the app’s root vanity domain to customers (e.g.,
customer-a.ai-chat.playground.tensor9.app). - Customer-Supplied: Your customer brings their own domain (e.g.,
app.internal.customer.com) and delegates it to the appliance.
Enable Vanity Domains
To enable vanity domains, specify a root domain during app creation:Specify a vanity domain during app creation
Vanity Domain Assignment
Once the app is created with a vanity domain, your customers can choose to use either the vendor-supplied or customer-supplied vanity domain option during appliance setup.Vendor-Supplied Domains
In this model, Tensor9 automatically manages the assignment and delegation of a subdomain of your app’s root vanity domain to an appliance. When a customer installs your app, Tensor9 automatically:Assigns a unique subdomain
customer-a.ai-chat.playground.tensor9.app).Creates a hosted zone
Customer-Supplied Domains
In this model, your customer brings their own domain name.Customer provides domain
portal.corp.com).Zone creation
DNS Provider Support
Tensor9 uses the native DNS service of each target environment where possible. For environments without a built-in DNS service, Tensor9 supports external DNS providers.| Target Environment | DNS Provider | Notes |
|---|---|---|
| AWS | Route 53 | Native AWS DNS service |
| Google Cloud | Cloud DNS | Native GCP DNS service |
| Azure | Azure DNS | Native Azure DNS service |
| Private Kubernetes | Route 53 or Cloudflare | External DNS provider configured during appliance setup |
Origin Stack: DNS
To support both vanity domain workflows, your Terraform code should look up a hosted zone rather than create one.1. Receive the Domain Name
Use the@vanity_domain_root() annotation on a variable. Tensor9 injects the install’s assigned fully qualified domain name (FQDN) at deploy time.
2. Look Up the Hosted Zone
Reference the hosted zone using a Terraform data source instead of a resource. The zone already exists (created during appliance setup) by the time your stack is deployed.Load Balancer Endpoints
Tensor9 compiles load balancer resources from your origin stack to equivalent resources in the target environment using the service equivalents model. For example, you can define load balancers using AWS resources, and Tensor9 will map them to Kubernetes-native load balancing when compiling for private environments.How It Works
Vendors define load balancer resources in their origin stack using AWS convention. During compilation, Tensor9:Identifies load balancer resources
Maps to target equivalents
Preserves configuration
Equivalence Table
| Origin (AWS) | Private Kubernetes | Notes |
|---|---|---|
| Kubernetes Service with NLB annotations | Kubernetes Service with MetalLB annotations | L4 TCP/UDP load balancing |
| Kubernetes Ingress with ALB annotations | Traefik IngressRoute | L7 HTTP/HTTPS routing |
| Health check annotations | Kubernetes probes | Automatic mapping |
| ACM certificate (via annotation) | cert-manager Certificate | See TLS Certificates |
Origin Stack Example
Here is a typical Kubernetes service with AWS NLB annotations from an AWS origin stack:@kubernetes_service() Annotation
Use @kubernetes_service(type='LoadBalancer') on a data "kubernetes_service_v1" data source when your stack needs to reference a load balancer service’s external address. This annotation tells the compiler how to handle platform-specific behavior. For example, MetalLB assigns IP addresses (not hostnames), so the compiler creates a DNS A record and rewrites .hostname references accordingly.
TLS Certificates
Tensor9 compiles TLS certificate resources to the appropriate equivalent for each target environment. In AWS, certificates are managed by ACM. In private Kubernetes environments, Tensor9 uses cert-manager with Let’s Encrypt DNS-01 validation.Origin Stack: ACM Certificates
Define TLS certificates using AWS ACM resources. Since the vanity domain is properly delegated, you can use automatic DNS validation:Equivalence: cert-manager
When compiling for private Kubernetes, Tensor9 replaces ACM resources with cert-manager equivalents:| Origin (AWS) | Private Kubernetes | Notes |
|---|---|---|
aws_acm_certificate | cert-manager Certificate CRD | Domain name and SANs preserved |
aws_acm_certificate_validation | Removed | cert-manager handles validation automatically |
aws_route53_record (validation) | Removed | DNS-01 challenge handled by cert-manager solver |
ClusterIssuer is managed automatically by Tensor9’s service dependency system and vendors do not need to define it. The issuer uses Let’s Encrypt with DNS-01 validation via the appliance’s configured DNS provider.
Referencing External Certificates
When an ACM certificate is passed as a variable (rather than defined in-stack), the compiler cannot follow the reference to extract domain information. Instead, use adata "aws_acm_certificate" data source to look up the certificate by domain. This allows Tensor9 to extract the domain information and automatically convert it to a Kubernetes data source when compiling for private Kubernetes.
Annotations Reference
| Annotation | Applies To | Description |
|---|---|---|
@vanity_domain_root() | variable | Injects the install’s vanity domain FQDN at deploy time |
@vanity_domain_provided() | variable (bool) | Controls conditional hosted zone creation (see below) |
@kubernetes_service(type='LoadBalancer') | data "kubernetes_service_v1" | Marks a load balancer data source for platform-specific handling |
Additional Annotations
@vanity_domain_provided()
If you need to keep the hosted zone definition inside your origin stack (e.g., for self-contained single-file stacks), use@vanity_domain_provided() to handle this conditionally.
Annotate a boolean variable with @vanity_domain_provided(). Set it to true to allow the hosted zone to be created when you deploy the stack directly.
During compilation, Tensor9 sets the variable to false to skip hosted zone creation (since it was created during appliance setup) and allows the deployment stack to look up the zone instead.
Best Practices
Purchase a separate root domain
Purchase a separate root domain
saas.com, pick an alternative like
saas-customers.com or saas.app for your vanity domain root. This ensures that the cookie space for your
hosted offering is entirely separate from your customer’s appliances.Keep the root domain as brief as possible
Keep the root domain as brief as possible
Use data sources for hosted zones
Use data sources for hosted zones
data "aws_route53_zone") instead of creating them with resources. The zone is created during appliance setup before your stack is deployed. Using a data source ensures your stack works with both vendor-supplied and customer-supplied vanity domains.Let Tensor9 manage load balancer equivalence
Let Tensor9 manage load balancer equivalence
Questions You Might Ask
How do vendor-supplied and customer-supplied vanity domains differ?
How do vendor-supplied and customer-supplied vanity domains differ?
@vanity_domain_root() variable in your origin stack.
Your origin stack does not need to distinguish between the two.The difference is in who owns the domain and who performs the NS delegation:- Vendor-supplied: You register a domain (e.g.,
your-domain.app) and delegate it to Tensor9. Tensor9 auto-generates a subdomain for each customer (e.g.,abc123.your-domain.app) and handles NS delegation to the customer’s hosted zone automatically. - Customer-supplied: The customer provides their own domain during appliance setup and creates the NS delegation on their side. Tensor9 configures the customer’s hosted zone accordingly.
Where is the customer's hosted zone created?
Where is the customer's hosted zone created?
Who creates the TLS certificates for each customer?
Who creates the TLS certificates for each customer?
@vanity_domain_root() annotated domain variable.
Tensor9 compiles that resource into each customer’s deployment with the correct domain and the
appropriate certificate type for the target environment (e.g., AWS ACM certificates on AWS,
cert-manager Certificates on Kubernetes). This works the same for both vendor-supplied and
customer-supplied domains.Do not hardcode certificate identifiers - the compiler operates on Terraform resources, not raw strings.Do TLS certificates live in our account or the customer's account?
Do TLS certificates live in our account or the customer's account?
Do I need to create the root hosted zone myself?
Do I need to create the root hosted zone myself?
- Root domain (e.g.,
your-domain.app): Update the NS records at your domain registrar to point to the nameservers Tensor9 returns. - Subdomain (e.g.,
self-host.your-domain.app): Create an NS record in whatever DNS provider hosts the parent domain (e.g., youryour-domain.appzone) delegating the subdomain to the Tensor9 nameservers.
Can I change the vanity domain after app creation?
Can I change the vanity domain after app creation?
Should I use a separate domain for customer deployments?
Should I use a separate domain for customer deployments?
your-domain.com, use a
separate domain like your-domain.app for vanity domains. This keeps the cookie space for
your cloud offering entirely separate from customer appliances.Related Topics
- Service Equivalents: Full reference for how Tensor9 maps services across cloud providers
- Origin Stacks: How to define portable infrastructure code
- Deployments: How compilation and deployment works
- Appliances: Deploy to different cloud environments