- 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
Tensor9 assigns a unique subdomain to the install (e.g.,
customer-a.ai-chat.playground.tensor9.app).Creates a hosted zone
The appliance setup process creates a hosted zone for this subdomain within the customer’s environment.
Customer-Supplied Domains
In this model, your customer brings their own domain name.Customer provides domain
During appliance setup, the customer specifies their desired domain (e.g.,
portal.corp.com).Zone creation
The appliance setup process creates a hosted zone for this domain within the customer’s environment.
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 |
For private Kubernetes appliances, the DNS provider is configured at the appliance level. Credentials are stored securely, never leave the customer’s environment, and are used by Tensor9 to manage DNS records on their behalf.
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
Tensor9 detects the use of NLBs, ALBs, or Kubernetes Services with AWS Load Balancer Controller annotations and Ingress resources with load balancer annotations.
Maps to target equivalents
Each load balancer resource is mapped to its functional equivalent based on the target form factor.
Preserves configuration
Port mappings, health checks, routing rules, and TLS settings are preserved in the mapping.
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 |
You do not need to define Traefik or cert-manager resources in your origin stack. Tensor9 automatically declares these as service dependencies and manages their installation in the target environment.
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
If your app is hosted at
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
The maximum length of the Common Name in a certificate is 64 characters. Vanity
domains assigned to customers include the appliance ID as well as any
endpoints defined in your origin stack. The total length of the
subdomain for which a certificate is requested cannot exceed the limit.
Use data sources for hosted zones
Use data sources for hosted zones
Always reference hosted zones using data sources (
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
Do not manually define Traefik or cert-manager resources in your origin stack. Use standard AWS load balancer annotations and ACM certificates — Tensor9 compiles these to the correct equivalents for each target environment and manages the required infrastructure automatically.
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