Teleport 16: Advancing Infrastructure Defense in Depth with Device Trust, MFA, and VNET
Jul 25
Register Today
Teleport logoTry For Free
Fork me on GitHub



VNet automatically proxies connections made to TCP applications available under the public address of a Proxy Service. This guide explains how to configure VNet to support apps with custom public addresses.

How it works

Let's assume that a user has logged in to a cluster through a Proxy Service available at There's a leaf cluster associated with that cluster. It has its own Proxy Service available at Once started, VNet captures DNS queries for both of those domains and their subdomains.

Type A and AAAA queries are matched against public_addr of applications registered in both clusters. If there's a match and the application is registered as a TCP application, VNet responds with a virtual IP address over which the connection will be proxied to the app. In any other case, the query is forwarded to the default DNS name server used by the OS.

If you want VNet to forward connections to an app that has a custom public_addr set, you need to first update the VNet config in the Auth Service to include a matching DNS zone and authorize the zone through a DNS TXT record.


  • A running Teleport cluster version 16.0.0 or above. If you want to get started with Teleport, sign up for a free trial or set up a demo environment.

  • The tctl admin tool and tsh client tool.

    Visit Installation for instructions on downloading tctl and tsh.

  • To check that you can connect to your Teleport cluster, sign in with tsh login, then verify that you can run tctl commands using your current credentials. tctl is supported on macOS and Linux machines. For example:
    tsh login --user=[email protected]
    tctl status


    Version 16.0.4

    CA pin sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678

    If you can connect to the cluster and run the tctl status command, you can use your current credentials to run subsequent tctl commands from your workstation. If you host your own Teleport cluster, you can also run tctl commands on the computer that hosts the Teleport Auth Service for full permissions.
  • A TCP application connected to the cluster.
  • A domain name under your control.

In this guide, we'll use the example app from TCP Application Access guide and make it available through VNet at with company.test as the custom DNS zone.

Step 1/4. Configure custom DNS zone

Create a file called vnet-config.yaml which specifies the custom DNS zone. In our case the public_addr of the app is going to be, so we're going to set company.test as suffix:

kind: vnet_config
version: v1
  name: vnet-config
  - suffix: suffix

Create the VNet config:

tctl create vnet-config.yaml
vnet_config has been created
Relationship between suffix and public_addr

suffix doesn't have to point to a domain that's exactly one level above the public_addr of an app. Any level of nesting works. E.g., you can have an app under and the suffix can be set to bar.qux.test.

Step 2/4. Set DNS TXT record

Establish the name of your cluster:

tctl status | awk '/Cluster/ {print $2}'

Set a DNS TXT record teleport-cluster=<cluster name> on the domain provided as suffix in the VNet config. This is required by VNet to prevent a rogue cluster admin from hijacking DNS resolution of arbitrary domains for unsuspecting users.

Wait a couple of minutes and verify that the DNS record changes have been propagated.

host -t TXT suffix
company.test descriptive text ""
DNS TXT and CNAME records

If the domain you chose for the suffix has the CNAME record set, you won't be able to add a TXT record. A CNAME record must be the only record for the given name. In that scenario, you can set the suffix to a domain one level above if possible (e.g., company.test instead of or switch from CNAME to A records.

Step 3/4. Set public_addr of the app

Set public_addr field of the application in the Application Service configuration file /etc/teleport.yaml and restart the teleport daemon.

version: v3
# …
  # …
  - name: "tcp-app"
    uri: tcp://localhost:5432
    public_addr: "public_addr"

Step 4/4. Connect

Once you start VNet, you should be able to connect to the application over the custom public_addr using the application client you would normally use to connect to it. You might need to restart VNet if it was already running while you were making changes to the cluster.

psql postgres://[email protected]/postgres

Next steps

Configuring IPv4 CIDR range

Each cluster has a configurable IPv4 CIDR range which VNet uses when assigning IP addresses to applications from that cluster. Root and leaf clusters can use different ranges. The default is and it can be changed by setting the ipv4_cidr_range field of the VNet config.

Create a file called vnet-config.yaml:

kind: vnet_config
version: v1
  name: vnet-config
  ipv4_cidr_range: ""

Create the VNet config:

tctl create vnet-config.yaml
vnet_config has been created

If the config already exists, you can use tctl edit instead:

$ tctl edit vnet_config
IPv4 address of the TUN device

When starting, VNet needs to assign an IPv4 address for its virtual network device. To pick an address, VNet arbitrarily chooses a root cluster that the user is logged in to and picks an address from the range used by that cluster. If your cluster uses a custom range, but your users are logged in to other clusters that are not under your control, this might cause VNet to pick an address for the TUN device from a range offered by one of those clusters.

Configuring leaf cluster apps

To make a leaf cluster app accessible over a custom public_addr, you need to follow the same steps while being logged in directly to the leaf cluster.

tsh login --user=[email protected]

The DNS TXT record of the domain provided as suffix needs to contain the name of the leaf cluster. A single domain can have multiple TXT records if you want to use it in multiple clusters.

Accessing web apps through VNet

VNet does not officially support web apps yet. However, technically any web app is a TCP app, so they can be made available over VNet as well. You'll need to change uri of your application in the Application Service configuration file to use tcp:// instead of http://. There's also a couple of caveats:

  • The Teleport Web UI uses HSTS. If the application is going to be served from a subdomain of a Proxy Service, it means that the application will not be accessible in browsers over plain HTTP, even with VNet running. It's possible to work around this by setting a custom public_addr as explained above in this guide.
  • If the application needs to be accessible over HTTPS, it must handle TLS connections and return a valid cert for the domain it is served on.
  • JWT Token, redirect and header rewrites are not available for TCP apps.
  • Teleport records the start and the end of a session for TCP apps in the audit log, but session chunks are not captured.

When accessing an HTTP API through VNet, the same caveats apply as above, with one main exception. Since API clients don't need to respect HSTS, the API itself does not need to be served over HTTPS.

The important thing to understand is that VNet doesn't do anything extra with a connection, other than passing it through a Teleport Proxy Service. Which application layer protocol is going to be used depends solely on the app itself and its clients.

Further reading

  • Read RFD 163 to learn how VNet works on a technical level.