Skip to main content
Tensor9 can automatically generate publicly-accessible custom DNS hostnames and hosted zones for deployed appliances. Vendors can enable this feature by defining a vanity domain during creation of a Tensor9 app that serves as the root domain for appliance subdomains. This delegation also enables the automatic generation of SSL certificates inside applianes automatically and touch-free.

Vendor-provided vanity domain

Tensor9 will automatically assign and delegate a vanity domain to your customer’s appliances once you perform the following steps:
1

Specify a vanity domain during app creation

During creation of your Tensor9 app, provide a vanity domain that will serve as the root for appliances:
tensor9 app create \
  -name ai-chat \
  -displayName "AI Chat (Playground)"  \
  -vanityDomain ai-chat.playground.tensor9.app
Specifying a vanity domain during app creation will cause the Tensor9 Vendor Controller to create a hosted zone for the specified domain in your Tensor9 account.Example output:
App `ai-chat` [id: xxxx] created successfully.
The vanity domain for your new app is: `ai-chat.playground.tensor9.app`.
To finish setting up your vanity domain, please add the following DNS records to your domain's DNS zone:
    NS ai-chat.playground.tensor9.app ns-1.awsdns-1.org
    NS ai-chat.playground.tensor9.app ns-2.awsdns-2.com
    NS ai-chat.playground.tensor9.app ns-3.awsdns-3.co.uk
    NS ai-chat.playground.tensor9.app ns-4.awsdns-4.net
2

One-time manual delegation

You must do a one-time manual delegation to this newly created hosted zone in order for Tensor9 to be able to delegate subdomains from it. In the example above, we can delegate the ai-chat.playground.tensor9.app root domain by adding a new NS record with the nameservers shown in the output in the DNS management for our tensor9.app domain.
3

Annotate your Terraform resources

Use Tensor9 annotations to configure DNS delegation for your appliances. See the Vanity Domain Annotations section below for detailed documentation.
# @vanity_domain_root()
variable "domain_root" {
  type    = string
  default = "ai-chat.playground.tensor9.app"
}

# @vanity_domain_zone(auto_delegate = true)
resource "aws_route53_zone" "dns_zone" {
  name = var.domain_root
}

resource "aws_route53_record" "ai_chat_app" {
  name    = "www.ai-chat.playground.tensor9.app"
  ttl     = 300
  type    = "CNAME"
  zone_id = aws_route53_zone.dns_zone.zone_id

  records = [aws_lb.lb.dns_name]
}
Following our example root vanity domain of ai-chat.playground.tensor9.app, assuming a main entrypoint to the app via a record called www, vanity domains assigned to customer appliances might look something like this:
www.<applianceID>.ai-chat.playground.tensor9.app
The behavior of vanity domains in your appliances is driven by specific annotations in your Terraform configuration. Use these annotations to tell the Tensor9 compiler where to inject the assigned vanity domain and how to handle DNS delegation.

Vanity Domain Annotations

Tensor9 enables you to provide every customer appliance a valid SSL certificate and a custom subdomain (e.g. abc123.ai-chat.playground.tensor9.app) automatically. This provides the following benefits:
  1. Zero-Touch Experience: Customers don’t need to manually configure DNS records.
  2. Automatic SSL: Since the domain is properly delegated, you can use DNS validation for free, automatic SSL certificates (e.g. via AWS ACM).
  3. Consistency: Every appliance gets a predictable, compliant hostname. Any records you add to your hosted zone in your origin stack will automatically be created in the customer’s appliance vanity domain.
To enable this, simply annotate your Terraform resources to identify your DNS-related resources to Tensor9.

@vanity_domain_root()

Tell Tensor9 which variable should receive the appliance’s unique domain name. Annotate a string variable with @vanity_domain_root(). During deployment, Tensor9 will automatically set this variable’s default value to the appliance’s assigned subdomain.
# @vanity_domain_root()
variable "domain_root" {
  type    = string
  # Default will be overwritten by the compiler with the actual
  # appliance domain (e.g. "abc123.ai-chat.playground.tensor9.app")
  default = "ai-chat.playground.tensor9.app"
}

@vanity_domain_zone()

Annotate aws_route53_zone resources with @vanity_domain_zone(auto_delegate = true/false). When auto_delegate is set to true, Tensor9 will automatically delegate the customer’s vanity domain to the customer’s appliance.
# @vanity_domain_zone(auto_delegate = true)
resource "aws_route53_zone" "app_zone" {
  name = var.domain_root
}
Note: You must pick one of two options for the cross-account delegation to take place: either annotate a zone with @vanity_domain_zone(auto_delegate = true) or create a delegation record to the zone and annotate it with @vanity_domain_delegation() .

@vanity_domain_delegation()

If you need granular control over how the delegation record is created (e.g. custom TTLs), you can set auto_delegate to false and manage the record yourself using @vanity_domain_delegation(). Tensor9 will overwrite the zone_id with your root vanity domain zone ID.
# @vanity_domain_delegation()
resource "aws_route53_record" "delegation" {
  # The zone_id will be automatically set to your root vanity domain zone ID
  zone_id = "Z1234567890ABC"
  name    = var.domain_root
  type    = "NS"
  ttl     = 300
  records = aws_route53_zone.app_zone.name_servers
}
Note: You must pick one of two options for the cross-account delegation to take place: either annotate a zone with @vanity_domain_zone(auto_delegate = true) or create a delegation record to the zone and annotate it with @vanity_domain_delegation() .

Complete Configuration Example

Here is an example configuration that gives every appliance a working, SSL-protected domain.
# 1. Receive the assigned unique domain
# @vanity_domain_root()
variable "domain_root" {
  type    = string
  default = "ai-chat.playground.tensor9.app"
}

# 2. Create the zone and delegate the domain to the customer's appliance
# @vanity_domain_zone(auto_delegate = true)
resource "aws_route53_zone" "main" {
  name = var.domain_root
}

resource "aws_lb" "lb" {
  name               = "example-lb"
  internal           = false
  load_balancer_type = "application"
}

# 3. Create additional records in the customer's zone
resource "aws_route53_record" "www" {
  zone_id = aws_route53_zone.main.zone_id
  name    = "www.${var.domain_root}"
  type    = "A"
  ttl     = 300
  records = [aws_lb.lb.dns_name]
}

# 4. Validate SSL certificates using the delegated domain
resource "aws_acm_certificate" "cert" {
  domain_name       = "www.${var.domain_root}"
  validation_method = "DNS"
}

Best Practices

Please note the following best practices when defining a root vanity domain for your customers:
If your app is present at saas.com pick an alternative like saas-customers.com or saas.app. This ensures that the cookie space for your hosted offering is entirely separate from your customer’s installs. Your customers will have control over the appliance vanity domain hosted zone since they are created inside their environment.
The maximum length of the Common Name in a certificate is 64 characters. Vanity domains assigned to customers will include the appliance ID as well as any endpoints you have defined in your origin stack. The total length of the subdomain for which a certificate is requested cannot exceed the limit.

SSL

Since Tensor9 automatically delegates a vanity subdomain into the customer’s account, it is possible to generate certificates automatically and touch-free. If your origin stack defines SSL certificates, like AWS ACM certificates, make sure that the domain of the certificate refers to a record inside of your stack’s hosted zone and enable DNS validation. If you also provide a root vanity domain during app creation (as described above) then Tensor9’s automatic delegation of an assigned vanity subdomain into the customer’s account will allow the resource to be created at stack deploy time.