Skip to content

Create a tunnel for a customer

Use separate namespaces for your tunnels

We recommend deploying customer tunnels into a one or more separate namespaces, that means you can keep the inlets namespace for the software coordinates the tunnels.

You could create a single namespace for customers i.e.

kubectl create namespace tunnels

Or you could create one per customer:

kubectl create namespace acmeco

Remember, that if you're an Istio user, you should label each namespace:

kubectl label namespace inlets \
  istio-injection=enabled --overwrite

Create a tunnel for a customer using the Custom Resource

Tunnel describes an inlets-uplink tunnel server. The specification describes a set of ports to use for TCP tunnels.

For example the following Tunnel configuration sets up a http tunnel on port 8000 by default and adds port 8080 for use with TCP tunnels. The licenceRef needs to reference a secret containing an inlets-uplink license.

kind: Tunnel
  name: acmeco
  namespace: tunnels
    name: inlets-uplink-license
    namespace: tunnels
  - 8080 

Alternatively the CLI can be used to create a tunnel:

inlets-pro tunnel create acmeco \
  -n tunnels
  --port 8080

Use a pre-existing token for a tunnel

By default a token is generated for tunnels, however if you are using a GitOps workflow, or store your tunnel YAML files in Git, you may want to pre-create the tokens for each tunnel.

Make sure the secret is in the same namespace as the Tunnel Custom Resource.

You can use openssl to generate a secure token:

openssl rand -base64 32 > token.txt

Create a Kubernetes secret for the token named custom-token:

kubectl create secret generic \
  -n tunnels acmeco-token \
  --from-file token=./token.txt

Reference the token when creating a tunnel:

kind: Tunnel
  name: acmeco
  namespace: tunnels
    name: inlets-uplink-license
    namespace: tunnels
    name: acmeco-token
    namespace: tunnels
  - 8080

Clients can now connect to the tunnel using the custom token.

Connect to tunnels

The uplink client command is part of the inlets-pro binary. It is used to connect to tunnels and expose services over the tunnel.

There are several ways to get the binary:

Example: Tunnel a customer HTTP service

We'll use inlets-pro's built in file server as an example of how to tunnel a HTTP service.

Run this command on a private network or on your workstation:

mkdir -p /tmp/share
cd /tmp/share
echo "Hello World" >

inlets-pro fileserver -w /tmp/share -a

Starting inlets Pro fileserver. Version: 0.9.10-rc1-1-g7bc49ae - 7bc49ae494bd9ec789fc5e9eaf500f2b1fe60786
Serving files from: /tmp/share
Listening on:, allow browsing: true, auth: false

Once the server is running connect to your tunnel using the inlets-uplink client. We will connect to the tunnel called acmeco (see the example in Create a tunnel for a customer using the Custom Resource to create this tunnel).

Retrieve the token for the tunnel:

kubectl get -n tunnels \
  secret/acmeco -o jsonpath="{.data.token}" | base64 --decode > token.txt 
inlets-pro tunnel token acmeco \
  -n tunnels > token.txt

The contents will be saved in token.txt.

Start the tunnel client:

inlets-pro uplink client \
  --url wss:// \
  --upstream \
  --token-file ./token.txt

Tip: get connection instructions

The tunnel plugin for the inlets-pro CLI can be used to get connection instructions for a tunnel.

inlets-pro tunnel connect acmeco \
  --domain \

Running the command above will print out the instructions to connect to the tunnel:

# Access your tunnel via ClusterIP: acmeco.tunnels
inlets-pro uplink client \
  --url=wss:// \
  --upstream= \

Run a container in the cluster to check the file server is accessible through the http tunnel using curl: curl -i acmeco.tunnels:8000

$ kubectl run -t -i curl --rm \
  --image /bin/sh   

$ curl -i acmeco.tunnels:8000
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Date: Thu, 17 Nov 2022 08:39:48 GMT
Last-Modified: Mon, 14 Nov 2022 20:52:53 GMT
Content-Length: 973

<a href=""></a>

Tunnel a customer's TCP service

Perhaps you need to access a customer's Postgres database from their private network?

Create a TCP tunnel using a Custom Resource

Example Custom Resource to deploy a tunnel for acmeco’s production Postgres database:

kind: Tunnel
  name: prod-database
  namespace: acmeco
    name: inlets-uplink-license
    namespace: acmeco
  - 5432

Alternatively the cli can be used to create a new tunnel:

inlets-pro tunnel create prod-database \
  -n acmeco
  --port 5432

Run postgresql on your private server

The quickest way to spin up a Postgres instance on your own machine would be to use Docker:

head -c 16 /dev/urandom |shasum 

export PASSWORD="8cb3efe58df984d3ab89bcf4566b31b49b2b79b9"

docker run --rm --name postgres \
  -p 5432:5432 \
  -e POSTGRES_PASSWORD=8cb3efe58df984d3ab89bcf4566b31b49b2b79b9 \
  -ti postgres:latest

inlets-pro uplink client \
  --url wss://${UPLINK_DOMAIN}/acmeco/prod-database \
  --upstream \
  --token-file ./token.txt

Access the customer database from within Kubernetes

Now that the tunnel is established, you can connect to the customer's Postgres database from within Kubernetes using its ClusterIP prod-database.acmeco.svc.cluster.local:

Try it out:

export PASSWORD="8cb3efe58df984d3ab89bcf4566b31b49b2b79b9"

kubectl run -i -t psql \
  --env PGPORT=5432 \
  --image postgres:latest -- psql -U postgres -h prod-database.acmeco

Try a command such as CREATE database websites (url TEXT), \dt or \l.

Getting help

Feel free to reach out to our team via email for technical support.