Skip to content
Help Center
Browse documentation

Test apps on a private network with the TestOptim CLI

Run the TestOptim CLI on a machine inside your network so TestOptim can reach internal apps, staging hosts and single sign-on pages that are not on the public internet.

Updated 8 min read

To test an app that only your network can reach, run the TestOptim CLI on a machine inside that network with testoptim tunnel. TestOptim then runs its browsers through that machine, so internal URLs such as https://app.corp work the same as public ones.

Before you start

  • To turn on the private tunnel for a project, you need the Owner, Admin or QA Lead role. Other roles see the switch but can't change it.
  • To create the API token the CLI uses, you need the Owner or Admin role.
  • Your project needs a URL that the machine running the CLI can open in a browser.
  • The machine needs outbound HTTPS (port 443) access to api.testoptim.com and tunnel.testoptim.com. You don't need to open any inbound ports.

Install the CLI

On macOS or Linux, install the testoptim binary with Homebrew or the install script:

brew install testoptim-ai/tap/testoptim
# or
curl -fsSL https://raw.githubusercontent.com/TestOptim-AI/testoptim-cli/main/install.sh | sh

On Windows, run this in PowerShell:

irm https://raw.githubusercontent.com/TestOptim-AI/testoptim-cli/main/install.ps1 | iex

It installs testoptim.exe in %LOCALAPPDATA%\Programs\testoptim and adds that folder to your user PATH. You don't need administrator rights. Open a new terminal before you run testoptim from another window.

To run it in a container, use the ghcr.io/testoptim-ai/testoptim-cli image.

Turn on Private network for your project

For a new project, turn on Private network in the New project form, then select Create and connect CLI. The project's Knowledge page opens and shows Waiting for the CLI to connect, with the install, sign-in and tunnel commands for your project.

For an existing project:

  1. Open the project, then Settings in the project's sidebar.
  2. Turn on Private network, then select Save changes. The same connect steps appear under the switch.

While it is on, all of the project's test traffic goes through the tunnel. Start exploration on the Knowledge page stays disabled until the CLI connects. Test runs and issue re-verification fail straight away if the tunnel is offline.

Create a token for the tunnel

The quickest way is from the connect steps: under Sign in, select Create token. TestOptim creates a token named Private tunnel that can only connect a tunnel (tunnel:connect) for this project. Copy it straight away. It starts with topt_ and is shown only once. Owners and admins see the button; anyone else is asked to get the token from one of them.

To create the token from scratch instead, select your name at the top right, then Settings > API keys > New token. A new token starts with the permissions for running tests from CI ticked and Connect private tunnel unticked. Untick the others, tick Connect private tunnel, and under Project access choose the project you want to test. A token limited to one project can only open tunnels for that project.

Note

A token without Connect private tunnel can't open a tunnel. testoptim auth warns you if the token you paste doesn't have it.

Connect the CLI

  1. Save the token on the machine:

    testoptim auth
    

    Paste the token when prompted. The CLI checks it with TestOptim and saves it in ~/.config/testoptim/config.json with owner-only permissions. On Windows, the file is %USERPROFILE%\.config\testoptim\config.json.

  2. Start the tunnel for your project, using the project ID from the project's URL, or copy the command from the connect steps:

    testoptim tunnel --project <project-id>
    

    If the token is limited to one project, you can leave out --project.

    When the tunnel is up, the CLI prints which hosts it allows, then one line for each connection TestOptim makes through the tunnel:

    Tunnel online for app.corp — allowing app.corp:80,443. Press Ctrl-C to stop.
    ✔ app.corp:443
    ✘ blocked 10.1.2.3:22 (not in allowlist)
    
  3. Leave the command running while you test. Press Ctrl-C to close the tunnel.

Once the tunnel is online, the connect steps change to CLI connected, with the Computer (the machine's host name), Last check-in and Allowed hosts, and Start exploration unlocks. The page checks every few seconds, so you don't need to reload it. If the CLI stops checking in for 90 seconds, it shows The CLI disconnected and Start exploration is disabled again until the tunnel is back.

Warning

A project has one tunnel at a time. Starting testoptim tunnel for the same project on a second machine takes over from the first, and the two then keep taking the tunnel from each other. Run it on one machine per project.

Choose which hosts the tunnel can reach

By default the tunnel reaches only the host of your project URL, on ports 80 and 443, plus the port in the URL if it uses another one, such as :8443. Everything else is blocked. Add the other hosts your app needs:

  • --allow <host[:port]> adds a host name. Repeat it for each host. Wildcards such as *.corp are allowed. Without a port, it allows ports 80 and 443. It doesn't accept IP addresses.
  • --allow-cidr <cidr> allows an IP range on every port, such as 10.20.0.0/16. For a single address, add /32, as in 10.1.2.3/32. A bare address such as 10.1.2.3 is rejected.

Host names that resolve to private addresses, such as 10.x.x.x, 172.16.x.x or 192.168.x.x, work with --allow alone. You only need --allow-cidr when:

  • TestOptim reaches a host by IP address rather than by name. If your project URL is an IP address, the CLI won't start until you allow it, and tells you the --allow-cidr to add.
  • A host name resolves to a loopback or link-local address. For example, to test an app running on the CLI machine itself at http://localhost:3000, add --allow-cidr 127.0.0.1/32.
testoptim tunnel --project <project-id> \
  --allow sso.corp \
  --allow auth.example.com:443 \
  --allow-cidr 10.20.0.0/16

In PowerShell, end each continued line with a backtick (`) instead of \, or put the whole command on one line.

Note

Single sign-on pages run on your identity provider's host. Add that host with --allow, or sign-in will fail when TestOptim reaches it.

Security model

  • The CLI makes only outbound HTTPS connections: to api.testoptim.com, to start the tunnel and check in every 30 seconds, and to the relay at tunnel.testoptim.com. You don't open any inbound ports.
  • Only the hosts and ports you allow can be reached. Requests to other hosts are blocked and shown in the CLI output.
  • Your machine resolves internal host names with your own DNS, so names that only exist inside your network keep working.
  • Loopback addresses such as 127.0.0.1, link-local addresses and cloud metadata addresses such as 169.254.169.254 are blocked unless you allow them with --allow-cidr.
  • If your app uses HTTPS, TLS runs end to end between the TestOptim browser and your app, and TestOptim's relay sees only encrypted traffic. Plain HTTP is encrypted between your machine and the relay, but the relay can read it.
  • To cut off a machine, revoke its token: on the API keys page, select the red bin icon next to the token, then Revoke in the Revoke token dialog. A running tunnel stops within about 30 seconds with API token no longer valid, and the token can't open new tunnels.

Run the tunnel in Docker or CI

For a container or a CI job, skip testoptim auth and set the token as an environment variable. TESTOPTIM_API_KEY overrides any saved token.

docker run --rm -e TESTOPTIM_API_KEY="$TESTOPTIM_API_KEY" \
  ghcr.io/testoptim-ai/testoptim-cli tunnel --project <project-id> --allow sso.corp

Store the token in your CI secrets. Don't put it in the command line or in your repository.

Troubleshooting

"Private tunnel offline"

If a test run or issue re-verification fails with Private tunnel offline — run testoptim tunnel --project <project-id>, the project has Private network turned on, but no machine has checked in for it in the last 90 seconds. Either no CLI is running for the project, or it lost its connection. Start testoptim tunnel on a machine inside your network, wait until the project shows CLI connected, then start the run again. The failed run isn't retried.

A host shows as blocked

  • not in allowlist: add the host with --allow <host>, or with --allow-cidr <address>/32 if it is an IP address, and start the tunnel again.
  • resolves to a blocked address: the host name points to a loopback or link-local address. If that is what you want, for example for an app on the CLI machine, allow the address with --allow-cidr, such as 127.0.0.1/32.

The Windows installer can't connect

On older Windows Server versions, PowerShell can fail with The underlying connection was closed before the install starts. Turn on TLS 1.2 for the session, then run the installer again:

[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 3072
irm https://raw.githubusercontent.com/TestOptim-AI/testoptim-cli/main/install.ps1 | iex

If your organization blocks PowerShell scripts, download the windows_amd64 (or windows_arm64) .zip from the latest release, extract testoptim.exe and put it in a folder on your PATH.

The tunnel keeps reconnecting

If the CLI keeps printing Tunnel session was closed by the server (another client may have taken over); reconnecting, another machine is running a tunnel for the same project. Stop the tunnel on one of them.

If it prints Connection lost or Relay unreachable, check that the machine can open outbound HTTPS connections to api.testoptim.com and tunnel.testoptim.com. A proxy or firewall that drops long-lived connections can cause repeated reconnects.

The CLI exits with "API token no longer valid" or "API token rejected"

The token was revoked. Create a new one and run testoptim auth again.